diff --git a/frontend/svelte5-best-practices.mdc b/.claude/skills/svelte-frontend/SKILL.md
similarity index 98%
rename from frontend/svelte5-best-practices.mdc
rename to .claude/skills/svelte-frontend/SKILL.md
index 6951584bc5..41d65a12be 100644
--- a/frontend/svelte5-best-practices.mdc
+++ b/.claude/skills/svelte-frontend/SKILL.md
@@ -1,8 +1,8 @@
---
-description:
-globs: frontend/src/**/*.svelte
-alwaysApply: false
+name: svelte-frontend
+description: Svelte coding guidelines for the Windmill frontend. MUST use when writing or modifying code in the frontend directory.
---
+
# Svelte 5 Best Practices
This guide outlines best practices for developing with Svelte 5, incorporating the new Runes API and other modern Svelte features. These rules MUST NOT be applied on svelte 4 files unless explicitly asked to do so.
diff --git a/.github/workflows/check-org-membership.yml b/.github/workflows/check-org-membership.yml
index d8d648e659..eb338d3188 100644
--- a/.github/workflows/check-org-membership.yml
+++ b/.github/workflows/check-org-membership.yml
@@ -4,9 +4,10 @@ on:
workflow_call:
inputs:
commenter:
- required: true
+ required: false
type: string
- description: 'The username to check for organization membership'
+ default: ''
+ description: 'The username to check. Auto-detected from the event context if not provided.'
organization:
required: false
type: string
@@ -32,11 +33,27 @@ jobs:
outputs:
is_member: ${{ steps.check-membership.outputs.is_member }}
steps:
+ - name: Determine commenter
+ id: determine-commenter
+ run: |
+ COMMENTER="${{ inputs.commenter }}"
+ if [[ -z "$COMMENTER" ]]; then
+ if [[ "${{ github.event_name }}" == "issue_comment" || \
+ "${{ github.event_name }}" == "pull_request_review_comment" ]]; then
+ COMMENTER="${{ github.event.comment.user.login }}"
+ elif [[ "${{ github.event_name }}" == "pull_request_review" ]]; then
+ COMMENTER="${{ github.event.review.user.login }}"
+ else
+ COMMENTER="${{ github.event.issue.user.login }}"
+ fi
+ fi
+ echo "commenter=$COMMENTER" >> $GITHUB_OUTPUT
+
- name: Check organization membership
id: check-membership
env:
ORG_ACCESS_TOKEN: ${{ secrets.access_token }}
- COMMENTER: ${{ inputs.commenter }}
+ COMMENTER: ${{ steps.determine-commenter.outputs.commenter }}
ORG: ${{ inputs.organization }}
TRUSTED_BOT: ${{ inputs.trusted_bot }}
run: |
diff --git a/.github/workflows/claude-fast.yml b/.github/workflows/claude-fast.yml
index 9ca2f5d8ce..4ad53d326f 100644
--- a/.github/workflows/claude-fast.yml
+++ b/.github/workflows/claude-fast.yml
@@ -11,40 +11,18 @@ on:
types: [submitted]
jobs:
- determine-commenter:
+ check-membership:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/ai-fast')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/ai-fast')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '/ai-fast')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '/ai-fast'))
- runs-on: ubicloud-standard-2
- outputs:
- commenter: ${{ steps.determine-commenter.outputs.commenter }}
- steps:
- - name: Determine commenter
- id: determine-commenter
- run: |
- # Work out who wrote the comment / review
- if [[ "${{ github.event_name }}" == "issue_comment" || \
- "${{ github.event_name }}" == "pull_request_review_comment" ]]; then
- COMMENTER="${{ github.event.comment.user.login }}"
- elif [[ "${{ github.event_name }}" == "pull_request_review" ]]; then
- COMMENTER="${{ github.event.review.user.login }}"
- else
- COMMENTER="${{ github.event.issue.user.login }}"
- fi
- echo "commenter=$COMMENTER" >> $GITHUB_OUTPUT
-
- check-membership:
- needs: determine-commenter
uses: ./.github/workflows/check-org-membership.yml
- with:
- commenter: ${{ needs.determine-commenter.outputs.commenter }}
secrets:
access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
claude-code-action:
- needs: [determine-commenter, check-membership]
+ needs: check-membership
if: |
needs.check-membership.outputs.is_member == 'true'
runs-on: ubicloud-standard-8
diff --git a/.github/workflows/claude-plan.yml b/.github/workflows/claude-plan.yml
index c9abc3465b..c0457dabed 100644
--- a/.github/workflows/claude-plan.yml
+++ b/.github/workflows/claude-plan.yml
@@ -11,40 +11,18 @@ on:
types: [submitted]
jobs:
- determine-commenter:
+ check-membership:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/plan')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/plan')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '/plan')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '/plan'))
- runs-on: ubicloud-standard-2
- outputs:
- commenter: ${{ steps.determine-commenter.outputs.commenter }}
- steps:
- - name: Determine commenter
- id: determine-commenter
- run: |
- # Work out who wrote the comment / review
- if [[ "${{ github.event_name }}" == "issue_comment" || \
- "${{ github.event_name }}" == "pull_request_review_comment" ]]; then
- COMMENTER="${{ github.event.comment.user.login }}"
- elif [[ "${{ github.event_name }}" == "pull_request_review" ]]; then
- COMMENTER="${{ github.event.review.user.login }}"
- else
- COMMENTER="${{ github.event.issue.user.login }}"
- fi
- echo "commenter=$COMMENTER" >> $GITHUB_OUTPUT
-
- check-membership:
- needs: determine-commenter
uses: ./.github/workflows/check-org-membership.yml
- with:
- commenter: ${{ needs.determine-commenter.outputs.commenter }}
secrets:
access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
claude-plan-action:
- needs: [determine-commenter, check-membership]
+ needs: check-membership
if: |
needs.check-membership.outputs.is_member == 'true'
runs-on: ubicloud-standard-4
diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml
index ad1e234d98..88dacf80ef 100644
--- a/.github/workflows/claude.yml
+++ b/.github/workflows/claude.yml
@@ -11,40 +11,18 @@ on:
types: [submitted]
jobs:
- determine-commenter:
+ check-membership:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/ai')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/ai')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '/ai')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '/ai'))
- runs-on: ubicloud-standard-2
- outputs:
- commenter: ${{ steps.determine-commenter.outputs.commenter }}
- steps:
- - name: Determine commenter
- id: determine-commenter
- run: |
- # Work out who wrote the comment / review
- if [[ "${{ github.event_name }}" == "issue_comment" || \
- "${{ github.event_name }}" == "pull_request_review_comment" ]]; then
- COMMENTER="${{ github.event.comment.user.login }}"
- elif [[ "${{ github.event_name }}" == "pull_request_review" ]]; then
- COMMENTER="${{ github.event.review.user.login }}"
- else
- COMMENTER="${{ github.event.issue.user.login }}"
- fi
- echo "commenter=$COMMENTER" >> $GITHUB_OUTPUT
-
- check-membership:
- needs: determine-commenter
uses: ./.github/workflows/check-org-membership.yml
- with:
- commenter: ${{ needs.determine-commenter.outputs.commenter }}
secrets:
access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
claude-code-action:
- needs: [determine-commenter, check-membership]
+ needs: check-membership
if: |
needs.check-membership.outputs.is_member == 'true'
runs-on: ubicloud-standard-8
diff --git a/.github/workflows/create-docs.yml b/.github/workflows/create-docs.yml
deleted file mode 100644
index e6b313617c..0000000000
--- a/.github/workflows/create-docs.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-on:
- issue_comment:
- types: [created]
-
-jobs:
- check-membership:
- if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/docs') }}
- uses: ./.github/workflows/check-org-membership.yml
- with:
- commenter: ${{ github.event.comment.user.login }}
- secrets:
- access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
-
- generate-token:
- needs: check-membership
- if: ${{ needs.check-membership.outputs.is_member == 'true' }}
- runs-on: ubicloud-standard-2
- outputs:
- app_token: ${{ steps.app.outputs.token }}
- steps:
- - name: Generate an installation token
- id: app
- uses: actions/create-github-app-token@v2
- with:
- app-id: ${{ vars.INTERNAL_APP_ID }}
- private-key: ${{ secrets.INTERNAL_APP_KEY }}
- owner: windmill-labs
-
- trigger-docs:
- needs: [generate-token, check-membership]
- if: ${{ needs.check-membership.outputs.is_member == 'true' }}
- uses: windmill-labs/windmilldocs/.github/workflows/create-docs.yml@main
- with:
- pr_number: ${{ github.event.issue.number }}
- repo: ${{ github.event.repository.name }}
- comment_text: ${{ github.event.comment.body }}
- secrets:
- DOCS_TOKEN: ${{ needs.generate-token.outputs.app_token }}
- GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
diff --git a/.github/workflows/git-commands.yaml b/.github/workflows/git-commands.yaml
index 6e44067283..4e93cd8e9b 100644
--- a/.github/workflows/git-commands.yaml
+++ b/.github/workflows/git-commands.yaml
@@ -5,8 +5,21 @@ on:
types: [created]
jobs:
+ check-membership:
+ if: >-
+ github.event.issue.pull_request && (
+ startsWith(github.event.comment.body, '/updatesqlx') ||
+ startsWith(github.event.comment.body, '/demo') ||
+ startsWith(github.event.comment.body, '/eeref') ||
+ startsWith(github.event.comment.body, '/docs')
+ )
+ uses: ./.github/workflows/check-org-membership.yml
+ secrets:
+ access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
+
update-sqlx:
- if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/updatesqlx')
+ needs: check-membership
+ if: needs.check-membership.outputs.is_member == 'true' && startsWith(github.event.comment.body, '/updatesqlx')
runs-on: ubicloud-standard-8
permissions:
contents: write
@@ -121,7 +134,8 @@ jobs:
})
demo:
- if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/demo')
+ needs: check-membership
+ if: needs.check-membership.outputs.is_member == 'true' && startsWith(github.event.comment.body, '/demo')
runs-on: ubicloud-standard-2
permissions:
contents: read
@@ -200,7 +214,8 @@ jobs:
fi
update-ee-ref:
- if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/eeref')
+ needs: check-membership
+ if: needs.check-membership.outputs.is_member == 'true' && startsWith(github.event.comment.body, '/eeref')
runs-on: ubicloud-standard-2
permissions:
contents: write
@@ -283,3 +298,35 @@ jobs:
repo: context.repo.repo,
body: 'Successfully updated ee-repo-ref.txt'
})
+
+ update-docs:
+ needs: check-membership
+ if: needs.check-membership.outputs.is_member == 'true' && startsWith(github.event.comment.body, '/docs')
+ runs-on: ubicloud-standard-2
+ permissions:
+ contents: read
+ pull-requests: read
+ issues: read
+ steps:
+ - uses: actions/create-github-app-token@v2
+ id: app
+ with:
+ app-id: ${{ vars.INTERNAL_APP_ID }}
+ private-key: ${{ secrets.INTERNAL_APP_KEY }}
+ owner: ${{ github.repository_owner }}
+ repositories: |
+ windmilldocs
+
+ - name: Trigger docs update
+ env:
+ GH_TOKEN: ${{ steps.app.outputs.token }}
+ COMMENT_TEXT: ${{ github.event.comment.body }}
+ run: |
+ jq -n \
+ --argjson pr_number ${{ github.event.issue.number }} \
+ --arg repo "${{ github.event.repository.name }}" \
+ --arg comment "$COMMENT_TEXT" \
+ '{event_type: "create-docs", client_payload: {pr_number: $pr_number, repo: $repo, comment_text: $comment}}' | \
+ gh api repos/windmill-labs/windmilldocs/dispatches \
+ --method POST \
+ --input -
diff --git a/.github/workflows/spawn-ephemeral-backend.yml b/.github/workflows/spawn-ephemeral-backend.yml
index 9070f5af0d..725890031a 100644
--- a/.github/workflows/spawn-ephemeral-backend.yml
+++ b/.github/workflows/spawn-ephemeral-backend.yml
@@ -13,38 +13,16 @@ on:
type: number
jobs:
- determine-commenter:
+ check-membership:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/spawnbackend')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/spawnbackend'))
- runs-on: ubicloud-standard-2
- outputs:
- commenter: ${{ steps.determine-commenter.outputs.commenter }}
- steps:
- - name: Determine commenter
- id: determine-commenter
- run: |
- # Work out who wrote the comment / review
- if [[ "${{ github.event_name }}" == "issue_comment" || \
- "${{ github.event_name }}" == "pull_request_review_comment" ]]; then
- COMMENTER="${{ github.event.comment.user.login }}"
- elif [[ "${{ github.event_name }}" == "pull_request_review" ]]; then
- COMMENTER="${{ github.event.review.user.login }}"
- else
- COMMENTER="${{ github.event.issue.user.login }}"
- fi
- echo "commenter=$COMMENTER" >> $GITHUB_OUTPUT
-
- check-membership:
- needs: determine-commenter
uses: ./.github/workflows/check-org-membership.yml
- with:
- commenter: ${{ needs.determine-commenter.outputs.commenter }}
secrets:
access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
spawn-backend:
- needs: [determine-commenter, check-membership]
+ needs: check-membership
# Only run on PR comments that contain /spawn-backend, or manual dispatch
if: |
github.event_name == 'workflow_dispatch' ||
diff --git a/.mcp.json b/.mcp.json
index 8a587025cd..d71108f978 100644
--- a/.mcp.json
+++ b/.mcp.json
@@ -3,6 +3,10 @@
"svelte": {
"type": "http",
"url": "https://mcp.svelte.dev/mcp"
+ },
+ "playwright": {
+ "command": "npx",
+ "args": ["@playwright/mcp@latest"]
}
}
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa40577230..e8c4b0e5f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,149 @@
# Changelog
+## [1.635.1](https://github.com/windmill-labs/windmill/compare/v1.635.0...v1.635.1) (2026-02-15)
+
+
+### Bug Fixes
+
+* pin strum_macros to 0.27 to match strum version ([#7957](https://github.com/windmill-labs/windmill/issues/7957)) ([68f766e](https://github.com/windmill-labs/windmill/commit/68f766e1ae54dbe2fe42769559d81d4d76a409ef))
+
+## [1.635.0](https://github.com/windmill-labs/windmill/compare/v1.634.6...v1.635.0) (2026-02-15)
+
+
+### Features
+
+* add Kubernetes operator and instance settings YAML editor ([#7836](https://github.com/windmill-labs/windmill/issues/7836)) ([82e5f6d](https://github.com/windmill-labs/windmill/commit/82e5f6de48e246a49b25e7d4ea7be65122e8772c))
+* add maven settings.xml support for java private registries ([#7940](https://github.com/windmill-labs/windmill/issues/7940)) ([581dde8](https://github.com/windmill-labs/windmill/commit/581dde8d0bc4428a5e95fcb5341239231ab36ef6))
+* **cli:** add `lint` command ([#7917](https://github.com/windmill-labs/windmill/issues/7917)) ([37d1277](https://github.com/windmill-labs/windmill/commit/37d1277b91d1b8a03e327b0585f547037482498d))
+* handle $var: and $res: in arrays for transform_json_value ([#7949](https://github.com/windmill-labs/windmill/issues/7949)) ([e4a34d0](https://github.com/windmill-labs/windmill/commit/e4a34d031b2bdb1b73a2a7ca68544fa34f83ed0f))
+* IaC hints, YAML editor for worker configs ([#7956](https://github.com/windmill-labs/windmill/issues/7956)) ([8b8e33e](https://github.com/windmill-labs/windmill/commit/8b8e33e2dc1a2b4c0effab70463f6d4b402a0f7f))
+* open-source worker group configuration UI ([#7954](https://github.com/windmill-labs/windmill/issues/7954)) ([6cf3f5f](https://github.com/windmill-labs/windmill/commit/6cf3f5f4a35a6139b5cdf9f44af29c3941f19645))
+
+
+### Bug Fixes
+
+* allow renaming of backend runnables in the UI ([6215760](https://github.com/windmill-labs/windmill/commit/6215760b1294d55245909a1c1de6c4cc8cef320a))
+* **go:** preserve proxy envs for go mod tidy/download ([#7946](https://github.com/windmill-labs/windmill/issues/7946)) ([8410b59](https://github.com/windmill-labs/windmill/commit/8410b59a8f23d62c57e497d170449643b46595a0))
+* Missing app policy for datatable ([#7944](https://github.com/windmill-labs/windmill/issues/7944)) ([a9dbd1f](https://github.com/windmill-labs/windmill/commit/a9dbd1f73fca9100b64106281802c43881181e78))
+* strip slack_oauth_client_secret from get_settings for non-admins ([#7950](https://github.com/windmill-labs/windmill/issues/7950)) ([43218c6](https://github.com/windmill-labs/windmill/commit/43218c62852490d0efafa8f94385bfe0e8f2ad82))
+
+## [1.634.6](https://github.com/windmill-labs/windmill/compare/v1.634.5...v1.634.6) (2026-02-13)
+
+
+### Bug Fixes
+
+* full build fix with new rustup config ([caccdd5](https://github.com/windmill-labs/windmill/commit/caccdd553ad72ff26c2c7c45f0ff3a25bd19a49f))
+
+## [1.634.5](https://github.com/windmill-labs/windmill/compare/v1.634.4...v1.634.5) (2026-02-13)
+
+
+### Bug Fixes
+
+* rust + java works with just /tmp mounted ([e144432](https://github.com/windmill-labs/windmill/commit/e144432a168178a531aa146def0aff478f3d1586))
+
+## [1.634.4](https://github.com/windmill-labs/windmill/compare/v1.634.3...v1.634.4) (2026-02-13)
+
+
+### Bug Fixes
+
+* improve style panel reactivity and CSS defaults ([#7935](https://github.com/windmill-labs/windmill/issues/7935)) ([eacbee3](https://github.com/windmill-labs/windmill/commit/eacbee38cb51d11b051612ac66994e6444e81bf2))
+* java + rust only relies on /tmp, + https proxy improvement for java ([791cb3e](https://github.com/windmill-labs/windmill/commit/791cb3e225ebda4b2f6f7181bc8265c378150d4e))
+
+## [1.634.3](https://github.com/windmill-labs/windmill/compare/v1.634.2...v1.634.3) (2026-02-13)
+
+
+### Bug Fixes
+
+* fix incorrect oauth base url refresh error ([b3a1629](https://github.com/windmill-labs/windmill/commit/b3a1629e56217605d059d1dceca43c9999a58592))
+
+## [1.634.2](https://github.com/windmill-labs/windmill/compare/v1.634.1...v1.634.2) (2026-02-13)
+
+
+### Bug Fixes
+
+* fix hub schedule not set at on-boarding ([beeb19d](https://github.com/windmill-labs/windmill/commit/beeb19db04e8e9059c63007d2402981c3e81f1e2))
+
+## [1.634.1](https://github.com/windmill-labs/windmill/compare/v1.634.0...v1.634.1) (2026-02-13)
+
+
+### Bug Fixes
+
+* conditionally skip relock on dep job ([#7860](https://github.com/windmill-labs/windmill/issues/7860)) ([d6c72df](https://github.com/windmill-labs/windmill/commit/d6c72df99a0a500bdd925fcdcba8abd8bbe537f5))
+* improve on-boarding experience ([4e38a4f](https://github.com/windmill-labs/windmill/commit/4e38a4f1083d880b0814e336d5e27cb40187fc28))
+
+## [1.634.0](https://github.com/windmill-labs/windmill/compare/v1.633.1...v1.634.0) (2026-02-12)
+
+
+### Features
+
+* add force_sandboxing global setting and #sandbox bash annotation ([#7816](https://github.com/windmill-labs/windmill/issues/7816)) ([2646629](https://github.com/windmill-labs/windmill/commit/2646629194f260d0be3a809be421bbab1307f927))
+* support for datatables in App Db studio ([#7930](https://github.com/windmill-labs/windmill/issues/7930)) ([6cee34a](https://github.com/windmill-labs/windmill/commit/6cee34a81da389faebb1474957a3989c4aadb00f))
+
+## [1.633.1](https://github.com/windmill-labs/windmill/compare/v1.633.0...v1.633.1) (2026-02-12)
+
+
+### Bug Fixes
+
+* add private registries support for RUST + java home nit ([e2c28e4](https://github.com/windmill-labs/windmill/commit/e2c28e42dbda0f7bf119efc8d587da0d30636a44))
+
+## [1.633.0](https://github.com/windmill-labs/windmill/compare/v1.632.0...v1.633.0) (2026-02-12)
+
+
+### Features
+
+* /health endpoints ([#7727](https://github.com/windmill-labs/windmill/issues/7727)) ([7df4aa4](https://github.com/windmill-labs/windmill/commit/7df4aa4fec021fc728950fc10db4d0401a205087))
+
+
+### Bug Fixes
+
+* save deployment msg in CE ([#7923](https://github.com/windmill-labs/windmill/issues/7923)) ([e9be616](https://github.com/windmill-labs/windmill/commit/e9be616d3c079a0c6fd98733c66560f2cc1ee40d))
+
+## [1.632.0](https://github.com/windmill-labs/windmill/compare/v1.631.2...v1.632.0) (2026-02-12)
+
+
+### Features
+
+* **ai:** add AWS bedrock session token support ([#7908](https://github.com/windmill-labs/windmill/issues/7908)) ([d95e4db](https://github.com/windmill-labs/windmill/commit/d95e4db8f31e70a645a5f41e287557933b257db8))
+
+
+### Bug Fixes
+
+* add kafka kerberos runtime packages ([#7918](https://github.com/windmill-labs/windmill/issues/7918)) ([22f22c2](https://github.com/windmill-labs/windmill/commit/22f22c26612b904c2b82b415ec9337213ef593c3))
+* **frontend:** redesign instance settings ([#7916](https://github.com/windmill-labs/windmill/issues/7916)) ([dd419ad](https://github.com/windmill-labs/windmill/commit/dd419ade94a992073dfd1a979bfeb8a5fadfb051))
+* hash long dedicated worker tags ([#7914](https://github.com/windmill-labs/windmill/issues/7914)) ([aaa1b92](https://github.com/windmill-labs/windmill/commit/aaa1b92300bdc0794de5356ef6750bab5d8d81a0))
+
+## [1.631.2](https://github.com/windmill-labs/windmill/compare/v1.631.1...v1.631.2) (2026-02-11)
+
+
+### Bug Fixes
+
+* **frontend:** revert CloseButton refactor that broke tag removal in MultiSelect ([#7909](https://github.com/windmill-labs/windmill/issues/7909)) ([b11d6ed](https://github.com/windmill-labs/windmill/commit/b11d6ed7940faddfe74a22b25bcb132527cbcec8))
+* nix flake libz.so for deno_core ([#7905](https://github.com/windmill-labs/windmill/issues/7905)) ([900c76c](https://github.com/windmill-labs/windmill/commit/900c76ccad09f58fc6adcfa8151db780249617f6))
+* strip unsupported schema fields for Google AI ([#7894](https://github.com/windmill-labs/windmill/issues/7894)) ([5effb87](https://github.com/windmill-labs/windmill/commit/5effb87a36793e20d17e678619091ef458fe8f0a)), closes [#7759](https://github.com/windmill-labs/windmill/issues/7759)
+
+## [1.631.1](https://github.com/windmill-labs/windmill/compare/v1.631.0...v1.631.1) (2026-02-11)
+
+
+### Bug Fixes
+
+* add kafka-gssapi support to ee builds ([2815cfa](https://github.com/windmill-labs/windmill/commit/2815cfae1a5eefb2c553e893dc926e62ad1df528))
+
+## [1.631.0](https://github.com/windmill-labs/windmill/compare/v1.630.2...v1.631.0) (2026-02-11)
+
+
+### Features
+
+* **ai:** support 1M context window for Anthropic resources ([#7891](https://github.com/windmill-labs/windmill/issues/7891)) ([f22eb96](https://github.com/windmill-labs/windmill/commit/f22eb964e47defe9922ecdb6ab471dd4ca267952))
+* **uv:** index resolve strategy ([#7885](https://github.com/windmill-labs/windmill/issues/7885)) ([097d928](https://github.com/windmill-labs/windmill/commit/097d9288c58076882f1991e2fb33e4441fe332d3))
+
+
+### Bug Fixes
+
+* **frontend:** improve time picker ([#7893](https://github.com/windmill-labs/windmill/issues/7893)) ([31bfccc](https://github.com/windmill-labs/windmill/commit/31bfccc74588af10fc11fbbb0bc4833d65ff6421))
+* otel gracefully handle no native ts ([92c6018](https://github.com/windmill-labs/windmill/commit/92c601860f1e1211aa34838cd08900ba7334a20c))
+* waitJob getJob and streamJob in raw apps ([#7901](https://github.com/windmill-labs/windmill/issues/7901)) ([754b48c](https://github.com/windmill-labs/windmill/commit/754b48cb898dffe196339cea1c1598c9e1765cdc))
+* worker do not apply migrations anymore but wait for servers to do so ([7eb239f](https://github.com/windmill-labs/windmill/commit/7eb239f1e2eb1b71234a8d4265c7c5813e5861ae))
+
## [1.630.2](https://github.com/windmill-labs/windmill/compare/v1.630.1...v1.630.2) (2026-02-11)
diff --git a/CLAUDE.md b/CLAUDE.md
index 9f68fae3a1..7a5c365101 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -17,19 +17,52 @@ When implementing new features in Windmill, follow these best practices:
## Language-Specific Guides
-- Backend (Rust): @backend/rust-best-practices.mdc + @backend/summarized_schema.txt
-- Frontend (Svelte 5): @frontend/svelte5-best-practices.mdc
+- Backend (Rust): see `backend/CLAUDE.md` and the `rust-backend` skill: `.claude/skills/rust-backend/SKILL.md`
+- Frontend (Svelte 5): see `frontend/CLAUDE.md` and the `svelte-frontend` skill: `.claude/skills/svelte-frontend/SKILL.md`
+
+## Dev Environment
+
+- **Backend**: `cargo run` from `backend/` (API at http://localhost:8000)
+- **Frontend**: `REMOTE=http://localhost:8000 npm run dev` from `frontend/`
+ - The `REMOTE` env var configures the Vite proxy target. Without it, API calls proxy to `https://app.windmill.dev` instead of the local backend.
+ - The dev server starts on port 3000 (or 3001+ if 3000 is in use).
+- **Default login**: `admin@windmill.dev` / `changeme`
+- **Instance settings**: navigate to `/#superadmin-settings` (opens the drawer overlay)
+
+## UI Testing with Playwright MCP
+
+When testing the frontend with the Playwright MCP tools:
+
+1. **Start servers**: Launch backend (`cargo run`) and frontend (`REMOTE=http://localhost:8000 npm run dev`) as background tasks
+2. **Wait for readiness**: Backend takes ~60s to compile; check output for `health check completed`. Frontend starts in ~5s.
+3. **Login flow**: Navigate to `/user/login`, click "Log in without third-party", fill email/password, submit
+4. **Instance settings drawer**: Navigate to `/#superadmin-settings` to open the drawer directly
+5. **Toggle components**: The YAML toggle uses a custom `` component where the checkbox is visually hidden (`sr-only`). Click the wrapper `
- Try it - Docs - Discord - Hub - Contributor's guide
+ Try it - Website - Docs - Discord - Hub - Contributor's guide
# Windmill - Developer platform for APIs, background jobs, workflows and UIs
diff --git a/backend/.sqlx/query-023cdbc77ea9e2c17a1aa92a5b9001f29e58e81b3f782887db6e0a627dd8ad75.json b/backend/.sqlx/query-023cdbc77ea9e2c17a1aa92a5b9001f29e58e81b3f782887db6e0a627dd8ad75.json
index 5b58cedc72..d3f1c39c7a 100644
--- a/backend/.sqlx/query-023cdbc77ea9e2c17a1aa92a5b9001f29e58e81b3f782887db6e0a627dd8ad75.json
+++ b/backend/.sqlx/query-023cdbc77ea9e2c17a1aa92a5b9001f29e58e81b3f782887db6e0a627dd8ad75.json
@@ -12,7 +12,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-06072cfe26abe58629623a8b38382b33947c5a5c702ce586e6e6ea51430380bf.json b/backend/.sqlx/query-06072cfe26abe58629623a8b38382b33947c5a5c702ce586e6e6ea51430380bf.json
index 8ecc409fc8..97e39aa0e5 100644
--- a/backend/.sqlx/query-06072cfe26abe58629623a8b38382b33947c5a5c702ce586e6e6ea51430380bf.json
+++ b/backend/.sqlx/query-06072cfe26abe58629623a8b38382b33947c5a5c702ce586e6e6ea51430380bf.json
@@ -17,7 +17,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-11e24f758a70cd5f3a240bc81a05f40754826db0ee1194409227597a98603e92.json b/backend/.sqlx/query-11e24f758a70cd5f3a240bc81a05f40754826db0ee1194409227597a98603e92.json
deleted file mode 100644
index 4ed5cb835e..0000000000
--- a/backend/.sqlx/query-11e24f758a70cd5f3a240bc81a05f40754826db0ee1194409227597a98603e92.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n SELECT\n path,\n custom_path\n FROM \n app\n WHERE \n custom_path IN (\n SELECT \n custom_path\n FROM \n app\n GROUP \n BY custom_path\n HAVING COUNT(*) > 1\n )\n ORDER BY custom_path\n ",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "path",
- "type_info": "Varchar"
- },
- {
- "ordinal": 1,
- "name": "custom_path",
- "type_info": "Text"
- }
- ],
- "parameters": {
- "Left": []
- },
- "nullable": [
- false,
- true
- ]
- },
- "hash": "11e24f758a70cd5f3a240bc81a05f40754826db0ee1194409227597a98603e92"
-}
diff --git a/backend/.sqlx/query-1ea97f9085ec018f779e77e0fdbda3d4ecd67b3fbee9a58228ef577f846607ae.json b/backend/.sqlx/query-1ea97f9085ec018f779e77e0fdbda3d4ecd67b3fbee9a58228ef577f846607ae.json
new file mode 100644
index 0000000000..d453eb430d
--- /dev/null
+++ b/backend/.sqlx/query-1ea97f9085ec018f779e77e0fdbda3d4ecd67b3fbee9a58228ef577f846607ae.json
@@ -0,0 +1,24 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT EXISTS(SELECT 1 FROM resource_type WHERE workspace_id = 'admins' AND name = $1 AND schema IS NOT DISTINCT FROM $2 AND description IS NOT DISTINCT FROM $3)",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "exists",
+ "type_info": "Bool"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Text",
+ "Jsonb",
+ "Text"
+ ]
+ },
+ "nullable": [
+ null
+ ]
+ },
+ "hash": "1ea97f9085ec018f779e77e0fdbda3d4ecd67b3fbee9a58228ef577f846607ae"
+}
diff --git a/backend/.sqlx/query-256118bb9c87675d6a8db2d13c4f446d88c7bc671d5e90307febfd60bb235031.json b/backend/.sqlx/query-256118bb9c87675d6a8db2d13c4f446d88c7bc671d5e90307febfd60bb235031.json
index 4e48ae281c..c51175e921 100644
--- a/backend/.sqlx/query-256118bb9c87675d6a8db2d13c4f446d88c7bc671d5e90307febfd60bb235031.json
+++ b/backend/.sqlx/query-256118bb9c87675d6a8db2d13c4f446d88c7bc671d5e90307febfd60bb235031.json
@@ -16,7 +16,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-2602402bedcdbc45cdc0d64a76ce075c6ae51404037b0a7d4d33faf6a7d6a6d8.json b/backend/.sqlx/query-2602402bedcdbc45cdc0d64a76ce075c6ae51404037b0a7d4d33faf6a7d6a6d8.json
index 128a435c8b..5a4cd89224 100644
--- a/backend/.sqlx/query-2602402bedcdbc45cdc0d64a76ce075c6ae51404037b0a7d4d33faf6a7d6a6d8.json
+++ b/backend/.sqlx/query-2602402bedcdbc45cdc0d64a76ce075c6ae51404037b0a7d4d33faf6a7d6a6d8.json
@@ -11,7 +11,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-26141a1c3c48184285d94a2e2aca94ff708ce8e0b0b4fb59e5de7c9698c75c25.json b/backend/.sqlx/query-26141a1c3c48184285d94a2e2aca94ff708ce8e0b0b4fb59e5de7c9698c75c25.json
index 9abe8af9af..08c6c1cbc2 100644
--- a/backend/.sqlx/query-26141a1c3c48184285d94a2e2aca94ff708ce8e0b0b4fb59e5de7c9698c75c25.json
+++ b/backend/.sqlx/query-26141a1c3c48184285d94a2e2aca94ff708ce8e0b0b4fb59e5de7c9698c75c25.json
@@ -11,7 +11,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-26b35cf50959b1b1fd7e1cb33c65da40d29e20fd16b02355ba073f420c03a767.json b/backend/.sqlx/query-26b35cf50959b1b1fd7e1cb33c65da40d29e20fd16b02355ba073f420c03a767.json
new file mode 100644
index 0000000000..e5df344996
--- /dev/null
+++ b/backend/.sqlx/query-26b35cf50959b1b1fd7e1cb33c65da40d29e20fd16b02355ba073f420c03a767.json
@@ -0,0 +1,26 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT\n path,\n custom_path\n FROM\n app\n WHERE\n custom_path IN (\n SELECT\n custom_path\n FROM\n app\n GROUP\n BY custom_path\n HAVING COUNT(*) > 1\n )\n ORDER BY custom_path\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "path",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 1,
+ "name": "custom_path",
+ "type_info": "Text"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ false,
+ true
+ ]
+ },
+ "hash": "26b35cf50959b1b1fd7e1cb33c65da40d29e20fd16b02355ba073f420c03a767"
+}
diff --git a/backend/.sqlx/query-27ada97cb533c8595f1d73987c7823d8e54c96889e06895c57cafae9ca27bf8b.json b/backend/.sqlx/query-27ada97cb533c8595f1d73987c7823d8e54c96889e06895c57cafae9ca27bf8b.json
index 5d7c0e2abc..1199e9441f 100644
--- a/backend/.sqlx/query-27ada97cb533c8595f1d73987c7823d8e54c96889e06895c57cafae9ca27bf8b.json
+++ b/backend/.sqlx/query-27ada97cb533c8595f1d73987c7823d8e54c96889e06895c57cafae9ca27bf8b.json
@@ -15,7 +15,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-2fd22c4ffa2d222bb116260994a748e0639c2f73cbc1d8be66420c70b14c96e1.json b/backend/.sqlx/query-2fd22c4ffa2d222bb116260994a748e0639c2f73cbc1d8be66420c70b14c96e1.json
index 8f6c8edf25..afd0f503bf 100644
--- a/backend/.sqlx/query-2fd22c4ffa2d222bb116260994a748e0639c2f73cbc1d8be66420c70b14c96e1.json
+++ b/backend/.sqlx/query-2fd22c4ffa2d222bb116260994a748e0639c2f73cbc1d8be66420c70b14c96e1.json
@@ -12,7 +12,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-3b3f60623126626b52ca0a4a188655ddf728cd3f21ee308db7393694ccc5c7b3.json b/backend/.sqlx/query-3b3f60623126626b52ca0a4a188655ddf728cd3f21ee308db7393694ccc5c7b3.json
index 27b2503991..0df550b57c 100644
--- a/backend/.sqlx/query-3b3f60623126626b52ca0a4a188655ddf728cd3f21ee308db7393694ccc5c7b3.json
+++ b/backend/.sqlx/query-3b3f60623126626b52ca0a4a188655ddf728cd3f21ee308db7393694ccc5c7b3.json
@@ -12,7 +12,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-3cc7ecab48c379cd845b22012ef1fe1573fc332c9f1c44960084f3784ddb3f54.json b/backend/.sqlx/query-3cc7ecab48c379cd845b22012ef1fe1573fc332c9f1c44960084f3784ddb3f54.json
new file mode 100644
index 0000000000..6ba020e059
--- /dev/null
+++ b/backend/.sqlx/query-3cc7ecab48c379cd845b22012ef1fe1573fc332c9f1c44960084f3784ddb3f54.json
@@ -0,0 +1,22 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT logs FROM job_logs WHERE created_at > $1",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "logs",
+ "type_info": "Text"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Timestamptz"
+ ]
+ },
+ "nullable": [
+ true
+ ]
+ },
+ "hash": "3cc7ecab48c379cd845b22012ef1fe1573fc332c9f1c44960084f3784ddb3f54"
+}
diff --git a/backend/.sqlx/query-3e5bdc2e071fc2f1e3c7971736272f20bb5a0aa921a614bd02898d3f162660c2.json b/backend/.sqlx/query-3e5bdc2e071fc2f1e3c7971736272f20bb5a0aa921a614bd02898d3f162660c2.json
index e6dc6ff08b..fdcb10be1c 100644
--- a/backend/.sqlx/query-3e5bdc2e071fc2f1e3c7971736272f20bb5a0aa921a614bd02898d3f162660c2.json
+++ b/backend/.sqlx/query-3e5bdc2e071fc2f1e3c7971736272f20bb5a0aa921a614bd02898d3f162660c2.json
@@ -16,7 +16,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
@@ -51,7 +52,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-4b93550c7836fd3643180ade3548faa875e471d3f9ca37fc669f359e7a1818bb.json b/backend/.sqlx/query-4b93550c7836fd3643180ade3548faa875e471d3f9ca37fc669f359e7a1818bb.json
new file mode 100644
index 0000000000..63283a830a
--- /dev/null
+++ b/backend/.sqlx/query-4b93550c7836fd3643180ade3548faa875e471d3f9ca37fc669f359e7a1818bb.json
@@ -0,0 +1,16 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "INSERT INTO resource_type (workspace_id, name, schema, description, edited_at)\n VALUES ('admins', $1, $2, $3, now())\n ON CONFLICT (workspace_id, name) DO UPDATE\n SET schema = EXCLUDED.schema, description = EXCLUDED.description, edited_at = now()",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Varchar",
+ "Jsonb",
+ "Text"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "4b93550c7836fd3643180ade3548faa875e471d3f9ca37fc669f359e7a1818bb"
+}
diff --git a/backend/.sqlx/query-5368683c19f8d6744d5dbc53e5b2ab0f2348646d79f5306c6868e2c3a8f389ee.json b/backend/.sqlx/query-5368683c19f8d6744d5dbc53e5b2ab0f2348646d79f5306c6868e2c3a8f389ee.json
index 1058d78d8b..ebf1df39a3 100644
--- a/backend/.sqlx/query-5368683c19f8d6744d5dbc53e5b2ab0f2348646d79f5306c6868e2c3a8f389ee.json
+++ b/backend/.sqlx/query-5368683c19f8d6744d5dbc53e5b2ab0f2348646d79f5306c6868e2c3a8f389ee.json
@@ -16,7 +16,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-55a7460901c8ccdb478a2b7a3d4bd9d367838fe80844b5a14d2ef66452f36297.json b/backend/.sqlx/query-55a7460901c8ccdb478a2b7a3d4bd9d367838fe80844b5a14d2ef66452f36297.json
new file mode 100644
index 0000000000..a1f3a7d6ba
--- /dev/null
+++ b/backend/.sqlx/query-55a7460901c8ccdb478a2b7a3d4bd9d367838fe80844b5a14d2ef66452f36297.json
@@ -0,0 +1,19 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "INSERT INTO dependency_map (workspace_id, importer_path, importer_kind, imported_path, importer_node_id, imported_lockfile_hash)\n VALUES ($1, $2, $3::text::IMPORTER_KIND, $4, $5, $6)\n ON CONFLICT (workspace_id, importer_node_id, importer_kind, importer_path, imported_path)\n DO UPDATE SET imported_lockfile_hash = EXCLUDED.imported_lockfile_hash",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Varchar",
+ "Varchar",
+ "Text",
+ "Varchar",
+ "Varchar",
+ "Int8"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "55a7460901c8ccdb478a2b7a3d4bd9d367838fe80844b5a14d2ef66452f36297"
+}
diff --git a/backend/.sqlx/query-5f6d0d1b24693db22230ec8322b3174ecc195242a1205131f5d0d32148c0280a.json b/backend/.sqlx/query-5f6d0d1b24693db22230ec8322b3174ecc195242a1205131f5d0d32148c0280a.json
new file mode 100644
index 0000000000..9ffceac7b9
--- /dev/null
+++ b/backend/.sqlx/query-5f6d0d1b24693db22230ec8322b3174ecc195242a1205131f5d0d32148c0280a.json
@@ -0,0 +1,20 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT hash FROM script WHERE path = 'f/rel/leaf_2' AND workspace_id = 'test-workspace' AND archived = false ORDER BY created_at DESC LIMIT 1",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "hash",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ false
+ ]
+ },
+ "hash": "5f6d0d1b24693db22230ec8322b3174ecc195242a1205131f5d0d32148c0280a"
+}
diff --git a/backend/.sqlx/query-6c10c38a5d5e560d8d76159ce0ae118cf7191b06d72285e71256dd6d70c19451.json b/backend/.sqlx/query-8acc8c47123af84d2308042dcd34d04b941e928c7621e66d3bdc510c335f8c20.json
similarity index 62%
rename from backend/.sqlx/query-6c10c38a5d5e560d8d76159ce0ae118cf7191b06d72285e71256dd6d70c19451.json
rename to backend/.sqlx/query-8acc8c47123af84d2308042dcd34d04b941e928c7621e66d3bdc510c335f8c20.json
index 1e49b8405c..a450218ccd 100644
--- a/backend/.sqlx/query-6c10c38a5d5e560d8d76159ce0ae118cf7191b06d72285e71256dd6d70c19451.json
+++ b/backend/.sqlx/query-8acc8c47123af84d2308042dcd34d04b941e928c7621e66d3bdc510c335f8c20.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n INSERT INTO workspace_dependencies(name, workspace_id, content, language, description)\n VALUES ($1, $2, $3, $4, $5)\n RETURNING id\n ",
+ "query": "\n WITH ins AS (\n INSERT INTO workspace_dependencies(name, workspace_id, content, language, description)\n VALUES ($1, $2, $3, $4, $5)\n RETURNING id\n ), lock_ins AS (\n INSERT INTO lock_hash (workspace_id, path, lockfile_hash)\n VALUES ($2, $6, $7)\n ON CONFLICT (workspace_id, path) DO UPDATE SET lockfile_hash = $7\n )\n SELECT id FROM ins\n ",
"describe": {
"columns": [
{
@@ -46,12 +46,14 @@
}
}
},
- "Text"
+ "Text",
+ "Varchar",
+ "Int8"
]
},
"nullable": [
false
]
},
- "hash": "6c10c38a5d5e560d8d76159ce0ae118cf7191b06d72285e71256dd6d70c19451"
+ "hash": "8acc8c47123af84d2308042dcd34d04b941e928c7621e66d3bdc510c335f8c20"
}
diff --git a/backend/.sqlx/query-9052b7cd438ff029a37bd489190d98d365acec09f2f102b7de71dcc9d356900e.json b/backend/.sqlx/query-9052b7cd438ff029a37bd489190d98d365acec09f2f102b7de71dcc9d356900e.json
index 02cad7d11d..62f8d3100f 100644
--- a/backend/.sqlx/query-9052b7cd438ff029a37bd489190d98d365acec09f2f102b7de71dcc9d356900e.json
+++ b/backend/.sqlx/query-9052b7cd438ff029a37bd489190d98d365acec09f2f102b7de71dcc9d356900e.json
@@ -17,7 +17,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-95c57fb921a2e3725b92cbafac6e3dc360b88429f03dd1e2b1b55cfabe208cb7.json b/backend/.sqlx/query-95c57fb921a2e3725b92cbafac6e3dc360b88429f03dd1e2b1b55cfabe208cb7.json
index 4b989c893b..a189bc4da2 100644
--- a/backend/.sqlx/query-95c57fb921a2e3725b92cbafac6e3dc360b88429f03dd1e2b1b55cfabe208cb7.json
+++ b/backend/.sqlx/query-95c57fb921a2e3725b92cbafac6e3dc360b88429f03dd1e2b1b55cfabe208cb7.json
@@ -17,7 +17,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-9ca267c5a88f0cf3a4821e7514fe585131a42136c522a0fdde47c63cc0c6bc5a.json b/backend/.sqlx/query-9ca267c5a88f0cf3a4821e7514fe585131a42136c522a0fdde47c63cc0c6bc5a.json
new file mode 100644
index 0000000000..995bf49b52
--- /dev/null
+++ b/backend/.sqlx/query-9ca267c5a88f0cf3a4821e7514fe585131a42136c522a0fdde47c63cc0c6bc5a.json
@@ -0,0 +1,24 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT\n COUNT(*) > 0\n AND BOOL_AND(\n CASE\n -- For dependencies/: use IS NOT DISTINCT FROM (NULL = NULL is true for legacy)\n -- And the reason for this, is that for every script we also add dependency on default workspace dependencies by default\n -- that default/unnamed workspace dependencies may not exist, but we still do this.\n -- it is needed for windmill to know what to redeploy when default workspace dependencies are being added\n\n -- naturally for non-existant entries we have no hash of it\n -- so if we compared hash with '=' (instead of IS NOT DISTINCT FROM), it would give false on NULL = NULL,\n -- which would mean that this entire query returns false, which means relock skip cannot happen\n\n -- The solution is to say if both: referenced and current hash are NULLs we treat it as true, so it becomes no longer a blocker from skip.\n --\n -- It is backed up by the fact that server is responsible for deploying new workspace dependencies\n -- so if one was to deploy a new wdeps, server would assign it new hash, and this expression would be invalid and would not approve skip\n WHEN dm.imported_path LIKE 'dependencies/%'\n THEN dm.imported_lockfile_hash IS NOT DISTINCT FROM lh.lockfile_hash\n\n -- For scripts: use = with COALESCE (NULL = NULL becomes false)\n -- unlike w deps, we can't do IS NOT DISTINCT FROM here\n -- the reason is that scripts deployments are issued by other workers instead of the server\n -- which would mean that there is no guarantee that new d job will also write it's lock's hash to the `lock_hash`\n -- which could lead to false positives\n ELSE COALESCE(dm.imported_lockfile_hash = lh.lockfile_hash, false)\n END\n )\n FROM dependency_map dm\n LEFT JOIN lock_hash lh\n ON lh.workspace_id = dm.workspace_id\n AND lh.path = dm.imported_path\n WHERE dm.workspace_id = $1\n AND dm.importer_path = $2\n AND dm.importer_node_id = $3",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "?column?",
+ "type_info": "Bool"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Text",
+ "Text",
+ "Text"
+ ]
+ },
+ "nullable": [
+ null
+ ]
+ },
+ "hash": "9ca267c5a88f0cf3a4821e7514fe585131a42136c522a0fdde47c63cc0c6bc5a"
+}
diff --git a/backend/.sqlx/query-9f07510019ebe6f0c5fa17bf31c2d14755474cba82b3b388a47585a8bb325b1a.json b/backend/.sqlx/query-9f07510019ebe6f0c5fa17bf31c2d14755474cba82b3b388a47585a8bb325b1a.json
new file mode 100644
index 0000000000..25a32e5338
--- /dev/null
+++ b/backend/.sqlx/query-9f07510019ebe6f0c5fa17bf31c2d14755474cba82b3b388a47585a8bb325b1a.json
@@ -0,0 +1,17 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "INSERT INTO deployment_metadata (workspace_id, path, script_hash, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, script_hash) WHERE script_hash IS NOT NULL DO UPDATE SET deployment_msg = EXCLUDED.deployment_msg",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Varchar",
+ "Varchar",
+ "Int8",
+ "Text"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "9f07510019ebe6f0c5fa17bf31c2d14755474cba82b3b388a47585a8bb325b1a"
+}
diff --git a/backend/.sqlx/query-a264bbd8dbabb03854bd25350a7aeda0704770eb200bae635f1933eece90c9d6.json b/backend/.sqlx/query-a264bbd8dbabb03854bd25350a7aeda0704770eb200bae635f1933eece90c9d6.json
deleted file mode 100644
index 1030965135..0000000000
--- a/backend/.sqlx/query-a264bbd8dbabb03854bd25350a7aeda0704770eb200bae635f1933eece90c9d6.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "SELECT EXISTS(SELECT 1 FROM app WHERE path = 'g/all/setup_app')",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "exists",
- "type_info": "Bool"
- }
- ],
- "parameters": {
- "Left": []
- },
- "nullable": [
- null
- ]
- },
- "hash": "a264bbd8dbabb03854bd25350a7aeda0704770eb200bae635f1933eece90c9d6"
-}
diff --git a/backend/.sqlx/query-b615d73ddb43e9d655b86a0cf98f892bf40e629ee11ee4845199481755f2789d.json b/backend/.sqlx/query-b615d73ddb43e9d655b86a0cf98f892bf40e629ee11ee4845199481755f2789d.json
index 96f59aab3f..e6ef13f492 100644
--- a/backend/.sqlx/query-b615d73ddb43e9d655b86a0cf98f892bf40e629ee11ee4845199481755f2789d.json
+++ b/backend/.sqlx/query-b615d73ddb43e9d655b86a0cf98f892bf40e629ee11ee4845199481755f2789d.json
@@ -21,7 +21,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
@@ -71,7 +72,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-bbf166552ba15ce7cd76f812cdf7223414fa5c8a4860f3fe829d649baa1c5465.json b/backend/.sqlx/query-bbf166552ba15ce7cd76f812cdf7223414fa5c8a4860f3fe829d649baa1c5465.json
new file mode 100644
index 0000000000..e187b2cd91
--- /dev/null
+++ b/backend/.sqlx/query-bbf166552ba15ce7cd76f812cdf7223414fa5c8a4860f3fe829d649baa1c5465.json
@@ -0,0 +1,20 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT COUNT(*) FROM worker_ping WHERE ping_at > now() - interval '5 minutes'",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "count",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ null
+ ]
+ },
+ "hash": "bbf166552ba15ce7cd76f812cdf7223414fa5c8a4860f3fe829d649baa1c5465"
+}
diff --git a/backend/.sqlx/query-ead84a63cb965e36155605434c9e3670e50344f39b0d61eef8e60c2cdb57ae1f.json b/backend/.sqlx/query-c8dee3bd1ce03d8ee3c05345a0bdd5bdbd75396fe5bc24fd2d42edc79261169c.json
similarity index 64%
rename from backend/.sqlx/query-ead84a63cb965e36155605434c9e3670e50344f39b0d61eef8e60c2cdb57ae1f.json
rename to backend/.sqlx/query-c8dee3bd1ce03d8ee3c05345a0bdd5bdbd75396fe5bc24fd2d42edc79261169c.json
index 499e2e6730..9227c072bd 100644
--- a/backend/.sqlx/query-ead84a63cb965e36155605434c9e3670e50344f39b0d61eef8e60c2cdb57ae1f.json
+++ b/backend/.sqlx/query-c8dee3bd1ce03d8ee3c05345a0bdd5bdbd75396fe5bc24fd2d42edc79261169c.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n DELETE FROM dependency_map\n WHERE workspace_id = $1\n AND importer_path = $2\n AND importer_kind = $3::text::IMPORTER_KIND\n AND importer_node_id = $4\n AND imported_path = $5\n ",
+ "query": "\n DELETE FROM dependency_map\n WHERE workspace_id = $1\n AND importer_path = $2\n AND importer_kind = $3::text::IMPORTER_KIND\n AND importer_node_id = $4\n AND imported_path = $5\n AND imported_lockfile_hash IS NOT DISTINCT FROM $6 -- we don't want to delete other entries with other lockfile hash.\n ",
"describe": {
"columns": [],
"parameters": {
@@ -9,10 +9,11 @@
"Text",
"Text",
"Text",
- "Text"
+ "Text",
+ "Int8"
]
},
"nullable": []
},
- "hash": "ead84a63cb965e36155605434c9e3670e50344f39b0d61eef8e60c2cdb57ae1f"
+ "hash": "c8dee3bd1ce03d8ee3c05345a0bdd5bdbd75396fe5bc24fd2d42edc79261169c"
}
diff --git a/backend/.sqlx/query-cbbe20745c2b743acc814e8e77c0e4e154b511af676e085bbe88e72e7d14aee3.json b/backend/.sqlx/query-cbbe20745c2b743acc814e8e77c0e4e154b511af676e085bbe88e72e7d14aee3.json
new file mode 100644
index 0000000000..b72346db9e
--- /dev/null
+++ b/backend/.sqlx/query-cbbe20745c2b743acc814e8e77c0e4e154b511af676e085bbe88e72e7d14aee3.json
@@ -0,0 +1,23 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT lock FROM script WHERE path = $1 AND workspace_id = $2 AND lock IS NOT NULL\n AND deleted = false ORDER BY created_at DESC LIMIT 1",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "lock",
+ "type_info": "Text"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Text",
+ "Text"
+ ]
+ },
+ "nullable": [
+ true
+ ]
+ },
+ "hash": "cbbe20745c2b743acc814e8e77c0e4e154b511af676e085bbe88e72e7d14aee3"
+}
diff --git a/backend/.sqlx/query-cc5919b087e3319045fc2242f22384514987b6a4eb807ee375fb8b5cd4e92307.json b/backend/.sqlx/query-cc5919b087e3319045fc2242f22384514987b6a4eb807ee375fb8b5cd4e92307.json
index 0e338633fe..8a0dacd864 100644
--- a/backend/.sqlx/query-cc5919b087e3319045fc2242f22384514987b6a4eb807ee375fb8b5cd4e92307.json
+++ b/backend/.sqlx/query-cc5919b087e3319045fc2242f22384514987b6a4eb807ee375fb8b5cd4e92307.json
@@ -11,7 +11,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-d0b493da8ff5b3b78a9a0c6972cd2ca5449dad0fe361bee1a9834989bfeabbae.json b/backend/.sqlx/query-d0b493da8ff5b3b78a9a0c6972cd2ca5449dad0fe361bee1a9834989bfeabbae.json
index b0cef08da3..b71bf15f85 100644
--- a/backend/.sqlx/query-d0b493da8ff5b3b78a9a0c6972cd2ca5449dad0fe361bee1a9834989bfeabbae.json
+++ b/backend/.sqlx/query-d0b493da8ff5b3b78a9a0c6972cd2ca5449dad0fe361bee1a9834989bfeabbae.json
@@ -12,7 +12,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-d697b7311430e7bd5375ec5494179f4071e3bfe123d9600249cfa80c1103edd8.json b/backend/.sqlx/query-d697b7311430e7bd5375ec5494179f4071e3bfe123d9600249cfa80c1103edd8.json
deleted file mode 100644
index e35c4e2730..0000000000
--- a/backend/.sqlx/query-d697b7311430e7bd5375ec5494179f4071e3bfe123d9600249cfa80c1103edd8.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "UPDATE script SET lock = $1 WHERE hash = $2 AND workspace_id = $3",
- "describe": {
- "columns": [],
- "parameters": {
- "Left": [
- "Text",
- "Int8",
- "Text"
- ]
- },
- "nullable": []
- },
- "hash": "d697b7311430e7bd5375ec5494179f4071e3bfe123d9600249cfa80c1103edd8"
-}
diff --git a/backend/.sqlx/query-e004ebd5b5532a4b85984a62f8ad48a81aa3460c1ca07701f386135d72cdecf5.json b/backend/.sqlx/query-e004ebd5b5532a4b85984a62f8ad48a81aa3460c1ca07701f386135d72cdecf5.json
new file mode 100644
index 0000000000..0769d083d6
--- /dev/null
+++ b/backend/.sqlx/query-e004ebd5b5532a4b85984a62f8ad48a81aa3460c1ca07701f386135d72cdecf5.json
@@ -0,0 +1,20 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT 1",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "?column?",
+ "type_info": "Int4"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ null
+ ]
+ },
+ "hash": "e004ebd5b5532a4b85984a62f8ad48a81aa3460c1ca07701f386135d72cdecf5"
+}
diff --git a/backend/.sqlx/query-e32d6c6ae4e0d824c4cf19128182d67f36d1fd87fe4cf4f002e18367088c497c.json b/backend/.sqlx/query-e32d6c6ae4e0d824c4cf19128182d67f36d1fd87fe4cf4f002e18367088c497c.json
deleted file mode 100644
index 915cf7416b..0000000000
--- a/backend/.sqlx/query-e32d6c6ae4e0d824c4cf19128182d67f36d1fd87fe4cf4f002e18367088c497c.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "INSERT INTO dependency_map (workspace_id, importer_path, importer_kind, imported_path, importer_node_id)\n VALUES ($1, $2, $3::text::IMPORTER_KIND, $4, $5) ON CONFLICT DO NOTHING",
- "describe": {
- "columns": [],
- "parameters": {
- "Left": [
- "Varchar",
- "Varchar",
- "Text",
- "Varchar",
- "Varchar"
- ]
- },
- "nullable": []
- },
- "hash": "e32d6c6ae4e0d824c4cf19128182d67f36d1fd87fe4cf4f002e18367088c497c"
-}
diff --git a/backend/.sqlx/query-ecab1af12a7afa685c056b9d0e526275203fc8ecddf83ca6d05c9fb77e46e7ee.json b/backend/.sqlx/query-ecab1af12a7afa685c056b9d0e526275203fc8ecddf83ca6d05c9fb77e46e7ee.json
index f80b75b5ec..16ccdd10e9 100644
--- a/backend/.sqlx/query-ecab1af12a7afa685c056b9d0e526275203fc8ecddf83ca6d05c9fb77e46e7ee.json
+++ b/backend/.sqlx/query-ecab1af12a7afa685c056b9d0e526275203fc8ecddf83ca6d05c9fb77e46e7ee.json
@@ -21,7 +21,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
@@ -71,7 +72,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-ee537def1ead8bee48bb9f5c1f57d42e7add6011c34d91761ba23e2c74c4032c.json b/backend/.sqlx/query-ee537def1ead8bee48bb9f5c1f57d42e7add6011c34d91761ba23e2c74c4032c.json
index 4ce08c9e1c..536175599d 100644
--- a/backend/.sqlx/query-ee537def1ead8bee48bb9f5c1f57d42e7add6011c34d91761ba23e2c74c4032c.json
+++ b/backend/.sqlx/query-ee537def1ead8bee48bb9f5c1f57d42e7add6011c34d91761ba23e2c74c4032c.json
@@ -21,7 +21,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
@@ -71,7 +72,8 @@
"name": "native_trigger_service",
"kind": {
"Enum": [
- "nextcloud"
+ "nextcloud",
+ "google"
]
}
}
diff --git a/backend/.sqlx/query-f8c08997d7fd0158b4d3cc093fb0a2aadd4473e98873d5a7873f4fa944b99d58.json b/backend/.sqlx/query-f8c08997d7fd0158b4d3cc093fb0a2aadd4473e98873d5a7873f4fa944b99d58.json
new file mode 100644
index 0000000000..45979be595
--- /dev/null
+++ b/backend/.sqlx/query-f8c08997d7fd0158b4d3cc093fb0a2aadd4473e98873d5a7873f4fa944b99d58.json
@@ -0,0 +1,18 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "WITH update_lock AS (\n UPDATE script SET lock = $1 WHERE hash = $2 AND workspace_id = $3\n )\n INSERT INTO lock_hash (workspace_id, path, lockfile_hash)\n VALUES ($3, $4, $5)\n ON CONFLICT (workspace_id, path) DO UPDATE SET lockfile_hash = $5",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Text",
+ "Int8",
+ "Text",
+ "Varchar",
+ "Int8"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "f8c08997d7fd0158b4d3cc093fb0a2aadd4473e98873d5a7873f4fa944b99d58"
+}
diff --git a/backend/.sqlx/query-f912b91c940900b9961920ac0f71b7ba1e8cd50ce90c0c17336e9dd9c684f348.json b/backend/.sqlx/query-f912b91c940900b9961920ac0f71b7ba1e8cd50ce90c0c17336e9dd9c684f348.json
new file mode 100644
index 0000000000..2dd9d2d040
--- /dev/null
+++ b/backend/.sqlx/query-f912b91c940900b9961920ac0f71b7ba1e8cd50ce90c0c17336e9dd9c684f348.json
@@ -0,0 +1,26 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT\n worker_group,\n wm_version\n FROM worker_ping\n WHERE ping_at > now() - interval '5 minutes'\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "worker_group",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 1,
+ "name": "wm_version",
+ "type_info": "Varchar"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ false,
+ false
+ ]
+ },
+ "hash": "f912b91c940900b9961920ac0f71b7ba1e8cd50ce90c0c17336e9dd9c684f348"
+}
diff --git a/backend/CLAUDE.md b/backend/CLAUDE.md
index dcc993b6c5..54550c2dcb 100644
--- a/backend/CLAUDE.md
+++ b/backend/CLAUDE.md
@@ -49,6 +49,28 @@ Windmill uses a workspace-based architecture with multiple crates:
- Use feature flags: `#[cfg(feature = "enterprise")]`
- Isolate enterprise code in separate modules
+## Code Validation (MUST DO)
+
+After making backend changes, you MUST run `cargo check` and fix all errors and warnings before considering the work done.
+
+Only enable the feature flags relevant to your changes — do NOT use `all_sqlx_features` as it compiles the entire codebase and is very slow. Check the `[features]` section in `Cargo.toml` to identify which flags gate the crates/modules you modified.
+
+Examples:
+```bash
+# Changed core code (no feature-gated modules)
+cargo check
+
+# Changed code behind the enterprise feature
+cargo check --features enterprise
+
+# Changed kafka trigger code
+cargo check --features kafka
+```
+
+## Git Workflow
+
+- **Never push directly to main** — always create a branch and open a pull request
+
## Testing
- Write unit tests for core functionality
diff --git a/backend/Cargo.lock b/backend/Cargo.lock
index 3bc383bf77..5a3ed6ebd7 100644
--- a/backend/Cargo.lock
+++ b/backend/Cargo.lock
@@ -234,9 +234,9 @@ dependencies = [
[[package]]
name = "arc-swap"
-version = "1.8.1"
+version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ded5f9a03ac8f24d1b8a25101ee812cd32cdc8c50a4c50237de2c4915850e73"
+checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5"
dependencies = [
"rustversion",
]
@@ -554,7 +554,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
"synstructure 0.13.2",
]
@@ -577,7 +577,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -589,7 +589,7 @@ dependencies = [
"proc-macro2",
"quote",
"swc_macros_common",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -730,7 +730,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -752,7 +752,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -763,7 +763,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -848,9 +848,9 @@ dependencies = [
[[package]]
name = "aws-credential-types"
-version = "1.2.11"
+version = "1.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cd362783681b15d136480ad555a099e82ecd8e2d10a841e14dfd0078d67fee3"
+checksum = "e26bbf46abc608f2dc61fd6cb3b7b0665497cc259a21520151ed98f8b37d2c79"
dependencies = [
"aws-smithy-async",
"aws-smithy-runtime-api",
@@ -870,9 +870,9 @@ dependencies = [
[[package]]
name = "aws-lc-sys"
-version = "0.37.0"
+version = "0.37.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c34dda4df7017c8db52132f0f8a2e0f8161649d15723ed63fc00c82d0f2081a"
+checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549"
dependencies = [
"cc",
"cmake",
@@ -882,9 +882,9 @@ dependencies = [
[[package]]
name = "aws-runtime"
-version = "1.6.0"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c635c2dc792cb4a11ce1a4f392a925340d1bdf499289b5ec1ec6810954eb43f5"
+checksum = "b0f92058d22a46adf53ec57a6a96f34447daf02bff52e8fb956c66bcd5c6ac12"
dependencies = [
"aws-credential-types",
"aws-sigv4",
@@ -896,6 +896,7 @@ dependencies = [
"aws-smithy-types",
"aws-types",
"bytes",
+ "bytes-utils",
"fastrand",
"http 1.4.0",
"http-body 1.0.1",
@@ -907,9 +908,9 @@ dependencies = [
[[package]]
name = "aws-sdk-bedrock"
-version = "1.130.0"
+version = "1.131.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "883f0f0b2014a0bb59b6bfce8265a6ca6dc7e849d09314124f94a347b9d9e9f5"
+checksum = "ed3b305e7a8c79c55c3b6098727ca81d1cacca1dedace6f301a0db21940ff2b6"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -980,9 +981,9 @@ dependencies = [
[[package]]
name = "aws-sdk-rds"
-version = "1.125.0"
+version = "1.126.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6897e8c3b3621b5616ccb838b1d30b8e18fb0c0699cea8e235e5005f902f12a"
+checksum = "497a9468a09ecd67589e3c4b3ea324da3a37b4af6ab1e1fe94ffd98681cc7db9"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1029,9 +1030,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sso"
-version = "1.93.0"
+version = "1.94.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9dcb38bb33fc0a11f1ffc3e3e85669e0a11a37690b86f77e75306d8f369146a0"
+checksum = "699da1961a289b23842d88fe2984c6ff68735fdf9bdcbc69ceaeb2491c9bf434"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1053,9 +1054,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ssooidc"
-version = "1.95.0"
+version = "1.96.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ada8ffbea7bd1be1f53df1dadb0f8fdb04badb13185b3321b929d1ee3caad09"
+checksum = "e3e3a4cb3b124833eafea9afd1a6cc5f8ddf3efefffc6651ef76a03cbc6b4981"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1100,9 +1101,9 @@ dependencies = [
[[package]]
name = "aws-sigv4"
-version = "1.3.8"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efa49f3c607b92daae0c078d48a4571f599f966dce3caee5f1ea55c4d9073f99"
+checksum = "68f6ae9b71597dc5fd115d52849d7a5556ad9265885ad3492ea8d73b93bbc46e"
dependencies = [
"aws-credential-types",
"aws-smithy-eventstream",
@@ -1342,9 +1343,9 @@ dependencies = [
[[package]]
name = "aws-types"
-version = "1.3.11"
+version = "1.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164"
+checksum = "6c50f3cdf47caa8d01f2be4a6663ea02418e892f9bbfd82c7b9a3a37eaccdd3a"
dependencies = [
"aws-credential-types",
"aws-smithy-async",
@@ -1472,7 +1473,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -1612,7 +1613,7 @@ dependencies = [
"regex",
"rustc-hash 1.1.0",
"shlex",
- "syn 2.0.114",
+ "syn 2.0.115",
"which 4.4.2",
]
@@ -1633,7 +1634,7 @@ dependencies = [
"regex",
"rustc-hash 1.1.0",
"shlex",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -1653,7 +1654,7 @@ dependencies = [
"regex",
"rustc-hash 2.1.1",
"shlex",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -1671,7 +1672,7 @@ dependencies = [
"regex",
"rustc-hash 2.1.1",
"shlex",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -1859,9 +1860,9 @@ dependencies = [
[[package]]
name = "bon"
-version = "3.8.2"
+version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "234655ec178edd82b891e262ea7cf71f6584bcd09eff94db786be23f1821825c"
+checksum = "2d13a61f2963b88eef9c1be03df65d42f6996dfeac1054870d950fcf66686f83"
dependencies = [
"bon-macros",
"rustversion",
@@ -1869,9 +1870,9 @@ dependencies = [
[[package]]
name = "bon-macros"
-version = "3.8.2"
+version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ec27229c38ed0eb3c0feee3d2c1d6a4379ae44f418a29a658890e062d8f365"
+checksum = "d314cc62af2b6b0c65780555abb4d02a03dd3b799cd42419044f0c38d99738c0"
dependencies = [
"darling 0.23.0",
"ident_case",
@@ -1879,7 +1880,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -1902,7 +1903,7 @@ dependencies = [
"proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -1912,7 +1913,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17d4f95e880cfd28c4ca5a006cf7f6af52b4bcb7b5866f573b2faa126fb7affb"
dependencies = [
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2048,7 +2049,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2118,7 +2119,7 @@ dependencies = [
"gemm",
"half",
"libm",
- "memmap2 0.9.9",
+ "memmap2 0.9.10",
"num-traits",
"num_cpus",
"rand 0.9.0",
@@ -2193,7 +2194,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b4a6cae9efc04cc6cbb8faf338d2c497c165c83e74509cf4dbedea948bbf6e5"
dependencies = [
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2207,9 +2208,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.55"
+version = "1.2.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29"
+checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -2322,9 +2323,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.57"
+version = "4.5.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a"
+checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806"
dependencies = [
"clap_builder",
"clap_derive",
@@ -2332,9 +2333,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.57"
+version = "4.5.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238"
+checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2"
dependencies = [
"anstream",
"anstyle",
@@ -2351,14 +2352,14 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
name = "clap_lex"
-version = "0.7.7"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
+checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
[[package]]
name = "clipboard-win"
@@ -2406,7 +2407,7 @@ dependencies = [
"nom 7.1.3",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2810,7 +2811,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2913,7 +2914,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim 0.11.1",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2927,7 +2928,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim 0.11.1",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2940,7 +2941,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim 0.11.1",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2973,7 +2974,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core 0.20.11",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2984,7 +2985,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
dependencies = [
"darling_core 0.21.3",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -2995,7 +2996,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
dependencies = [
"darling_core 0.23.0",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -3487,7 +3488,7 @@ checksum = "df6f88d7ee27daf8b108ba910f9015176b36fbc72902b1ca5c2a5f1d1717e1a1"
dependencies = [
"datafusion-expr",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -3925,7 +3926,7 @@ checksum = "babccedee31ce7e57c3e6dff2cb3ab8d68c49d0df8222fe0d11d628e65192790"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -4316,7 +4317,7 @@ dependencies = [
"stringcase",
"strum 0.25.0",
"strum_macros 0.25.3",
- "syn 2.0.114",
+ "syn 2.0.115",
"thiserror 2.0.18",
]
@@ -4832,7 +4833,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -4886,7 +4887,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version 0.4.1",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -4915,7 +4916,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -4927,7 +4928,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version 0.4.1",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -5053,7 +5054,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -5088,7 +5089,7 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -5294,7 +5295,7 @@ dependencies = [
"enum-ordinalize",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -5360,7 +5361,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -5380,7 +5381,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -5400,7 +5401,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -5745,7 +5746,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -5783,7 +5784,7 @@ checksum = "32016f1242eb82af5474752d00fd8ebcd9004bd69b462b1c91de833972d08ed4"
dependencies = [
"proc-macro2",
"swc_macros_common",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -5840,9 +5841,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futures"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
dependencies = [
"futures-channel",
"futures-core",
@@ -5855,9 +5856,9 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
"futures-sink",
@@ -5865,15 +5866,15 @@ dependencies = [
[[package]]
name = "futures-core"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-executor"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
dependencies = [
"futures-core",
"futures-task",
@@ -5893,9 +5894,9 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
[[package]]
name = "futures-lite"
@@ -5912,32 +5913,32 @@ dependencies = [
[[package]]
name = "futures-macro"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
name = "futures-sink"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
[[package]]
name = "futures-task"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-channel",
"futures-core",
@@ -5947,7 +5948,6 @@ dependencies = [
"futures-task",
"memchr",
"pin-project-lite",
- "pin-utils",
"slab",
]
@@ -6224,7 +6224,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -6562,7 +6562,7 @@ checksum = "149e3ea90eb5a26ad354cfe3cb7f7401b9329032d0235f2687d03a35f30e5d4c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -7453,7 +7453,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -7672,9 +7672,9 @@ dependencies = [
[[package]]
name = "keccak"
-version = "0.1.5"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
+checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653"
dependencies = [
"cpufeatures",
]
@@ -7820,7 +7820,7 @@ dependencies = [
"quote",
"serde",
"serde_json",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -7858,9 +7858,9 @@ checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553"
[[package]]
name = "lazy-regex"
-version = "3.5.1"
+version = "3.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5c13b6857ade4c8ee05c3c3dc97d2ab5415d691213825b90d3211c425c1f907"
+checksum = "6bae91019476d3ec7147de9aa291cadb6d870abf2f3015d2da73a90325ac1496"
dependencies = [
"lazy-regex-proc_macros",
"once_cell",
@@ -7869,14 +7869,14 @@ dependencies = [
[[package]]
name = "lazy-regex-proc_macros"
-version = "3.5.1"
+version = "3.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a95c68db5d41694cea563c86a4ba4dc02141c16ef64814108cb23def4d5438"
+checksum = "4de9c1e1439d8b7b3061b2d209809f447ca33241733d9a3c01eabf2dc8d94358"
dependencies = [
"proc-macro2",
"quote",
"regex",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -7965,9 +7965,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.181"
+version = "0.2.182"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5"
+checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
[[package]]
name = "libffi"
@@ -8055,7 +8055,7 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
dependencies = [
"bitflags 2.9.4",
"libc",
- "redox_syscall 0.7.0",
+ "redox_syscall 0.7.1",
]
[[package]]
@@ -8457,9 +8457,9 @@ dependencies = [
[[package]]
name = "memmap2"
-version = "0.9.9"
+version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
+checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
dependencies = [
"libc",
"stable_deref_trait",
@@ -8520,7 +8520,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -8641,7 +8641,7 @@ checksum = "c402a4092d5e204f32c9e155431046831fa712637043c58cb73bc6bc6c9663b5"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -8686,7 +8686,7 @@ dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
"termcolor",
"thiserror 2.0.18",
]
@@ -8789,22 +8789,22 @@ dependencies = [
"quote",
"serde",
"serde_json",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
name = "native-tls"
-version = "0.2.14"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
+checksum = "9d5d26952a508f321b4d3d2e80e78fc2603eaefcdf0c30783867f19586518bdc"
dependencies = [
"libc",
"log",
"openssl",
- "openssl-probe 0.1.6",
+ "openssl-probe 0.2.1",
"openssl-sys",
"schannel",
- "security-framework 2.11.1",
+ "security-framework 3.6.0",
"security-framework-sys",
"tempfile",
]
@@ -8986,7 +8986,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -9254,7 +9254,7 @@ dependencies = [
"proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -9471,7 +9471,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -9969,7 +9969,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -10050,7 +10050,7 @@ dependencies = [
"phf_shared 0.11.3",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -10100,7 +10100,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -10312,7 +10312,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -10386,7 +10386,7 @@ dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -10397,7 +10397,7 @@ checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f"
dependencies = [
"proc-macro-rules-macros",
"proc-macro2",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -10409,7 +10409,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -10506,7 +10506,7 @@ dependencies = [
"prost",
"prost-types",
"regex",
- "syn 2.0.114",
+ "syn 2.0.115",
"tempfile",
]
@@ -10520,7 +10520,7 @@ dependencies = [
"itertools 0.14.0",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -10975,7 +10975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b"
dependencies = [
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -10989,9 +10989,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
+checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b"
dependencies = [
"bitflags 2.9.4",
]
@@ -11035,7 +11035,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -11360,7 +11360,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_json",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -11410,7 +11410,7 @@ dependencies = [
"proc-macro2",
"quote",
"rquickjs-core",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -11497,7 +11497,7 @@ dependencies = [
"quote",
"rust-embed-utils",
"shellexpand",
- "syn 2.0.114",
+ "syn 2.0.115",
"walkdir",
]
@@ -11685,7 +11685,7 @@ dependencies = [
"openssl-probe 0.2.1",
"rustls-pki-types",
"schannel",
- "security-framework 3.5.1",
+ "security-framework 3.6.0",
]
[[package]]
@@ -11731,7 +11731,7 @@ dependencies = [
"rustls-native-certs 0.8.3",
"rustls-platform-verifier-android",
"rustls-webpki 0.103.9",
- "security-framework 3.5.1",
+ "security-framework 3.6.0",
"security-framework-sys",
"webpki-root-certs 1.0.6",
"windows-sys 0.61.2",
@@ -12025,7 +12025,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -12037,7 +12037,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -12119,9 +12119,9 @@ dependencies = [
[[package]]
name = "security-framework"
-version = "3.5.1"
+version = "3.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
+checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38"
dependencies = [
"bitflags 2.9.4",
"core-foundation 0.10.1",
@@ -12132,9 +12132,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.15.0"
+version = "2.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
+checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a"
dependencies = [
"core-foundation-sys",
"libc",
@@ -12226,7 +12226,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -12237,7 +12237,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -12289,7 +12289,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -12356,7 +12356,7 @@ dependencies = [
"darling 0.21.3",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -12809,7 +12809,7 @@ checksum = "da5fc6819faabb412da764b99d3b713bb55083c11e7e0c00144d386cd6a1939c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -12874,7 +12874,7 @@ dependencies = [
"quote",
"sqlx-core",
"sqlx-macros-core",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -12897,7 +12897,7 @@ dependencies = [
"sqlx-mysql",
"sqlx-postgres",
"sqlx-sqlite",
- "syn 2.0.114",
+ "syn 2.0.115",
"tokio",
"url",
]
@@ -13061,7 +13061,7 @@ dependencies = [
"proc-macro2",
"quote",
"swc_macros_common",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13130,7 +13130,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13142,7 +13142,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13261,7 +13261,7 @@ dependencies = [
"proc-macro2",
"quote",
"swc_macros_common",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13310,7 +13310,7 @@ dependencies = [
"proc-macro2",
"quote",
"swc_macros_common",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13395,7 +13395,7 @@ dependencies = [
"proc-macro2",
"quote",
"swc_macros_common",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13502,7 +13502,7 @@ checksum = "63db0adcff29d220c3d151c5b25c0eabe7e32dd936212b84cdaa1392e3130497"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13513,7 +13513,7 @@ checksum = "f486687bfb7b5c560868f69ed2d458b880cebc9babebcb67e49f31b55c5bf847"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13536,7 +13536,7 @@ dependencies = [
"proc-macro2",
"quote",
"swc_macros_common",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13552,9 +13552,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.114"
+version = "2.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
+checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12"
dependencies = [
"proc-macro2",
"quote",
@@ -13590,7 +13590,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13707,7 +13707,7 @@ dependencies = [
"lru 0.12.5",
"lz4_flex",
"measure_time",
- "memmap2 0.9.9",
+ "memmap2 0.9.10",
"once_cell",
"oneshot",
"rayon",
@@ -13913,7 +13913,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -13924,7 +13924,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -14184,7 +14184,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -14451,9 +14451,9 @@ dependencies = [
[[package]]
name = "toml_parser"
-version = "1.0.7+spec-1.1.0"
+version = "1.0.8+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1"
+checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc"
dependencies = [
"winnow 0.7.14",
]
@@ -14617,7 +14617,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -14840,9 +14840,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
[[package]]
name = "typed-path"
-version = "0.12.2"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3015e6ce46d5ad8751e4a772543a30c7511468070e98e64e20165f8f81155b64"
+checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e"
[[package]]
name = "typeid"
@@ -14877,7 +14877,7 @@ checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -15355,7 +15355,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
"wasm-bindgen-shared",
]
@@ -15390,7 +15390,7 @@ checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -15425,7 +15425,7 @@ checksum = "a369369e4360c2884c3168d22bded735c43cccae97bbc147586d4b480edd138d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -15725,7 +15725,7 @@ dependencies = [
[[package]]
name = "windmill"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-nats",
@@ -15765,6 +15765,7 @@ dependencies = [
"tokio",
"tokio-stream",
"tracing",
+ "tracing-subscriber",
"url",
"uuid",
"windmill-api",
@@ -15776,8 +15777,10 @@ dependencies = [
"windmill-dep-map",
"windmill-git-sync",
"windmill-indexer",
+ "windmill-operator",
"windmill-queue",
"windmill-runtime-nativets",
+ "windmill-test-utils",
"windmill-worker",
"windows-service",
"windows-sys 0.52.0",
@@ -15785,7 +15788,7 @@ dependencies = [
[[package]]
name = "windmill-alerting"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -15798,7 +15801,7 @@ dependencies = [
[[package]]
name = "windmill-api"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"argon2",
@@ -15890,6 +15893,7 @@ dependencies = [
"windmill-api-debug",
"windmill-api-embeddings",
"windmill-api-flow-conversations",
+ "windmill-api-flows",
"windmill-api-groups",
"windmill-api-inputs",
"windmill-api-jobs",
@@ -15934,7 +15938,7 @@ dependencies = [
[[package]]
name = "windmill-api-agent-workers"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -15957,7 +15961,7 @@ dependencies = [
[[package]]
name = "windmill-api-assets"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -15970,7 +15974,7 @@ dependencies = [
[[package]]
name = "windmill-api-auth"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -15996,7 +16000,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"reqwest 0.12.28",
"serde",
@@ -16006,7 +16010,7 @@ dependencies = [
[[package]]
name = "windmill-api-configs"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16023,7 +16027,7 @@ dependencies = [
[[package]]
name = "windmill-api-debug"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"base64 0.22.1",
@@ -16046,7 +16050,7 @@ dependencies = [
[[package]]
name = "windmill-api-embeddings"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16069,7 +16073,7 @@ dependencies = [
[[package]]
name = "windmill-api-flow-conversations"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16083,9 +16087,29 @@ dependencies = [
"windmill-common",
]
+[[package]]
+name = "windmill-api-flows"
+version = "1.635.1"
+dependencies = [
+ "axum 0.7.9",
+ "chrono",
+ "hyper 1.8.1",
+ "serde",
+ "serde_json",
+ "sql-builder",
+ "sqlx",
+ "tracing",
+ "windmill-api-auth",
+ "windmill-audit",
+ "windmill-common",
+ "windmill-dep-map",
+ "windmill-git-sync",
+ "windmill-queue",
+]
+
[[package]]
name = "windmill-api-groups"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16105,7 +16129,7 @@ dependencies = [
[[package]]
name = "windmill-api-inputs"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16117,9 +16141,33 @@ dependencies = [
"windmill-common",
]
+[[package]]
+name = "windmill-api-integration-tests"
+version = "1.635.1"
+dependencies = [
+ "anyhow",
+ "async-nats",
+ "aws-config",
+ "aws-credential-types",
+ "aws-sdk-sqs",
+ "base64 0.22.1",
+ "rand 0.9.0",
+ "rdkafka",
+ "reqwest 0.13.1",
+ "rumqttc",
+ "serde",
+ "serde_json",
+ "sqlx",
+ "tokio",
+ "uuid",
+ "windmill-api-client",
+ "windmill-common",
+ "windmill-test-utils",
+]
+
[[package]]
name = "windmill-api-jobs"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16144,7 +16192,7 @@ dependencies = [
[[package]]
name = "windmill-api-npm-proxy"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"flate2",
@@ -16160,7 +16208,7 @@ dependencies = [
[[package]]
name = "windmill-api-openapi"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16181,7 +16229,7 @@ dependencies = [
[[package]]
name = "windmill-api-schedule"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16201,7 +16249,7 @@ dependencies = [
[[package]]
name = "windmill-api-scripts"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16230,7 +16278,7 @@ dependencies = [
[[package]]
name = "windmill-api-settings"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16256,7 +16304,7 @@ dependencies = [
[[package]]
name = "windmill-api-sse"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"lazy_static",
"serde",
@@ -16268,7 +16316,7 @@ dependencies = [
[[package]]
name = "windmill-api-users"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"argon2",
"axum 0.7.9",
@@ -16291,7 +16339,7 @@ dependencies = [
[[package]]
name = "windmill-api-workers"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16305,7 +16353,7 @@ dependencies = [
[[package]]
name = "windmill-api-workspaces"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16334,7 +16382,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"chrono",
"lazy_static",
@@ -16348,7 +16396,7 @@ dependencies = [
[[package]]
name = "windmill-autoscaling"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16367,7 +16415,7 @@ dependencies = [
[[package]]
name = "windmill-common"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"aes-gcm",
"anyhow",
@@ -16429,6 +16477,7 @@ dependencies = [
"reqwest-middleware",
"reqwest-retry",
"rsa",
+ "schemars 0.8.22",
"semver 1.0.27",
"serde",
"serde_json",
@@ -16466,7 +16515,7 @@ dependencies = [
[[package]]
name = "windmill-dep-map"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"chrono",
"itertools 0.14.0",
@@ -16485,7 +16534,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"regex",
"serde",
@@ -16500,7 +16549,7 @@ dependencies = [
[[package]]
name = "windmill-indexer"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"astral-tokio-tar",
@@ -16524,7 +16573,7 @@ dependencies = [
[[package]]
name = "windmill-jseval"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"futures",
@@ -16541,7 +16590,7 @@ dependencies = [
[[package]]
name = "windmill-macros"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"itertools 0.14.0",
"lazy_static",
@@ -16552,12 +16601,12 @@ dependencies = [
"serde",
"serde_derive",
"serde_yml",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
name = "windmill-mcp"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -16578,7 +16627,7 @@ dependencies = [
[[package]]
name = "windmill-native-triggers"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -16609,7 +16658,7 @@ dependencies = [
[[package]]
name = "windmill-oauth"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-oauth2",
@@ -16631,9 +16680,29 @@ dependencies = [
"windmill-common",
]
+[[package]]
+name = "windmill-operator"
+version = "1.635.1"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "futures",
+ "k8s-openapi",
+ "kube",
+ "schemars 0.8.22",
+ "serde",
+ "serde_json",
+ "serde_yml",
+ "sqlx",
+ "thiserror 2.0.18",
+ "tokio",
+ "tracing",
+ "windmill-common",
+]
+
[[package]]
name = "windmill-parser"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"convert_case 0.6.0",
"serde",
@@ -16642,7 +16711,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -16654,7 +16723,7 @@ dependencies = [
[[package]]
name = "windmill-parser-csharp"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"serde_json",
@@ -16666,7 +16735,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"gosyn",
@@ -16678,7 +16747,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -16690,7 +16759,7 @@ dependencies = [
[[package]]
name = "windmill-parser-java"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"serde_json",
@@ -16702,7 +16771,7 @@ dependencies = [
[[package]]
name = "windmill-parser-nu"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"nu-parser",
@@ -16713,7 +16782,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -16724,7 +16793,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -16737,7 +16806,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -16761,7 +16830,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ruby"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -16775,7 +16844,7 @@ dependencies = [
[[package]]
name = "windmill-parser-rust"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -16785,14 +16854,14 @@ dependencies = [
"quote",
"regex",
"serde_json",
- "syn 2.0.114",
+ "syn 2.0.115",
"toml",
"windmill-parser",
]
[[package]]
name = "windmill-parser-sql"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -16806,7 +16875,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -16825,7 +16894,7 @@ dependencies = [
[[package]]
name = "windmill-parser-yaml"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"serde",
@@ -16836,7 +16905,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -16873,7 +16942,7 @@ dependencies = [
[[package]]
name = "windmill-runtime-nativets"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"const_format",
@@ -16911,7 +16980,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"wasm-bindgen",
"wasm-bindgen-test",
@@ -16921,7 +16990,7 @@ dependencies = [
[[package]]
name = "windmill-store"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -16948,9 +17017,32 @@ dependencies = [
"windmill-oauth",
]
+[[package]]
+name = "windmill-test-utils"
+version = "1.635.1"
+dependencies = [
+ "anyhow",
+ "axum 0.7.9",
+ "chrono",
+ "futures",
+ "serde",
+ "serde_json",
+ "sqlx",
+ "tokio",
+ "tracing",
+ "uuid",
+ "windmill-api",
+ "windmill-api-agent-workers",
+ "windmill-api-client",
+ "windmill-common",
+ "windmill-queue",
+ "windmill-runtime-nativets",
+ "windmill-worker",
+]
+
[[package]]
name = "windmill-trigger"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -16983,7 +17075,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-email"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -17003,7 +17095,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-gcp"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -17037,7 +17129,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-http"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -17071,7 +17163,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-kafka"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -17094,7 +17186,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-mqtt"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -17118,7 +17210,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-nats"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-nats",
@@ -17142,7 +17234,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-postgres"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -17177,7 +17269,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-sqs"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -17205,7 +17297,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-websocket"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-trait",
@@ -17228,7 +17320,7 @@ dependencies = [
[[package]]
name = "windmill-types"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"chrono",
@@ -17245,7 +17337,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
-version = "1.630.2"
+version = "1.635.1"
dependencies = [
"anyhow",
"async-once-cell",
@@ -17458,7 +17550,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -17469,7 +17561,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -17480,7 +17572,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -17491,7 +17583,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -17502,7 +17594,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -17513,7 +17605,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -17984,7 +18076,7 @@ dependencies = [
"heck 0.5.0",
"indexmap 2.11.1",
"prettyplease",
- "syn 2.0.114",
+ "syn 2.0.115",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
@@ -18000,7 +18092,7 @@ dependencies = [
"prettyplease",
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
"wit-bindgen-core",
"wit-bindgen-rust",
]
@@ -18196,7 +18288,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
"synstructure 0.13.2",
]
@@ -18208,7 +18300,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
"synstructure 0.13.2",
]
@@ -18229,7 +18321,7 @@ checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -18249,7 +18341,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
"synstructure 0.13.2",
]
@@ -18270,7 +18362,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
@@ -18303,14 +18395,14 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.114",
+ "syn 2.0.115",
]
[[package]]
name = "zip"
-version = "7.4.0"
+version = "7.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc12baa6db2b15a140161ce53d72209dacea594230798c24774139b54ecaa980"
+checksum = "c42e33efc22a0650c311c2ef19115ce232583abbe80850bc8b66509ebef02de0"
dependencies = [
"crc32fast",
"indexmap 2.11.1",
diff --git a/backend/Cargo.toml b/backend/Cargo.toml
index 37b367619d..c41289aa8c 100644
--- a/backend/Cargo.toml
+++ b/backend/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "windmill"
-version = "1.630.2"
+version = "1.635.1"
authors.workspace = true
edition.workspace = true
@@ -9,6 +9,7 @@ resolver = "2"
members = [
"./windmill-api",
"./windmill-api-scripts",
+ "./windmill-api-flows",
"./windmill-api-users",
"./windmill-api-workspaces",
"./windmill-api-groups",
@@ -51,6 +52,7 @@ members = [
"./windmill-audit",
"./windmill-git-sync",
"./windmill-autoscaling",
+ "./windmill-operator",
"./windmill-indexer",
"./windmill-macros",
"./windmill-oauth",
@@ -66,12 +68,14 @@ members = [
"./parsers/windmill-parser-py",
"./parsers/windmill-parser-py-imports",
"./parsers/windmill-sql-datatype-parser-wasm",
- "./parsers/windmill-parser-yaml", "windmill-macros", "parsers/windmill-parser-nu"
+ "./parsers/windmill-parser-yaml", "windmill-macros", "parsers/windmill-parser-nu",
+ "./windmill-test-utils",
+ "./windmill-api-integration-tests",
]
exclude = ["./windmill-duckdb-ffi-internal"]
[workspace.package]
-version = "1.630.2"
+version = "1.635.1"
authors = ["Ruben Fiszel "]
edition = "2021"
@@ -92,8 +96,8 @@ lto = "thin"
[features]
default = []
-private = ["windmill-api/private", "windmill-api-agent-workers?/private", "windmill-autoscaling/private", "windmill-common/private", "windmill-git-sync/private", "windmill-indexer/private", "windmill-queue/private", "windmill-worker/private"]
-agent_worker_server = ["windmill-api/agent_worker_server", "dep:windmill-api-agent-workers"]
+private = ["windmill-api/private", "windmill-api-agent-workers?/private", "windmill-autoscaling/private", "windmill-common/private", "windmill-git-sync/private", "windmill-indexer/private", "windmill-operator?/private", "windmill-queue/private", "windmill-worker/private", "windmill-test-utils/private"]
+agent_worker_server = ["windmill-api/agent_worker_server", "dep:windmill-api-agent-workers", "windmill-test-utils/agent_worker_server"]
enterprise = ["windmill-worker/enterprise", "windmill-queue/enterprise", "windmill-api/enterprise", "windmill-api-agent-workers?/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise", "windmill-git-sync/enterprise", "windmill-common/prometheus", "windmill-common/enterprise"]
local_reports = ["windmill-common/local_reports"]
enterprise_saml = ["windmill-api/enterprise_saml", "oauth2"]
@@ -109,7 +113,7 @@ cloud = ["windmill-queue/cloud", "windmill-worker/cloud", "windmill-common/cloud
jemalloc = ["windmill-common/jemalloc", "dep:tikv-jemallocator", "dep:tikv-jemalloc-sys", "dep:tikv-jemalloc-ctl"]
tantivy = ["dep:windmill-indexer", "windmill-api/tantivy", "windmill-indexer/enterprise", "windmill-indexer/parquet", "windmill-common/tantivy", "enterprise", "parquet"]
sqlx = ["windmill-worker/sqlx"]
-deno_core = ["windmill-worker/deno_core", "dep:windmill-runtime-nativets"]
+deno_core = ["windmill-worker/deno_core", "dep:windmill-runtime-nativets", "windmill-test-utils/deno_core"]
deno_core_mac = ["deno_core", "windmill-worker/libffi_mac"]
kafka = ["windmill-api/kafka"]
kafka-gssapi = ["windmill-api/kafka-gssapi"]
@@ -132,9 +136,11 @@ zip = ["windmill-api/zip"]
static_frontend = ["windmill-api/static_frontend"]
scoped_cache = ["windmill-common/scoped_cache"]
no_auth = ["windmill-api/no_auth"]
+operator = ["dep:windmill-operator"]
+test_job_debouncing = []
private_registry_test = []
# Languages
-python = ["windmill-worker/python", "windmill-api/python"]
+python = ["windmill-worker/python", "windmill-api/python", "windmill-test-utils/python"]
rust = ["windmill-worker/rust"]
mysql = ["windmill-worker/mysql"]
oracledb = ["windmill-worker/oracledb"]
@@ -160,11 +166,11 @@ oss_core = [
"static_frontend", "mcp", "bedrock", "inline_preview",
"quickjs"
]
-ce_core = ["oss_core", "private"]
+ce_core = ["oss_core", "private", "operator"]
ee_core = [
"enterprise", "stripe", "prometheus", "cloud",
"kafka", "sqs_trigger", "nats", "gcp_trigger",
- "jemalloc", "otel"
+ "jemalloc", "otel", "operator"
]
ee_server = ["enterprise_saml", "tantivy", "agent_worker_server", "local_reports"]
# Edition meta-features: CE variants
@@ -172,13 +178,14 @@ oss = ["oss_core", "all_languages", "no_auth"]
ce_rpi = ["ce_core", "all_languages"]
ce = ["ce_rpi", "jemalloc", "dind", "agent_worker_server"]
# Edition meta-features: EE variants
-ee = ["ce", "ee_core", "ee_server"]
-ee_rhel = ["ce_core", "ee_core", "all_languages"]
+ee = ["ce", "ee_core", "ee_server", "kafka-gssapi"]
+ee_rhel = ["ce_core", "ee_core", "kafka-gssapi", "all_languages"]
ee_windows = ["ce_core", "ee_core", "all_languages_windows"]
all_sqlx_features = ["all_languages", "enterprise", "enterprise_saml", "embedding", "parquet", "prometheus", "flow_testing",
"openidconnect", "cloud", "jemalloc", "tantivy", "sqlx", "kafka", "kafka-gssapi", "nats", "otel", "dind", "websocket", "http_trigger",
"postgres_trigger", "mcp", "mqtt_trigger", "sqs_trigger", "gcp_trigger", "smtp", "stripe",
- "license", "oauth2", "zip", "static_frontend", "scoped_cache", "agent_worker_server", "bedrock", "native_trigger", "quickjs"]
+ "license", "oauth2", "zip", "static_frontend", "scoped_cache", "agent_worker_server", "bedrock", "native_trigger", "quickjs",
+ "windmill-git-sync/all_sqlx_features"]
[patch.crates-io]
object_store = { git = "https://github.com/apache/arrow-rs-object-store", rev = "36752c975d4f29e20b57c91f81a10872dcd48ae7" }
@@ -199,8 +206,10 @@ windmill-api-settings.workspace = true
windmill-worker.workspace = true
windmill-indexer = { workspace = true, optional = true }
windmill-autoscaling = { workspace = true, optional = true }
+windmill-operator = { workspace = true, optional = true }
futures.workspace = true
tracing.workspace = true
+tracing-subscriber.workspace = true
sqlx.workspace = true
sql-builder.workspace = true
rand.workspace = true
@@ -239,6 +248,7 @@ serde_json.workspace = true
reqwest.workspace = true
windmill-queue = { workspace = true, features = ["failpoints"] }
windmill-dep-map.workspace = true
+windmill-test-utils.workspace = true
axum.workspace = true
serde.workspace = true
windmill-api-client.workspace = true
@@ -261,12 +271,14 @@ windmill-common = { path = "./windmill-common", default-features = false }
windmill-audit = { path = "./windmill-audit" }
windmill-git-sync = { path = "./windmill-git-sync" }
windmill-autoscaling = { path = "./windmill-autoscaling" }
+windmill-operator = { path = "./windmill-operator" }
windmill-indexer = {path = "./windmill-indexer"}
windmill-mcp = {path = "./windmill-mcp"}
windmill-oauth = {path = "./windmill-oauth"}
windmill-macros = {path = "./windmill-macros"}
windmill-api-auth = { path = "./windmill-api-auth" }
windmill-api-scripts = { path = "./windmill-api-scripts" }
+windmill-api-flows = { path = "./windmill-api-flows" }
windmill-api-users = { path = "./windmill-api-users" }
windmill-api-workspaces = { path = "./windmill-api-workspaces" }
windmill-api-groups = { path = "./windmill-api-groups" }
@@ -315,6 +327,7 @@ windmill-parser-php = { path = "./parsers/windmill-parser-php" }
windmill-jseval = { path = "./windmill-jseval" }
windmill-runtime-nativets = { path = "./windmill-runtime-nativets" }
windmill-api-client = { path = "./windmill-api-client" }
+windmill-test-utils = { path = "./windmill-test-utils" }
reqwest-retry = "^0"
reqwest-middleware = { version = "^0", features = ["json"] }
@@ -551,6 +564,7 @@ backon = "1.3.0"
flume = { version = "0.11.1", features = ["async"] }
kube = { version = "1.1.0", features = ["runtime", "derive"] }
+schemars = "0.8"
k8s-openapi = { version = "0.25.0", features = ["latest"] }
libloading = "0.8.8"
@@ -570,7 +584,7 @@ tree-sitter-ruby = "0.23.0"
oracle = { version = "0.6.3", features = ["chrono"] }
rumqttc = { version = "0.24.0", features = ["use-native-tls"]}
strum = { version = "0.27", features = ["derive"] }
-strum_macros = "^0"
+strum_macros = "0.27"
hudsucker = { version = "0.22", features = ["rcgen-ca", "native-tls-client"] }
hyper-http-proxy = { version = "1", default-features = false, features = ["native-tls"] }
rcgen = "0.13"
diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt
index c3e5ea69bb..5cb666dcac 100644
--- a/backend/ee-repo-ref.txt
+++ b/backend/ee-repo-ref.txt
@@ -1 +1 @@
-b2bd490cd14e7794bebbd8737c2833ea671370b3
\ No newline at end of file
+c2f12c6989e9f069fd274085aefde29264f73c8c
\ No newline at end of file
diff --git a/backend/migrations/20260209000001_dependency_map_lockfile_hash.down.sql b/backend/migrations/20260209000001_dependency_map_lockfile_hash.down.sql
new file mode 100644
index 0000000000..53c1828256
--- /dev/null
+++ b/backend/migrations/20260209000001_dependency_map_lockfile_hash.down.sql
@@ -0,0 +1,3 @@
+DROP TABLE IF EXISTS lock_hash;
+DROP INDEX IF EXISTS dependency_map_importer_path_idx;
+ALTER TABLE dependency_map DROP COLUMN IF EXISTS imported_lockfile_hash;
diff --git a/backend/migrations/20260209000001_dependency_map_lockfile_hash.up.sql b/backend/migrations/20260209000001_dependency_map_lockfile_hash.up.sql
new file mode 100644
index 0000000000..4c4203fab5
--- /dev/null
+++ b/backend/migrations/20260209000001_dependency_map_lockfile_hash.up.sql
@@ -0,0 +1,14 @@
+-- Add column to track lockfile hash of imported scripts
+-- Used to skip re-locking when imports' lockfiles haven't changed
+ALTER TABLE dependency_map ADD COLUMN imported_lockfile_hash BIGINT;
+
+-- Index for queries filtering by importer (skip-relock check, load(), clear_map_for_item)
+CREATE INDEX IF NOT EXISTS dependency_map_importer_path_idx ON dependency_map (workspace_id, importer_path);
+
+-- Stores lockfile/content hashes to detect when imports' locks have changed
+CREATE TABLE lock_hash (
+ workspace_id VARCHAR(50) NOT NULL REFERENCES workspace(id) ON DELETE CASCADE,
+ path VARCHAR(255) NOT NULL,
+ lockfile_hash BIGINT NOT NULL,
+ PRIMARY KEY (workspace_id, path)
+);
diff --git a/backend/migrations/20260212000000_remove_setup_app.down.sql b/backend/migrations/20260212000000_remove_setup_app.down.sql
new file mode 100644
index 0000000000..61a77a811a
--- /dev/null
+++ b/backend/migrations/20260212000000_remove_setup_app.down.sql
@@ -0,0 +1,3 @@
+-- The setup_app was a complex app created via multiple migrations.
+-- Restoring it would require re-running the original creation and update migrations.
+-- This is a no-op down migration since the app is no longer needed.
diff --git a/backend/migrations/20260212000000_remove_setup_app.up.sql b/backend/migrations/20260212000000_remove_setup_app.up.sql
new file mode 100644
index 0000000000..9f663dcbc0
--- /dev/null
+++ b/backend/migrations/20260212000000_remove_setup_app.up.sql
@@ -0,0 +1 @@
+DELETE FROM app WHERE workspace_id = 'admins' AND path = 'g/all/setup_app';
diff --git a/backend/parsers/windmill-parser-py-imports/src/mapping.rs b/backend/parsers/windmill-parser-py-imports/src/mapping.rs
index cb9a14b27a..6246a1f156 100644
--- a/backend/parsers/windmill-parser-py-imports/src/mapping.rs
+++ b/backend/parsers/windmill-parser-py-imports/src/mapping.rs
@@ -328,6 +328,7 @@ pub static FULL_IMPORTS_MAP: PyMap = phf_map! {
"azure.keyvault.secrets" => "azure-keyvault-secrets",
"azure.storage.blob" => "azure-storage-blob",
"azure.storage.filedatalake" => "azure-storage-file-datalake",
+ "azure.identity" => "azure-identity",
// Add new entry here ^
};
diff --git a/backend/src/main.rs b/backend/src/main.rs
index 4a7b23aab7..a55d95affd 100644
--- a/backend/src/main.rs
+++ b/backend/src/main.rs
@@ -10,10 +10,11 @@ use monitor::{
load_base_url, load_otel, reload_critical_alerts_on_db_oversize,
reload_delete_logs_periodically_setting, reload_indexer_config,
reload_instance_python_version_setting, reload_maven_repos_setting,
- reload_no_default_maven_setting, reload_nuget_config_setting,
- reload_powershell_repo_pat_setting, reload_powershell_repo_url_setting,
- reload_ruby_repos_setting, reload_timeout_wait_result_setting,
- send_current_log_file_to_object_store, send_logs_to_object_store, WORKERS_NAMES,
+ reload_maven_settings_xml_setting, reload_no_default_maven_setting,
+ reload_nuget_config_setting, reload_powershell_repo_pat_setting,
+ reload_powershell_repo_url_setting, reload_ruby_repos_setting,
+ reload_timeout_wait_result_setting, send_current_log_file_to_object_store,
+ send_logs_to_object_store, WORKERS_NAMES,
};
use rand::Rng;
use sqlx::{Pool, Postgres};
@@ -42,15 +43,15 @@ use windmill_common::{
DEFAULT_TAGS_WORKSPACES_SETTING, EMAIL_DOMAIN_SETTING, ENV_SETTINGS,
EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING, EXTRA_PIP_INDEX_URL_SETTING,
HUB_API_SECRET_SETTING, HUB_BASE_URL_SETTING, INDEXER_SETTING,
- INSTANCE_PYTHON_VERSION_SETTING, JOB_DEFAULT_TIMEOUT_SECS_SETTING, JWT_SECRET_SETTING,
- KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, MAVEN_REPOS_SETTING,
- MONITOR_LOGS_ON_OBJECT_STORE_SETTING, NO_DEFAULT_MAVEN_SETTING,
+ INSTANCE_PYTHON_VERSION_SETTING, JOB_DEFAULT_TIMEOUT_SECS_SETTING, JOB_ISOLATION_SETTING,
+ JWT_SECRET_SETTING, KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, MAVEN_REPOS_SETTING,
+ MAVEN_SETTINGS_XML_SETTING, MONITOR_LOGS_ON_OBJECT_STORE_SETTING, NO_DEFAULT_MAVEN_SETTING,
NPM_CONFIG_REGISTRY_SETTING, NUGET_CONFIG_SETTING, OAUTH_SETTING, OTEL_SETTING,
- OTEL_TRACING_PROXY_SETTING, PIP_INDEX_URL_SETTING, POWERSHELL_REPO_PAT_SETTING,
- POWERSHELL_REPO_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
+ OTEL_TRACING_PROXY_SETTING, PIP_INDEX_URL_SETTING,
+ POWERSHELL_REPO_PAT_SETTING, POWERSHELL_REPO_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING,
RUBY_REPOS_SETTING, SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, SMTP_SETTING, TEAMS_SETTING,
- TIMEOUT_WAIT_RESULT_SETTING,
+ TIMEOUT_WAIT_RESULT_SETTING, UV_INDEX_STRATEGY_SETTING,
},
scripts::ScriptLang,
stats_oss::schedule_stats,
@@ -100,10 +101,10 @@ use crate::monitor::{
reload_bunfig_install_scopes_setting, reload_critical_alert_mute_ui_setting,
reload_critical_error_channels_setting, reload_extra_pip_index_url_setting,
reload_hub_api_secret_setting, reload_hub_base_url_setting, reload_job_default_timeout_setting,
- reload_jwt_secret_setting, reload_license_key, reload_npm_config_registry_setting,
- reload_otel_tracing_proxy_setting, reload_pip_index_url_setting,
- reload_retention_period_setting, reload_scim_token_setting, reload_smtp_config,
- reload_worker_config, MonitorIteration,
+ reload_job_isolation_setting, reload_jwt_secret_setting, reload_license_key,
+ reload_npm_config_registry_setting, reload_otel_tracing_proxy_setting,
+ reload_pip_index_url_setting, reload_retention_period_setting, reload_scim_token_setting,
+ reload_smtp_config, reload_uv_index_strategy_setting, reload_worker_config, MonitorIteration,
};
#[cfg(feature = "parquet")]
@@ -483,6 +484,9 @@ fn print_help() {
println!(" version Show Windmill version and exit");
println!(" cache [hubPaths.json] Pre-cache hub scripts (default: ./hubPaths.json)");
println!(" cache-rt Pre-cache hub resource types");
+ println!(" sync-config Sync instance config from a YAML file to the database");
+ println!(" operator Run the Kubernetes operator (watches WindmillInstance CRDs)");
+ println!(" operator crd Print the WindmillInstance CRD YAML to stdout");
println!();
println!("Environment variables (name = default):");
println!(" DATABASE_URL = The Postgres database url.");
@@ -606,6 +610,43 @@ async fn windmill_main() -> anyhow::Result<()> {
cache_hub_resource_types().await?;
return Ok(());
}
+ "sync-config" => {
+ tracing_subscriber::fmt::init();
+ let path = std::env::args().nth(2).unwrap_or_else(|| {
+ eprintln!("Usage: windmill sync-config ");
+ std::process::exit(1);
+ });
+ let contents = tokio::fs::read_to_string(&path)
+ .await
+ .with_context(|| format!("Could not read config file: {path}"))?;
+ let mut config: windmill_common::instance_config::InstanceConfig =
+ serde_yml::from_str(&contents)
+ .with_context(|| format!("Could not parse YAML from: {path}"))?;
+ windmill_common::instance_config::resolve_env_refs(&mut config.global_settings)
+ .map_err(|var| anyhow::anyhow!("environment variable '{var}' not found"))?;
+
+ tracing::info!("Connecting to database...");
+ let db = crate::db_connect::initial_connection().await?;
+ config.sync_to_db(&db).await?;
+ tracing::info!("Synced instance config from {path}");
+ return Ok(());
+ }
+ #[cfg(feature = "operator")]
+ "operator" => {
+ let sub_arg = std::env::args().nth(2).unwrap_or_default();
+ if sub_arg == "crd" {
+ windmill_operator::print_crd_yaml();
+ return Ok(());
+ }
+
+ tracing_subscriber::fmt::init();
+ tracing::info!("Starting Windmill Kubernetes operator...");
+ tracing::info!("Connecting to database...");
+ let db = crate::db_connect::initial_connection().await?;
+ tracing::info!("Database connected. Starting controller...");
+ windmill_operator::run(db).await?;
+ return Ok(());
+ }
_ => {}
}
@@ -1216,11 +1257,15 @@ Windmill Community Edition {GIT_VERSION}
last_settings_reload = Instant::now();
}
- if server_mode {
- if !*windmill_common::QUIET_LOGS {
- tracing::info!("monitor task started");
- }
- }
+ let monitor_start = Instant::now();
+ let warn_handle = if server_mode {
+ Some(tokio::spawn(async move {
+ tokio::time::sleep(Duration::from_secs(5)).await;
+ tracing::warn!("monitor task has been running for more than 5s");
+ }))
+ } else {
+ None
+ };
monitor_db(
&conn,
&base_internal_url,
@@ -1235,10 +1280,12 @@ Windmill Community Edition {GIT_VERSION}
)
.await;
monitor_iteration += 1;
- if server_mode {
- if !*windmill_common::QUIET_LOGS {
- tracing::info!("monitor task finished");
- }
+ if let Some(handle) = warn_handle {
+ handle.abort();
+ }
+ let elapsed = monitor_start.elapsed();
+ if server_mode && elapsed >= Duration::from_secs(5) {
+ tracing::info!("monitor task finished in {elapsed:.1?}");
}
},
}
@@ -1555,6 +1602,7 @@ async fn process_notify_event(
reload_delete_logs_periodically_setting(conn).await
}
JOB_DEFAULT_TIMEOUT_SECS_SETTING => reload_job_default_timeout_setting(conn).await,
+ JOB_ISOLATION_SETTING => reload_job_isolation_setting(conn).await,
#[cfg(feature = "parquet")]
OBJECT_STORE_CONFIG_SETTING => {
if !disable_s3_store {
@@ -1564,6 +1612,7 @@ async fn process_notify_event(
SCIM_TOKEN_SETTING => reload_scim_token_setting(conn).await,
EXTRA_PIP_INDEX_URL_SETTING => reload_extra_pip_index_url_setting(conn).await,
PIP_INDEX_URL_SETTING => reload_pip_index_url_setting(conn).await,
+ UV_INDEX_STRATEGY_SETTING => reload_uv_index_strategy_setting(conn).await,
INSTANCE_PYTHON_VERSION_SETTING => {
reload_instance_python_version_setting(conn).await
}
@@ -1573,6 +1622,7 @@ async fn process_notify_event(
POWERSHELL_REPO_URL_SETTING => reload_powershell_repo_url_setting(conn).await,
POWERSHELL_REPO_PAT_SETTING => reload_powershell_repo_pat_setting(conn).await,
MAVEN_REPOS_SETTING => reload_maven_repos_setting(conn).await,
+ MAVEN_SETTINGS_XML_SETTING => reload_maven_settings_xml_setting(conn).await,
NO_DEFAULT_MAVEN_SETTING => reload_no_default_maven_setting(conn).await,
RUBY_REPOS_SETTING => reload_ruby_repos_setting(conn).await,
HUB_API_SECRET_SETTING => reload_hub_api_secret_setting(conn).await,
diff --git a/backend/src/monitor.rs b/backend/src/monitor.rs
index b854516b69..d36f2739cb 100644
--- a/backend/src/monitor.rs
+++ b/backend/src/monitor.rs
@@ -54,12 +54,14 @@ use windmill_common::{
DEFAULT_TAGS_PER_WORKSPACE_SETTING, DEFAULT_TAGS_WORKSPACES_SETTING,
EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING, EXTRA_PIP_INDEX_URL_SETTING,
HUB_API_SECRET_SETTING, HUB_BASE_URL_SETTING, INSTANCE_PYTHON_VERSION_SETTING,
- JOB_DEFAULT_TIMEOUT_SECS_SETTING, JWT_SECRET_SETTING, KEEP_JOB_DIR_SETTING,
- LICENSE_KEY_SETTING, MONITOR_LOGS_ON_OBJECT_STORE_SETTING, NPM_CONFIG_REGISTRY_SETTING,
- NUGET_CONFIG_SETTING, OTEL_SETTING, OTEL_TRACING_PROXY_SETTING, PIP_INDEX_URL_SETTING,
- POWERSHELL_REPO_PAT_SETTING, POWERSHELL_REPO_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
+ JOB_DEFAULT_TIMEOUT_SECS_SETTING, JOB_ISOLATION_SETTING, JWT_SECRET_SETTING,
+ KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, MONITOR_LOGS_ON_OBJECT_STORE_SETTING,
+ NPM_CONFIG_REGISTRY_SETTING, NUGET_CONFIG_SETTING, OTEL_SETTING,
+ OTEL_TRACING_PROXY_SETTING, PIP_INDEX_URL_SETTING, POWERSHELL_REPO_PAT_SETTING,
+ POWERSHELL_REPO_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING,
SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, TIMEOUT_WAIT_RESULT_SETTING,
+ UV_INDEX_STRATEGY_SETTING,
},
indexer::load_indexer_config,
jwt::JWT_SECRET,
@@ -84,11 +86,12 @@ use windmill_common::{
use windmill_common::{client::AuthedClient, global_settings::APP_WORKSPACED_ROUTE_SETTING};
use windmill_queue::{cancel_job, get_queued_job_v2, SameWorkerPayload};
use windmill_worker::{
- result_processor::handle_job_error, JobCompletedSender, OtelTracingProxySettings,
- SameWorkerSender, BUNFIG_INSTALL_SCOPES, INSTANCE_PYTHON_VERSION, JOB_DEFAULT_TIMEOUT,
- KEEP_JOB_DIR, MAVEN_REPOS, NO_DEFAULT_MAVEN, NPM_CONFIG_REGISTRY, NUGET_CONFIG,
- OTEL_TRACING_PROXY_SETTINGS, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL, POWERSHELL_REPO_PAT,
- POWERSHELL_REPO_URL,
+ result_processor::handle_job_error, JobCompletedSender, JobIsolationLevel,
+ OtelTracingProxySettings, SameWorkerSender, BUNFIG_INSTALL_SCOPES, CARGO_REGISTRIES,
+ INSTANCE_PYTHON_VERSION, JAVA_HOME_DIR, JOB_DEFAULT_TIMEOUT, JOB_ISOLATION, KEEP_JOB_DIR,
+ MAVEN_REPOS, MAVEN_SETTINGS_XML, NO_DEFAULT_MAVEN, NPM_CONFIG_REGISTRY, NSJAIL_AVAILABLE,
+ NUGET_CONFIG, OTEL_TRACING_PROXY_SETTINGS, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL,
+ POWERSHELL_REPO_PAT, POWERSHELL_REPO_URL, UV_INDEX_STRATEGY,
};
#[cfg(feature = "parquet")]
@@ -315,8 +318,10 @@ pub async fn initial_load(
if worker_mode {
reload_job_default_timeout_setting(&conn).await;
+ reload_job_isolation_setting(&conn).await;
reload_extra_pip_index_url_setting(&conn).await;
reload_pip_index_url_setting(&conn).await;
+ reload_uv_index_strategy_setting(&conn).await;
reload_npm_config_registry_setting(&conn).await;
reload_bunfig_install_scopes_setting(&conn).await;
reload_instance_python_version_setting(&conn).await;
@@ -324,8 +329,10 @@ pub async fn initial_load(
reload_powershell_repo_url_setting(&conn).await;
reload_powershell_repo_pat_setting(&conn).await;
reload_maven_repos_setting(&conn).await;
+ reload_maven_settings_xml_setting(&conn).await;
reload_no_default_maven_setting(&conn).await;
reload_ruby_repos_setting(&conn).await;
+ reload_cargo_registries_setting(&conn).await;
}
}
@@ -1250,6 +1257,16 @@ pub async fn reload_pip_index_url_setting(conn: &Connection) {
.await;
}
+pub async fn reload_uv_index_strategy_setting(conn: &Connection) {
+ reload_option_setting_with_tracing(
+ conn,
+ UV_INDEX_STRATEGY_SETTING,
+ "UV_INDEX_STRATEGY",
+ UV_INDEX_STRATEGY.clone(),
+ )
+ .await;
+}
+
pub async fn reload_instance_python_version_setting(conn: &Connection) {
reload_option_setting_with_tracing(
conn,
@@ -1320,6 +1337,39 @@ pub async fn reload_maven_repos_setting(conn: &Connection) {
.await;
}
+pub async fn reload_maven_settings_xml_setting(conn: &Connection) {
+ reload_option_setting_with_tracing(
+ conn,
+ windmill_common::global_settings::MAVEN_SETTINGS_XML_SETTING,
+ "MAVEN_SETTINGS_XML",
+ MAVEN_SETTINGS_XML.clone(),
+ )
+ .await;
+
+ if !cfg!(feature = "enterprise") {
+ return;
+ }
+
+ let settings_xml = MAVEN_SETTINGS_XML.read().await.clone();
+ match settings_xml {
+ Some(ref content) if !content.trim().is_empty() => {
+ let m2_dir = format!("{JAVA_HOME_DIR}/.m2");
+ if let Err(e) = tokio::fs::create_dir_all(&m2_dir).await {
+ tracing::error!("Failed to create .m2 directory: {e:#}");
+ return;
+ }
+ let settings_path = format!("{m2_dir}/settings.xml");
+ if let Err(e) = tokio::fs::write(&settings_path, content).await {
+ tracing::error!("Failed to write Maven settings.xml: {e:#}");
+ }
+ }
+ _ => {
+ let settings_path = format!("{JAVA_HOME_DIR}/.m2/settings.xml");
+ let _ = tokio::fs::remove_file(&settings_path).await;
+ }
+ }
+}
+
pub async fn reload_no_default_maven_setting(conn: &Connection) {
let value = load_value_from_global_settings_with_conn(
conn,
@@ -1346,6 +1396,16 @@ pub async fn reload_ruby_repos_setting(conn: &Connection) {
.await;
}
+pub async fn reload_cargo_registries_setting(conn: &Connection) {
+ reload_option_setting_with_tracing(
+ conn,
+ windmill_common::global_settings::CARGO_REGISTRIES_SETTING,
+ "CARGO_REGISTRIES",
+ CARGO_REGISTRIES.clone(),
+ )
+ .await;
+}
+
pub async fn reload_hub_api_secret_setting(conn: &Connection) {
reload_option_setting_with_tracing(
conn,
@@ -1395,6 +1455,32 @@ pub async fn reload_job_default_timeout_setting(conn: &Connection) {
.await;
}
+pub async fn reload_job_isolation_setting(conn: &Connection) {
+ let value =
+ match load_value_from_global_settings_with_conn(conn, JOB_ISOLATION_SETTING, true).await {
+ Ok(Some(v)) => JobIsolationLevel::from_str(v.as_str().unwrap_or("")),
+ Ok(None) => JobIsolationLevel::Undefined,
+ Err(e) => {
+ tracing::error!("Error reloading job_isolation setting: {:?}", e);
+ return;
+ }
+ };
+ let old_value = JobIsolationLevel::from_u8(JOB_ISOLATION.swap(value as u8, Ordering::Relaxed));
+ if old_value != value {
+ tracing::info!(
+ "job_isolation setting changed from {:?} to {:?}",
+ old_value,
+ value
+ );
+ }
+ if value == JobIsolationLevel::NsjailSandboxing && NSJAIL_AVAILABLE.is_none() {
+ tracing::error!(
+ "job_isolation is set to nsjail_sandboxing but nsjail is not available on this worker. \
+ All jobs will fail until nsjail is installed or the setting is changed."
+ );
+ }
+}
+
pub async fn reload_request_size(conn: &Connection) {
if let Err(e) = reload_setting(
conn,
diff --git a/backend/substitute_ee_code.sh b/backend/substitute_ee_code.sh
index 7cd9a0b25a..4f1a870b1a 100755
--- a/backend/substitute_ee_code.sh
+++ b/backend/substitute_ee_code.sh
@@ -11,12 +11,10 @@ EE_CODE_DIR="../windmill-ee-private/"
while [[ $# -gt 0 ]]; do
case $1 in
-r|--revert)
- # If EE files have been substituted, this will revert them to their initial content.
- # This relies on `git restore` so the EE files must not be committed to the repo for
- # this to work (commit hooks should prevent this from happening, as well as the fact
- # that we're using symlinks by default).
+ # Removes all _ee.rs files from the backend directory. Symlinks are deleted.
+ # Regular files with content differing from windmill-ee-private are moved back
+ # to the EE repo so nothing is lost.
REVERT="YES"
- MOVE_NEW_FILES="YES"
shift
;;
-c|--copy)
@@ -66,12 +64,28 @@ if [ ! -d "${EE_CODE_DIR}" ]; then
fi
if [ "$REVERT" == "YES" ]; then
- for ee_file in $(find ${EE_CODE_DIR} -name "*ee.rs"); do
- ce_file="${ee_file/${EE_CODE_DIR}/}"
- ce_file="${root_dirpath}/backend/${ce_file}"
- rm ${ce_file} || true
+ backend_dirpath="${root_dirpath}/backend/"
+ for ce_file in $(find "${root_dirpath}/backend" -name "*_ee.rs"); do
+ if [ -L "${ce_file}" ]; then
+ rm "${ce_file}"
+ echo "Deleted symlink '${ce_file}'"
+ else
+ ee_file="${ce_file/${backend_dirpath}/}"
+ ee_file="${EE_CODE_DIR}${ee_file}"
+ if [ ! -f "${ee_file}" ] || ! diff -q "${ce_file}" "${ee_file}" > /dev/null 2>&1; then
+ mkdir -p "$(dirname "${ee_file}")"
+ mv "${ce_file}" "${ee_file}"
+ echo "Moved '${ce_file}' -->> '${ee_file}'"
+ else
+ rm "${ce_file}"
+ echo "Deleted '${ce_file}' (identical to EE)"
+ fi
+ fi
done
-elif [ "$MOVE_NEW_FILES" == "NO" ]; then
+ exit 0
+fi
+
+if [ "$MOVE_NEW_FILES" == "NO" ]; then
# This replaces all files in current repo with alternative EE files in windmill-ee-private
for ee_file in $(find "${EE_CODE_DIR}" -name "*ee.rs"); do
ce_file="${ee_file/${EE_CODE_DIR}/}"
diff --git a/backend/summarize_schema.py b/backend/summarize_schema.py
index a6d929ba9a..daa7f5e93c 100644
--- a/backend/summarize_schema.py
+++ b/backend/summarize_schema.py
@@ -1,6 +1,6 @@
# This script is used to summarize the database schema.
# You can use pg_dump to dump the schema to a file.
-# pg_dump --file "schema.sql" --host "localhost" --port "5432" --username "postgres" --no-password --format=c --large-objects --schema-only --no-owner --no-privileges --no-tablespaces --no-unlogged-table-data --no-comments --no-publications --no-subscriptions --no-security-labels --no-toast-compression --no-table-access-method --verbose --schema "public" "windmill"
+# pg_dump --file "schema.sql" --format=p --large-objects --schema-only --no-owner --no-privileges --no-tablespaces --no-unlogged-table-data --no-comments --no-publications --no-subscriptions --no-security-labels --no-toast-compression --no-table-access-method --verbose --schema "public" "postgresql://postgres:changeme@localhost:5432/windmill"
# Then you can run python summarize_schema.py schema.sql to get the summarized schema.
import re
@@ -17,6 +17,7 @@ def summarize_schema(file_path):
# Use state variables to parse multi-line definitions
current_table = None
current_enum = None
+ pending_alter_table = None # For multi-line ALTER TABLE ... ADD CONSTRAINT
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
@@ -54,6 +55,9 @@ def summarize_schema(file_path):
match_column = re.match(r'^"?(\w+)"?\s+([\w\d\.\[\]\(\)]+)', line)
if match_column:
col_name = match_column.group(1)
+ # Skip CONSTRAINT definitions (e.g., CHECK, UNIQUE) mistakenly matched as columns
+ if col_name.upper() == 'CONSTRAINT':
+ continue
col_type = match_column.group(2)
tables[current_table]['columns'].append(f"{col_name} ({col_type})")
@@ -65,16 +69,22 @@ def summarize_schema(file_path):
tables[current_table]['pks'].update(pk_cols)
continue
- # --- Parse Foreign Keys (defined outside CREATE TABLE) ---
- match_fk = re.match(r"ALTER TABLE ONLY public\.(\w+)\s+ADD CONSTRAINT \w+ FOREIGN KEY \(([\w,\s\"]+)\) REFERENCES public\.(\w+)\(([\w,\s\"]+)\);", line)
- if match_fk:
- from_table, from_cols, to_table, to_cols = match_fk.groups()
- # Clean up column names
- from_cols_clean = ', '.join([c.strip().strip('"') for c in from_cols.split(',')])
- to_cols_clean = ', '.join([c.strip().strip('"') for c in to_cols.split(',')])
-
- fk_string = f"({from_cols_clean}) -> {to_table}({to_cols_clean})"
- tables[from_table]['fks'].append(fk_string)
+ # --- Parse Foreign Keys (defined outside CREATE TABLE, may span 2 lines) ---
+ match_alter = re.match(r"ALTER TABLE ONLY public\.(\w+)$", line)
+ if match_alter:
+ pending_alter_table = match_alter.group(1)
+ continue
+
+ if pending_alter_table:
+ match_fk = re.match(r"ADD CONSTRAINT \w+ FOREIGN KEY \(([\w,\s\"]+)\) REFERENCES public\.(\w+)\(([\w,\s\"]+)\)", line)
+ if match_fk:
+ from_cols, to_table, to_cols = match_fk.groups()
+ from_cols_clean = ', '.join([c.strip().strip('"') for c in from_cols.split(',')])
+ to_cols_clean = ', '.join([c.strip().strip('"') for c in to_cols.split(',')])
+ fk_string = f"({from_cols_clean}) -> {to_table}({to_cols_clean})"
+ tables[pending_alter_table]['fks'].append(fk_string)
+ pending_alter_table = None
+ continue
# --- Parse Index definitions ---
match_index = re.match(r"CREATE (UNIQUE )?INDEX (\w+) ON public\.(\w+) USING (\w+) \((.+)\);", line)
@@ -94,44 +104,73 @@ def summarize_schema(file_path):
return enums, tables
+TYPE_ABBREVIATIONS = {
+ 'character': 'char',
+ 'integer': 'int',
+ 'bigint': 'bigint',
+ 'smallint': 'smallint',
+ 'boolean': 'bool',
+ 'timestamp': 'ts',
+ 'bytea': 'bytes',
+ 'real': 'float',
+ 'json': 'json',
+ 'jsonb': 'jsonb',
+ 'text': 'text',
+ 'uuid': 'uuid',
+ 'bit(64)': 'bit64',
+}
+
+def shorten_type(col_str):
+ """Shorten a 'name (type)' string to 'name(short_type)'."""
+ match = re.match(r'^(\w+) \((.+)\)$', col_str)
+ if not match:
+ return col_str
+ name, typ = match.group(1), match.group(2)
+ # Strip public. prefix from enum types
+ typ = re.sub(r'^public\.', '', typ)
+ # Apply abbreviations (prefix-based to handle parametrized types like character(64) and array types like integer[])
+ for prefix, abbr in TYPE_ABBREVIATIONS.items():
+ if typ.startswith(prefix):
+ typ = abbr + typ[len(prefix):]
+ break
+ return f"{name}({typ})"
+
def format_output(enums, tables):
"""
- Formats the parsed schema data into a clean, readable string.
+ Formats the parsed schema data into a compact, LLM-friendly string.
"""
output = []
-
- output.append("### Simplified Database Schema ###")
- output.append("\n--- Custom Data Types (ENUMs) ---\n")
+
+ output.append("# Database Schema")
+ output.append("")
+ output.append("## ENUMs")
if not enums:
- output.append("No custom ENUM types found.")
+ output.append("(none)")
else:
for name, values in sorted(enums.items()):
- output.append(f"{name}:")
- for v in values:
- output.append(f" - {v}")
- output.append("")
+ output.append(f"{name}: {', '.join(values)}")
- output.append("\n--- Tables and Relationships ---\n")
+ output.append("")
+ output.append("## Tables")
if not tables:
- output.append("No tables found.")
+ output.append("(none)")
else:
for name, data in sorted(tables.items()):
- output.append(f"TABLE: {name}")
+ # Columns: inline, comma-separated, with PK marker and shortened types
+ cols = []
for col in data['columns']:
+ col_short = shorten_type(col)
col_name = col.split(' ')[0]
- marker = " (PK)" if col_name in data['pks'] else ""
- output.append(f" - {col}{marker}")
-
+ if col_name in data['pks']:
+ col_short += " PK"
+ cols.append(col_short)
+ output.append(f"{name}: {', '.join(cols)}")
+
+ # Foreign keys on one indented line
if data['fks']:
- output.append(" Relationships:")
- for fk in data['fks']:
- output.append(f" - {fk}")
-
- if data['indexes']:
- output.append(" Indexes:")
- for idx in data['indexes']:
- output.append(f" - {idx}")
- output.append("-" * 20)
+ output.append(f" FK: {' | '.join(data['fks'])}")
+
+ # Indexes omitted for brevity — query the database for exact index info
return "\n".join(output)
diff --git a/backend/summarized_schema.txt b/backend/summarized_schema.txt
index 5ec7fa7263..0e3d3257df 100644
--- a/backend/summarized_schema.txt
+++ b/backend/summarized_schema.txt
@@ -1,1088 +1,194 @@
-### Simplified Database Schema ###
+# Database Schema
---- Custom Data Types (ENUMs) ---
+## ENUMs
+action_kind: create, update, delete, execute
+asset_access_type: r, w, rw
+asset_kind: s3object, resource, variable, ducklake, datatable
+asset_usage_kind: script, flow, job
+authentication_method: none, windmill, api_key, basic_http, custom_script, signature
+autoscaling_event_type: full_scaleout, scalein, scaleout
+aws_auth_resource_type: oidc, credentials
+delivery_mode: push, pull
+draft_type: script, flow, app
+favorite_kind: app, script, flow, raw_app, asset
+gcp_subscription_mode: create_update, existing
+http_method: get, post, put, delete, patch
+importer_kind: script, flow, app
+job_kind: script, preview, flow, dependencies, flowpreview, script_hub, identity, flowdependencies, http, graphql, postgresql, noop, appdependencies, deploymentcallback, singlestepflow, flowscript, flownode, appscript, aiagent, unassigned_script, unassigned_flow, unassigned_singlestepflow
+job_status: success, failure, canceled, skipped
+job_trigger_kind: webhook, http, websocket, kafka, email, nats, schedule, app, ui, postgres, sqs, gcp, mqtt, nextcloud
+log_mode: standalone, server, worker, agent, indexer, mcp
+login_type: password, github
+message_type: user, assistant, tool
+metric_kind: scalar_int, scalar_float, timeseries_int, timeseries_float
+mqtt_client_version: v3, v5
+native_trigger_service: nextcloud
+request_type: sync, async, sync_sse
+runnable_type: ScriptHash, ScriptPath, FlowPath
+script_kind: script, trigger, failure, command, approval, preprocessor
+script_lang: python3, deno, go, bash, postgresql, nativets, bun, mysql, bigquery, snowflake, graphql, powershell, mssql, php, bunnative, rust, ansible, csharp, oracledb, nu, java, duckdb, ruby
+trigger_kind: webhook, http, websocket, kafka, email, nats, postgres, sqs, mqtt, gcp, default_email, nextcloud
+trigger_mode: enabled, disabled, suspended
+workspace_key_kind: cloud
-action_kind:
- - create
- - update
- - delete
- - execute
-
-authentication_method:
- - none
- - windmill
- - api_key
- - basic_http
- - custom_script
- - signature
-
-autoscaling_event_type:
- - full_scaleout
- - scalein
- - scaleout
-
-aws_auth_resource_type:
- - oidc
- - credentials
-
-delivery_mode:
- - push
- - pull
-
-draft_type:
- - script
- - flow
- - app
-
-favorite_kind:
- - app
- - script
- - flow
- - raw_app
-
-gcp_subscription_mode:
- - create_update
- - existing
-
-http_method:
- - get
- - post
- - put
- - delete
- - patch
-
-importer_kind:
- - script
- - flow
- - app
-
-job_kind:
- - script
- - preview
- - flow
- - dependencies
- - flowpreview
- - script_hub
- - identity
- - flowdependencies
- - http
- - graphql
- - postgresql
- - noop
- - appdependencies
- - deploymentcallback
- - singlescriptflow
- - flowscript
- - flownode
- - appscript
-
-job_status:
- - success
- - failure
- - canceled
- - skipped
-
-job_trigger_kind:
- - webhook
- - http
- - websocket
- - kafka
- - email
- - nats
- - schedule
- - app
- - ui
- - postgres
- - sqs
- - gcp
-
-log_mode:
- - standalone
- - server
- - worker
- - agent
- - indexer
- - mcp
-
-login_type:
- - password
- - github
-
-metric_kind:
- - scalar_int
- - scalar_float
- - timeseries_int
- - timeseries_float
-
-mqtt_client_version:
- - v3
- - v5
-
-runnable_type:
- - ScriptHash
- - ScriptPath
- - FlowPath
-
-script_kind:
- - script
- - trigger
- - failure
- - command
- - approval
- - preprocessor
-
-script_lang:
- - python3
- - deno
- - go
- - bash
- - postgresql
- - nativets
- - bun
- - mysql
- - bigquery
- - snowflake
- - graphql
- - powershell
- - mssql
- - php
- - bunnative
- - rust
- - ansible
- - csharp
- - oracledb
- - nu
- - java
- - duckdb
-
-trigger_kind:
- - webhook
- - http
- - websocket
- - kafka
- - email
- - nats
- - postgres
- - sqs
- - mqtt
- - gcp
-
-workspace_key_kind:
- - cloud
-
-
---- Tables and Relationships ---
-
-TABLE: _sqlx_migrations
- - version (bigint)
- - description (text)
- - installed_on (timestamp)
- - success (boolean)
- - checksum (bytea)
- - execution_time (bigint)
---------------------
-TABLE: account
- - workspace_id (character)
- - id (integer)
- - expires_at (timestamp)
- - refresh_token (character)
- - client (character)
- - refresh_error (text)
---------------------
-TABLE: alerts
- - id (integer)
- - alert_type (character)
- - message (text)
- - created_at (timestamp)
- - acknowledged (boolean)
- - workspace_id (text)
- - acknowledged_workspace (boolean)
- - resource (text)
- Indexes:
- - INDEX alerts_by_workspace (btree) ON (workspace_id)
---------------------
-TABLE: app
- - id (bigint)
- - workspace_id (character)
- - path (character)
- - summary (character)
- - policy (jsonb)
- - versions (bigint[])
- - extra_perms (jsonb)
- - draft_only (boolean)
- - custom_path (text)
- - CONSTRAINT (app_custom_path_check)
---------------------
-TABLE: app_script
- - id (bigint)
- - app (bigint)
- - hash (character(64))
- - lock (text)
- - code (text)
- - code_sha256 (character(64))
---------------------
-TABLE: app_version
- - id (bigint)
- - app_id (bigint)
- - value (json)
- - created_by (character)
- - created_at (timestamp)
- - raw_app (boolean)
---------------------
-TABLE: app_version_lite
- - id (bigint)
- - value (jsonb)
---------------------
-TABLE: audit
- - workspace_id (character)
- - id (integer)
- - timestamp (timestamp)
- - username (character)
- - operation (character)
- - action_kind (public.action_kind)
- - resource (character)
- - parameters (jsonb)
- Indexes:
- - INDEX ix_audit_timestamps (btree) ON (timestamp DESC)
---------------------
-TABLE: autoscaling_event
- - id (integer)
- - worker_group (text)
- - event_type (public.autoscaling_event_type)
- - desired_workers (integer)
- - applied_at (timestamp)
- - reason (text)
- Indexes:
- - INDEX autoscaling_event_worker_group_idx (btree) ON (worker_group, applied_at)
---------------------
-TABLE: capture
- - workspace_id (character)
- - path (character)
- - created_at (timestamp)
- - created_by (character)
- - main_args (jsonb)
- - is_flow (boolean)
- - trigger_kind (public.trigger_kind)
- - preprocessor_args (jsonb)
- - id (bigint)
- - CONSTRAINT (capture_payload_too_big)
---------------------
-TABLE: capture_config
- - workspace_id (character)
- - path (character)
- - is_flow (boolean)
- - trigger_kind (public.trigger_kind)
- - trigger_config (jsonb)
- - owner (character)
- - email (character)
- - server_id (character)
- - last_client_ping (timestamp)
- - last_server_ping (timestamp)
- - error (text)
---------------------
-TABLE: cloud_workspace_settings
- - workspace_id (character)
- - threshold_alert_amount (integer)
- - last_alert_sent (timestamp)
- - last_warning_sent (timestamp)
---------------------
-TABLE: concurrency_counter
- - concurrency_id (character)
- - job_uuids (jsonb)
---------------------
-TABLE: concurrency_key
- - key (character)
- - ended_at (timestamp)
- - job_id (uuid)
- Indexes:
- - INDEX concurrency_key_ended_at_idx (btree) ON (key, ended_at DESC)
---------------------
-TABLE: concurrency_locks
- - id (character)
- - last_locked_at (timestamp)
- - owner (character)
---------------------
-TABLE: config
- - name (character)
- - config (jsonb)
---------------------
-TABLE: custom_concurrency_key_ended
- - key (character)
- - ended_at (timestamp)
---------------------
-TABLE: dependency_map
- - workspace_id (character)
- - importer_path (character)
- - importer_kind (public.importer_kind)
- - imported_path (character)
- - importer_node_id (character)
- Indexes:
- - INDEX dependency_map_imported_path_idx (btree) ON (workspace_id, imported_path)
---------------------
-TABLE: deployment_metadata
- - workspace_id (character)
- - path (character)
- - script_hash (bigint)
- - app_version (bigint)
- - callback_job_ids (uuid[])
- - deployment_msg (text)
- - flow_version (bigint)
- Indexes:
- - UNIQUE INDEX deployment_metadata_app (btree) ON (workspace_id, path, app_version) WHERE (app_version IS NOT NULL)
- - UNIQUE INDEX deployment_metadata_flow (btree) ON (workspace_id, path, flow_version) WHERE (flow_version IS NOT NULL)
- - UNIQUE INDEX deployment_metadata_script (btree) ON (workspace_id, script_hash) WHERE (script_hash IS NOT NULL)
---------------------
-TABLE: draft
- - workspace_id (character)
- - path (character)
- - typ (public.draft_type)
- - value (json)
- - created_at (timestamp)
---------------------
-TABLE: email_to_igroup
- - email (character)
- - igroup (character)
---------------------
-TABLE: favorite
- - usr (character)
- - workspace_id (character)
- - path (character)
- - favorite_kind (public.favorite_kind)
---------------------
-TABLE: flow
- - workspace_id (character)
- - path (character)
- - summary (text)
- - description (text)
- - value (jsonb)
- - edited_by (character)
- - edited_at (timestamp)
- - archived (boolean)
- - schema (json)
- - extra_perms (jsonb)
- - dependency_job (uuid)
- - draft_only (boolean)
- - tag (character)
- - ws_error_handler_muted (boolean)
- - dedicated_worker (boolean)
- - timeout (integer)
- - visible_to_runner_only (boolean)
- - concurrency_key (character)
- - versions (bigint[])
- - on_behalf_of_email (text)
- - lock_error_logs (text)
- - CONSTRAINT (proper_id)
- Indexes:
- - INDEX flow_extra_perms (gin) ON (extra_perms)
---------------------
-TABLE: flow_node
- - id (bigint)
- - workspace_id (character)
- - hash (bigint)
- - path (character)
- - lock (text)
- - code (text)
- - flow (jsonb)
- - hash_v2 (character(64))
- Indexes:
- - INDEX flow_node_hash (btree) ON (hash)
---------------------
-TABLE: flow_version
- - id (bigint)
- - workspace_id (character)
- - path (character)
- - value (jsonb)
- - schema (json)
- - created_by (character)
- - created_at (timestamp)
- Indexes:
- - INDEX index_flow_version_path_created_at (btree) ON (path, created_at)
---------------------
-TABLE: flow_version_lite
- - id (bigint)
- - value (jsonb)
---------------------
-TABLE: folder
- - name (character)
- - workspace_id (character)
- - display_name (character)
- - owners (character)
- - extra_perms (jsonb)
- - summary (text)
- - edited_at (timestamp)
- - created_by (character)
- Indexes:
- - INDEX folder_extra_perms (gin) ON (extra_perms)
- - INDEX folder_owners (gin) ON (owners)
---------------------
-TABLE: gcp_trigger
- - gcp_resource_path (character)
- - topic_id (character)
- - subscription_id (character)
- - delivery_type (public.delivery_mode)
- - delivery_config (jsonb)
- - path (character)
- - script_path (character)
- - is_flow (boolean)
- - workspace_id (character)
- - edited_by (character)
- - email (character)
- - edited_at (timestamp)
- - extra_perms (jsonb)
- - server_id (character)
- - last_server_ping (timestamp)
- - error (text)
- - enabled (boolean)
- - subscription_mode (public.gcp_subscription_mode)
- - CONSTRAINT (gcp_trigger_check)
- - CONSTRAINT (gcp_trigger_subscription_id_check)
- - CONSTRAINT (gcp_trigger_topic_id_check)
- Indexes:
- - UNIQUE INDEX unique_subscription_per_gcp_resource (btree) ON (subscription_id, gcp_resource_path, workspace_id)
---------------------
-TABLE: global_settings
- - name (character)
- - value (jsonb)
- - updated_at (timestamp)
---------------------
-TABLE: group_
- - workspace_id (character)
- - name (character)
- - summary (text)
- - extra_perms (jsonb)
- - CONSTRAINT (proper_name)
- Indexes:
- - INDEX group_extra_perms (gin) ON (extra_perms)
---------------------
-TABLE: healthchecks
- - id (bigint)
- - check_type (character)
- - healthy (boolean)
- - created_at (timestamp)
- Indexes:
- - INDEX healthchecks_check_type_created_at (btree) ON (check_type, created_at)
---------------------
-TABLE: http_trigger
- - path (character)
- - route_path (character)
- - route_path_key (character)
- - script_path (character)
- - is_flow (boolean)
- - workspace_id (character)
- - edited_by (character)
- - email (character)
- - edited_at (timestamp)
- - extra_perms (jsonb)
- - is_async (boolean)
- - authentication_method (public.authentication_method)
- - http_method (public.http_method)
- - static_asset_config (jsonb)
- - is_static_website (boolean)
- - workspaced_route (boolean)
- - wrap_body (boolean)
- - raw_string (boolean)
- - authentication_resource_path (character)
---------------------
-TABLE: input
- - id (uuid)
- - workspace_id (character)
- - runnable_id (character)
- - runnable_type (public.runnable_type)
- - name (text)
- - args (jsonb)
- - created_at (timestamp)
- - created_by (character)
- - is_public (boolean)
---------------------
-TABLE: instance_group
- - name (character)
- - summary (character)
- - id (character)
- - scim_display_name (character)
- - external_id (character)
---------------------
-TABLE: job_logs
- - job_id (uuid)
- - workspace_id (character)
- - created_at (timestamp)
- - logs (text)
- - log_offset (integer)
- - log_file_index (text[])
---------------------
-TABLE: job_perms
- - job_id (uuid)
- - email (character)
- - username (character)
- - is_admin (boolean)
- - is_operator (boolean)
- - created_at (timestamp)
- - workspace_id (character)
- - groups (text[])
- - folders (jsonb[])
---------------------
-TABLE: job_stats
- - workspace_id (character)
- - job_id (uuid)
- - metric_id (character)
- - metric_name (character)
- - metric_kind (public.metric_kind)
- - scalar_int (integer)
- - scalar_float (real)
- - timestamps (timestamp)
- - timeseries_int (integer[])
- - timeseries_float (real[])
- Indexes:
- - INDEX job_stats_id (btree) ON (job_id)
---------------------
-TABLE: kafka_trigger
- - path (character)
- - kafka_resource_path (character)
- - topics (character)
- - group_id (character)
- - script_path (character)
- - is_flow (boolean)
- - workspace_id (character)
- - edited_by (character)
- - email (character)
- - edited_at (timestamp)
- - extra_perms (jsonb)
- - server_id (character)
- - last_server_ping (timestamp)
- - error (text)
- - enabled (boolean)
---------------------
-TABLE: log_file
- - hostname (character)
- - log_ts (timestamp)
- - ok_lines (bigint)
- - err_lines (bigint)
- - mode (public.log_mode)
- - worker_group (character)
- - file_path (character)
- - json_fmt (boolean)
- Indexes:
- - INDEX log_file_log_ts_idx (btree) ON (log_ts)
---------------------
-TABLE: magic_link
- - email (character)
- - token (character)
- - expiration (timestamp)
- Indexes:
- - INDEX index_magic_link_exp (btree) ON (expiration)
---------------------
-TABLE: metrics
- - id (character)
- - value (jsonb)
- - created_at (timestamp)
- Indexes:
- - INDEX idx_metrics_id_created_at (btree) ON (id, created_at DESC) WHERE ((id)::text ~~ 'queue_%'::text)
- - INDEX metrics_key_idx (btree) ON (id)
- - INDEX metrics_sort_idx (btree) ON (created_at DESC)
---------------------
-TABLE: mqtt_trigger
- - mqtt_resource_path (character)
- - subscribe_topics (jsonb[])
- - client_version (public.mqtt_client_version)
- - v5_config (jsonb)
- - v3_config (jsonb)
- - client_id (character)
- - path (character)
- - script_path (character)
- - is_flow (boolean)
- - workspace_id (character)
- - edited_by (character)
- - email (character)
- - edited_at (timestamp)
- - extra_perms (jsonb)
- - server_id (character)
- - last_server_ping (timestamp)
- - error (text)
- - enabled (boolean)
---------------------
-TABLE: nats_trigger
- - path (character)
- - nats_resource_path (character)
- - subjects (character)
- - stream_name (character)
- - consumer_name (character)
- - use_jetstream (boolean)
- - script_path (character)
- - is_flow (boolean)
- - workspace_id (character)
- - edited_by (character)
- - email (character)
- - edited_at (timestamp)
- - extra_perms (jsonb)
- - server_id (character)
- - last_server_ping (timestamp)
- - error (text)
- - enabled (boolean)
---------------------
-TABLE: outstanding_wait_time
- - job_id (uuid)
- - self_wait_time_ms (bigint)
- - aggregate_wait_time_ms (bigint)
---------------------
-TABLE: parallel_monitor_lock
- - parent_flow_id (uuid)
- - job_id (uuid)
- - last_ping (timestamp)
---------------------
-TABLE: password
- - email (character)
- - password_hash (character)
- - login_type (character)
- - super_admin (boolean)
- - verified (boolean)
- - name (character)
- - company (character)
- - first_time_user (boolean)
- - username (character)
- - devops (boolean)
---------------------
-TABLE: pending_user
- - email (character)
- - created_at (timestamp)
- - username (character)
---------------------
-TABLE: pip_resolution_cache
- - hash (character)
- - expiration (timestamp)
- - lockfile (text)
---------------------
-TABLE: postgres_trigger
- - path (character)
- - script_path (character)
- - is_flow (boolean)
- - workspace_id (character)
- - edited_by (character)
- - email (character)
- - edited_at (timestamp)
- - extra_perms (jsonb)
- - postgres_resource_path (character)
- - error (text)
- - server_id (character)
- - last_server_ping (timestamp)
- - replication_slot_name (character)
- - publication_name (character)
- - enabled (boolean)
---------------------
-TABLE: raw_app
- - path (character)
- - version (integer)
- - workspace_id (character)
- - summary (character)
- - edited_at (timestamp)
- - data (text)
- - extra_perms (jsonb)
---------------------
-TABLE: resource
- - workspace_id (character)
- - path (character)
- - value (jsonb)
- - description (text)
- - resource_type (character)
- - extra_perms (jsonb)
- - edited_at (timestamp)
- - created_by (character)
- - CONSTRAINT (proper_id)
- Indexes:
- - INDEX resource_extra_perms (gin) ON (extra_perms)
---------------------
-TABLE: resource_type
- - workspace_id (character)
- - name (character)
- - schema (jsonb)
- - description (text)
- - edited_at (timestamp)
- - created_by (character)
- - format_extension (character)
- - CONSTRAINT (proper_name)
---------------------
-TABLE: resume_job
- - id (uuid)
- - job (uuid)
- - flow (uuid)
- - created_at (timestamp)
- - value (jsonb)
- - approver (character)
- - resume_id (integer)
- - approved (boolean)
---------------------
-TABLE: schedule
- - workspace_id (character)
- - path (character)
- - edited_by (character)
- - edited_at (timestamp)
- - schedule (character)
- - enabled (boolean)
- - script_path (character)
- - args (jsonb)
- - extra_perms (jsonb)
- - is_flow (boolean)
- - email (character)
- - error (text)
- - timezone (character)
- - on_failure (character)
- - on_recovery (character)
- - on_failure_times (integer)
- - on_failure_exact (boolean)
- - on_failure_extra_args (jsonb)
- - on_recovery_times (integer)
- - on_recovery_extra_args (jsonb)
- - ws_error_handler_muted (boolean)
- - retry (jsonb)
- - summary (character)
- - no_flow_overlap (boolean)
- - tag (character)
- - paused_until (timestamp)
- - on_success (character)
- - on_success_extra_args (jsonb)
- - cron_version (text)
- - description (text)
- - CONSTRAINT (proper_id)
- Indexes:
- - INDEX schedule_extra_perms (gin) ON (extra_perms)
---------------------
-TABLE: script
- - workspace_id (character)
- - hash (bigint)
- - path (character)
- - parent_hashes (bigint[])
- - summary (text)
- - description (text)
- - content (text)
- - created_by (character)
- - created_at (timestamp)
- - archived (boolean)
- - schema (json)
- - deleted (boolean)
- - is_template (boolean)
- - extra_perms (jsonb)
- - lock (text)
- - lock_error_logs (text)
- - language (public.script_lang)
- - kind (public.script_kind)
- - tag (character)
- - draft_only (boolean)
- - envs (character)
- - concurrent_limit (integer)
- - concurrency_time_window_s (integer)
- - cache_ttl (integer)
- - dedicated_worker (boolean)
- - ws_error_handler_muted (boolean)
- - priority (smallint)
- - timeout (integer)
- - delete_after_use (boolean)
- - restart_unless_cancelled (boolean)
- - concurrency_key (character)
- - visible_to_runner_only (boolean)
- - no_main_func (boolean)
- - codebase (character)
- - has_preprocessor (boolean)
- - on_behalf_of_email (text)
- - schema_validation (boolean)
- - CONSTRAINT (proper_id)
- Indexes:
- - INDEX index_script_on_path_created_at (btree) ON (workspace_id, path, created_at DESC)
- - INDEX script_extra_perms (gin) ON (extra_perms)
---------------------
-TABLE: sqs_trigger
- - path (character)
- - queue_url (character)
- - aws_resource_path (character)
- - message_attributes (text[])
- - script_path (character)
- - is_flow (boolean)
- - workspace_id (character)
- - edited_by (character)
- - email (character)
- - edited_at (timestamp)
- - extra_perms (jsonb)
- - error (text)
- - server_id (character)
- - last_server_ping (timestamp)
- - enabled (boolean)
- - aws_auth_resource_type (public.aws_auth_resource_type)
---------------------
-TABLE: token
- - token (character)
- - label (character)
- - expiration (timestamp)
- - workspace_id (character)
- - owner (character)
- - email (character)
- - super_admin (boolean)
- - created_at (timestamp)
- - last_used_at (timestamp)
- - scopes (text[])
- - job (uuid)
- Indexes:
- - INDEX index_token_exp (btree) ON (expiration)
---------------------
-TABLE: tutorial_progress
- - email (character)
- - progress (bit(64))
---------------------
-TABLE: usage
- - id (character)
- - is_workspace (boolean)
- - month_ (integer)
- - usage (integer)
---------------------
-TABLE: usr
- - workspace_id (character)
- - username (character)
- - email (character)
- - is_admin (boolean)
- - created_at (timestamp)
- - operator (boolean)
- - disabled (boolean)
- - role (character)
- - CONSTRAINT (proper_email)
- - CONSTRAINT (proper_username)
- Indexes:
- - INDEX index_usr_email (btree) ON (email)
---------------------
-TABLE: usr_to_group
- - workspace_id (character)
- - group_ (character)
- - usr (character)
---------------------
-TABLE: v2_job
- - id (uuid)
- - raw_code (text)
- - raw_lock (text)
- - raw_flow (jsonb)
- - tag (character)
- - workspace_id (character)
- - created_at (timestamp)
- - created_by (character)
- - permissioned_as (character)
- - permissioned_as_email (character)
- - kind (public.job_kind)
- - runnable_id (bigint)
- - runnable_path (character)
- - parent_job (uuid)
- - root_job (uuid)
- - script_lang (public.script_lang)
- - script_entrypoint_override (character)
- - flow_step (integer)
- - flow_step_id (character)
- - flow_innermost_root_job (uuid)
- - trigger (character)
- - trigger_kind (public.job_trigger_kind)
- - same_worker (boolean)
- - visible_to_owner (boolean)
- - concurrent_limit (integer)
- - concurrency_time_window_s (integer)
- - cache_ttl (integer)
- - timeout (integer)
- - priority (smallint)
- - preprocessed (boolean)
- - args (jsonb)
- - labels (text[])
- - pre_run_error (text)
- Indexes:
- - INDEX ix_job_created_at (btree) ON (created_at DESC)
- - INDEX ix_job_root_job_index_by_path_2 (btree) ON (workspace_id, runnable_path, created_at DESC) WHERE (parent_job IS NULL)
- - INDEX ix_job_workspace_id_created_at_new_3 (btree) ON (workspace_id, created_at DESC)
- - INDEX ix_job_workspace_id_created_at_new_5 (btree) ON (workspace_id, created_at DESC) WHERE ((kind = ANY (ARRAY['preview'::public.job_kind, 'flowpreview'::public.job_kind])) AND (parent_job IS NULL))
- - INDEX ix_job_workspace_id_created_at_new_8 (btree) ON (workspace_id, created_at DESC) WHERE ((kind = 'deploymentcallback'::public.job_kind) AND (parent_job IS NULL))
- - INDEX ix_job_workspace_id_created_at_new_9 (btree) ON (workspace_id, created_at DESC) WHERE ((kind = ANY (ARRAY['dependencies'::public.job_kind, 'flowdependencies'::public.job_kind, 'appdependencies'::public.job_kind])) AND (parent_job IS NULL))
- - INDEX ix_v2_job_labels (gin) ON (labels) WHERE (labels IS NOT NULL)
- - INDEX ix_v2_job_workspace_id_created_at (btree) ON (workspace_id, created_at DESC) WHERE ((kind = ANY (ARRAY['script'::public.job_kind, 'flow'::public.job_kind, 'singlescriptflow'::public.job_kind])) AND (parent_job IS NULL))
---------------------
-TABLE: v2_job_completed
- - id (uuid)
- - workspace_id (character)
- - duration_ms (bigint)
- - result (jsonb)
- - deleted (boolean)
- - canceled_by (character)
- - canceled_reason (text)
- - flow_status (jsonb)
- - started_at (timestamp)
- - memory_peak (integer)
- - status (public.job_status)
- - completed_at (timestamp)
- - worker (character)
- - workflow_as_code_status (jsonb)
- - result_columns (text[])
- - retries (uuid[])
- - extras (jsonb)
- Indexes:
- - INDEX ix_completed_job_workspace_id_started_at_new_2 (btree) ON (workspace_id, started_at DESC)
- - INDEX ix_job_completed_completed_at (btree) ON (completed_at DESC)
- - INDEX labeled_jobs_on_jobs (gin) ON (((result -> 'wm_labels'::text))) WHERE (result ? 'wm_labels'::text)
---------------------
-TABLE: v2_job_queue
- - id (uuid)
- - workspace_id (character)
- - created_at (timestamp)
- - started_at (timestamp)
- - scheduled_for (timestamp)
- - running (boolean)
- - canceled_by (character)
- - canceled_reason (text)
- - suspend (integer)
- - suspend_until (timestamp)
- - tag (character)
- - priority (smallint)
- - worker (character)
- - extras (jsonb)
- Indexes:
- - INDEX queue_sort_v2 (btree) ON (priority DESC NULLS LAST, scheduled_for, tag) WHERE (running = false)
- - INDEX queue_suspended (btree) ON (priority DESC NULLS LAST, created_at, suspend_until, suspend, tag) WHERE (suspend_until IS NOT NULL)
- - INDEX root_queue_index_by_path (btree) ON (workspace_id, created_at)
- - INDEX v2_job_queue_suspend (btree) ON (workspace_id, suspend) WHERE (suspend > 0)
---------------------
-TABLE: v2_job_runtime
- - id (uuid)
- - ping (timestamp)
- - memory_peak (integer)
---------------------
-TABLE: v2_job_status
- - id (uuid)
- - flow_status (jsonb)
- - flow_leaf_jobs (jsonb)
- - workflow_as_code_status (jsonb)
---------------------
-TABLE: variable
- - workspace_id (character)
- - path (character)
- - value (character)
- - is_secret (boolean)
- - description (character)
- - extra_perms (jsonb)
- - account (integer)
- - is_oauth (boolean)
- - expires_at (timestamp)
- - CONSTRAINT (proper_id)
- Indexes:
- - INDEX variable_extra_perms (gin) ON (extra_perms)
---------------------
-TABLE: websocket_trigger
- - path (character)
- - url (character)
- - script_path (character)
- - is_flow (boolean)
- - workspace_id (character)
- - edited_by (character)
- - email (character)
- - edited_at (timestamp)
- - extra_perms (jsonb)
- - server_id (character)
- - last_server_ping (timestamp)
- - error (text)
- - enabled (boolean)
- - filters (jsonb[])
- - initial_messages (jsonb[])
- - url_runnable_args (jsonb)
- - can_return_message (boolean)
---------------------
-TABLE: windmill_migrations
- - name (text)
- - created_at (timestamp)
---------------------
-TABLE: worker_ping
- - worker (character)
- - worker_instance (character)
- - ping_at (timestamp)
- - started_at (timestamp)
- - ip (character)
- - jobs_executed (integer)
- - custom_tags (text[])
- - worker_group (character)
- - dedicated_worker (character)
- - dedicated_workers (text[])
- - wm_version (character)
- - current_job_id (uuid)
- - current_job_workspace_id (character)
- - vcpus (bigint)
- - memory (bigint)
- - occupancy_rate (real)
- - memory_usage (bigint)
- - wm_memory_usage (bigint)
- - occupancy_rate_15s (real)
- - occupancy_rate_5m (real)
- - occupancy_rate_30m (real)
- Indexes:
- - INDEX worker_ping_on_ping_at (btree) ON (ping_at)
---------------------
-TABLE: workspace
- - id (character)
- - name (character)
- - owner (character)
- - deleted (boolean)
- - premium (boolean)
- - CONSTRAINT (proper_id)
---------------------
-TABLE: workspace_env
- - workspace_id (character)
- - name (character)
- - value (character)
---------------------
-TABLE: workspace_invite
- - workspace_id (character)
- - email (character)
- - is_admin (boolean)
- - operator (boolean)
- - CONSTRAINT (proper_email)
---------------------
-TABLE: workspace_key
- - workspace_id (character)
- - kind (public.workspace_key_kind)
- - key (character)
---------------------
-TABLE: workspace_runnable_dependencies
- - flow_path (character)
- - runnable_path (character)
- - script_hash (bigint)
- - runnable_is_flow (boolean)
- - workspace_id (character)
- - app_path (character)
- - CONSTRAINT (workspace_runnable_dependencies_path_exclusive)
- Indexes:
- - UNIQUE INDEX app_workspace_with_hash_unique_idx (btree) ON (app_path, runnable_path, script_hash, runnable_is_flow, workspace_id) WHERE (script_hash IS NOT NULL)
- - UNIQUE INDEX app_workspace_without_hash_unique_idx (btree) ON (app_path, runnable_path, runnable_is_flow, workspace_id) WHERE (script_hash IS NULL)
- - INDEX flow_workspace_runnable_path_is_flow_idx (btree) ON (runnable_path, runnable_is_flow, workspace_id)
- - UNIQUE INDEX flow_workspace_with_hash_unique_idx (btree) ON (flow_path, runnable_path, script_hash, runnable_is_flow, workspace_id) WHERE (script_hash IS NOT NULL)
- - UNIQUE INDEX flow_workspace_without_hash_unique_idx (btree) ON (flow_path, runnable_path, runnable_is_flow, workspace_id) WHERE (script_hash IS NULL)
---------------------
-TABLE: workspace_settings
- - workspace_id (character)
- - slack_team_id (character)
- - slack_name (character)
- - slack_command_script (character)
- - slack_email (character)
- - auto_invite_domain (character)
- - auto_invite_operator (boolean)
- - customer_id (character)
- - plan (character)
- - webhook (text)
- - deploy_to (character)
- - error_handler (character)
- - ai_config (jsonb)
- - error_handler_extra_args (json)
- - error_handler_muted_on_cancel (boolean)
- - success_handler (text)
- - success_handler_extra_args (json)
- - large_file_storage (jsonb)
- - git_sync (jsonb)
- - default_app (character)
- - auto_add (boolean)
- - default_scripts (jsonb)
- - deploy_ui (jsonb)
- - mute_critical_alerts (boolean)
- - color (character)
- - operator_settings (jsonb)
- - teams_command_script (text)
- - teams_team_id (text)
- - teams_team_name (text)
- - git_app_installations (jsonb)
---------------------
-TABLE: zombie_job_counter
- - job_id (uuid)
- - counter (integer)
---------------------
+## Tables
+_sqlx_migrations: version(bigint), description(text), installed_on(ts), success(bool), checksum(bytes), execution_time(bigint)
+account: workspace_id(char), id(int), expires_at(ts), refresh_token(char), client(char), refresh_error(text), grant_type(char), cc_client_id(char), cc_client_secret(char), cc_token_url(char), mcp_server_url(text)
+ FK: (workspace_id) -> workspace(id)
+agent_token_blacklist: token(char), expires_at(ts), blacklisted_at(ts), blacklisted_by(char)
+ai_agent_memory: workspace_id(char), conversation_id(uuid), step_id(char), messages(jsonb), created_at(ts), updated_at(ts)
+alerts: id(int), alert_type(char), message(text), created_at(ts), acknowledged(bool), workspace_id(text), acknowledged_workspace(bool), resource(text)
+app: id(bigint), workspace_id(char), path(char), summary(char), policy(jsonb), versions(bigint[]), extra_perms(jsonb), draft_only(bool), custom_path(text)
+ FK: (workspace_id) -> workspace(id)
+app_bundles: app_version_id(bigint), w_id(char), file_type(char), data(bytes)
+app_script: id(bigint), app(bigint), hash(char(64)), lock(text), code(text), code_sha256(char(64))
+ FK: (app) -> app(id)
+app_version: id(bigint), app_id(bigint), value(json), created_by(char), created_at(ts), raw_app(bool)
+ FK: (app_id) -> app(id)
+app_version_lite: id(bigint), value(jsonb)
+ FK: (id) -> app_version(id)
+asset: workspace_id(char), path(char), kind(asset_kind), usage_access_type(asset_access_type), usage_path(char), usage_kind(asset_usage_kind), created_at(ts), id(bigint), columns(jsonb)
+ FK: (workspace_id) -> workspace(id)
+audit: workspace_id(char), id(bigint), timestamp(ts), username(char), operation(char), action_kind(action_kind), resource(char), parameters(jsonb), email(char), span(char)
+autoscaling_event: id(int), worker_group(text), event_type(autoscaling_event_type), desired_workers(int), applied_at(ts), reason(text)
+capture: workspace_id(char), path(char), created_at(ts), created_by(char), main_args(jsonb), is_flow(bool), trigger_kind(trigger_kind), preprocessor_args(jsonb), id(bigint)
+ FK: (workspace_id) -> workspace(id)
+capture_config: workspace_id(char), path(char), is_flow(bool), trigger_kind(trigger_kind), trigger_config(jsonb), owner(char), email(char), server_id(char), last_client_ping(ts), last_server_ping(ts), error(text)
+ FK: (workspace_id) -> workspace(id)
+cloud_workspace_settings: workspace_id(char), threshold_alert_amount(int), last_alert_sent(ts), last_warning_sent(ts), is_past_due(bool), max_tolerated_executions(int)
+ FK: (workspace_id) -> workspace(id)
+concurrency_counter: concurrency_id(char), job_uuids(jsonb)
+concurrency_key: key(char), ended_at(ts), job_id(uuid)
+concurrency_locks: id(char), last_locked_at(ts), owner(char)
+concurrency_settings: hash(bigint), concurrency_key(char), concurrent_limit(int), concurrency_time_window_s(int)
+config: name(char), config(jsonb)
+custom_concurrency_key_ended: key(char), ended_at(ts)
+debounce_key: key(char), job_id(uuid), previous_job_id(uuid), first_started_at(ts), debounced_times(int)
+debounce_stale_data: job_id(uuid), to_relock(text[])
+debouncing_settings: hash(bigint), debounce_key(char), debounce_delay_s(int), max_total_debouncing_time(int), max_total_debounces_amount(int), debounce_args_to_accumulate(text[])
+dependency_map: workspace_id(char), importer_path(char), importer_kind(importer_kind), imported_path(char), importer_node_id(char)
+deployment_metadata: workspace_id(char), path(char), script_hash(bigint), app_version(bigint), callback_job_ids(uuid[]), deployment_msg(text), flow_version(bigint), job_id(uuid)
+ FK: (workspace_id) -> workspace(id)
+draft: workspace_id(char), path(char), typ(draft_type), value(json), created_at(ts)
+ FK: (workspace_id) -> workspace(id)
+email_to_igroup: email(char), igroup(char)
+email_trigger: path(char), local_part(char), workspaced_local_part(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
+favorite: usr(char), workspace_id(char), path(char), favorite_kind(favorite_kind)
+flow: workspace_id(char), path(char), summary(text), description(text), value(jsonb), edited_by(char), edited_at(ts), archived(bool), schema(json), extra_perms(jsonb), dependency_job(uuid), draft_only(bool), tag(char), ws_error_handler_muted(bool), dedicated_worker(bool), timeout(int), visible_to_runner_only(bool), concurrency_key(char), versions(bigint[]), on_behalf_of_email(text), lock_error_logs(text)
+ FK: (workspace_id) -> workspace(id)
+flow_conversation: id(uuid), workspace_id(char), flow_path(char), title(char), created_at(ts), updated_at(ts), created_by(char)
+ FK: (workspace_id) -> workspace(id)
+flow_conversation_message: id(uuid), conversation_id(uuid), message_type(message_type), content(text), job_id(uuid), created_at(ts), step_name(char), success(bool)
+ FK: (conversation_id) -> flow_conversation(id) | (job_id) -> v2_job(id)
+flow_iterator_data: job_id(uuid), itered(jsonb)
+flow_node: id(bigint), workspace_id(char), hash(bigint), path(char), lock(text), code(text), flow(jsonb), hash_v2(char(64))
+ FK: (path, workspace_id) -> flow(path, workspace_id) | (workspace_id) -> workspace(id)
+flow_version: id(bigint), workspace_id(char), path(char), value(jsonb), schema(json), created_by(char), created_at(ts)
+ FK: (workspace_id, path) -> flow(workspace_id, path)
+flow_version_lite: id(bigint), value(jsonb)
+ FK: (id) -> flow_version(id)
+folder: name(char), workspace_id(char), display_name(char), owners(char), extra_perms(jsonb), summary(text), edited_at(ts), created_by(char)
+ FK: (workspace_id) -> workspace(id)
+folder_permission_history: id(bigint), workspace_id(char), folder_name(char), changed_by(char), changed_at(ts), change_type(char), affected(char)
+ FK: (workspace_id, folder_name) -> folder(workspace_id, name)
+gcp_trigger: gcp_resource_path(char), topic_id(char), subscription_id(char), delivery_type(delivery_mode), delivery_config(jsonb), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), subscription_mode(gcp_subscription_mode), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), auto_acknowledge_msg(bool), ack_deadline(int), mode(trigger_mode)
+global_settings: name(char), value(jsonb), updated_at(ts)
+group_: workspace_id(char), name(char), summary(text), extra_perms(jsonb)
+ FK: (workspace_id) -> workspace(id)
+group_permission_history: id(bigint), workspace_id(char), group_name(char), changed_by(char), changed_at(ts), change_type(char), member_affected(char)
+ FK: (workspace_id, group_name) -> group_(workspace_id, name)
+healthchecks: id(bigint), check_type(char), healthy(bool), created_at(ts)
+http_trigger: path(char), route_path(char), route_path_key(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), authentication_method(authentication_method), http_method(http_method), static_asset_config(jsonb), is_static_website(bool), workspaced_route(bool), wrap_body(bool), raw_string(bool), authentication_resource_path(char), summary(char), description(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), request_type(request_type), mode(trigger_mode)
+input: id(uuid), workspace_id(char), runnable_id(char), runnable_type(runnable_type), name(text), args(jsonb), created_at(ts), created_by(char), is_public(bool)
+ FK: (workspace_id) -> workspace(id)
+instance_group: name(char), summary(char), id(char), scim_display_name(char), external_id(char)
+job_logs: job_id(uuid), workspace_id(char), created_at(ts), logs(text), log_offset(int), log_file_index(text[])
+job_perms: job_id(uuid), email(char), username(char), is_admin(bool), is_operator(bool), created_at(ts), workspace_id(char), groups(text[]), folders(jsonb[]), end_user_email(char)
+job_result_stream: job_id(uuid), workspace_id(text), stream(text)
+job_result_stream_v2: job_id(uuid), workspace_id(text), stream(text), idx(int)
+job_settings: job_id(uuid), runnable_settings(bigint)
+job_stats: workspace_id(char), job_id(uuid), metric_id(char), metric_name(char), metric_kind(metric_kind), scalar_int(int), scalar_float(float), timestamps(ts), timeseries_int(int[]), timeseries_float(float[])
+ FK: (workspace_id) -> workspace(id)
+kafka_trigger: path(char), kafka_resource_path(char), topics(char), group_id(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), filters(jsonb[])
+log_file: hostname(char), log_ts(ts), ok_lines(bigint), err_lines(bigint), mode(log_mode), worker_group(char), file_path(char), json_fmt(bool)
+magic_link: email(char), token(char), expiration(ts)
+mcp_oauth_client: mcp_server_url(text), client_id(text), client_secret(text), client_secret_expires_at(ts), token_endpoint(text), created_at(ts)
+mcp_oauth_refresh_token: id(bigint), refresh_token(char), access_token(char), client_id(char), user_email(char), workspace_id(char), scopes(text[]), token_family(uuid), created_at(ts), expires_at(ts), used_at(ts), revoked(bool)
+ FK: (client_id) -> mcp_oauth_server_client(client_id)
+mcp_oauth_server_client: client_id(char), client_name(char), redirect_uris(text[]), created_at(ts)
+mcp_oauth_server_code: code(char), client_id(char), user_email(char), workspace_id(char), scopes(text[]), redirect_uri(text), code_challenge(char), code_challenge_method(char), created_at(ts), expires_at(ts)
+ FK: (client_id) -> mcp_oauth_server_client(client_id)
+metrics: id(char), value(jsonb), created_at(ts)
+mqtt_trigger: mqtt_resource_path(char), subscribe_topics(jsonb[]), client_version(mqtt_client_version), v5_config(jsonb), v3_config(jsonb), client_id(char), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
+native_trigger: external_id(char), workspace_id(char), service_name(native_trigger_service), script_path(char), is_flow(bool), webhook_token_prefix(char), service_config(jsonb), error(text), created_at(ts), updated_at(ts)
+ FK: (workspace_id) -> workspace(id)
+nats_trigger: path(char), nats_resource_path(char), subjects(char), stream_name(char), consumer_name(char), use_jetstream(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
+ FK: (workspace_id) -> workspace(id)
+notify_event: id(bigint), channel(text), payload(text), created_at(ts)
+otel_traces: trace_id(bytes), span_id(bytes), trace_state(text), parent_span_id(bytes), flags(int), name(text), kind(int), start_time_unix_nano(bigint), end_time_unix_nano(bigint), attributes(jsonb), dropped_attributes_count(int), events(jsonb), dropped_events_count(int), links(jsonb), dropped_links_count(int), status(jsonb)
+outstanding_wait_time: job_id(uuid), self_wait_time_ms(bigint), aggregate_wait_time_ms(bigint)
+parallel_monitor_lock: parent_flow_id(uuid), job_id(uuid), last_ping(ts)
+password: email(char), password_hash(char), login_type(char), super_admin(bool), verified(bool), name(char), company(char), first_time_user(bool), username(char), devops(bool)
+pending_user: email(char), created_at(ts), username(char)
+pip_resolution_cache: hash(char), expiration(ts), lockfile(text)
+postgres_trigger: path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), postgres_resource_path(char), error(text), server_id(char), last_server_ping(ts), replication_slot_name(char), publication_name(char), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
+ FK: (workspace_id) -> workspace(id)
+raw_app: path(char), version(int), workspace_id(char), summary(char), edited_at(ts), data(text), extra_perms(jsonb)
+ FK: (workspace_id) -> workspace(id)
+resource: workspace_id(char), path(char), value(jsonb), description(text), resource_type(char), extra_perms(jsonb), edited_at(ts), created_by(char)
+ FK: (workspace_id) -> workspace(id)
+resource_type: workspace_id(char), name(char), schema(jsonb), description(text), edited_at(ts), created_by(char), format_extension(char)
+ FK: (workspace_id) -> workspace(id)
+resume_job: id(uuid), job(uuid), flow(uuid), created_at(ts), value(jsonb), approver(char), resume_id(int), approved(bool)
+ FK: (flow) -> v2_job_queue(id)
+runnable_settings: hash(bigint), debouncing_settings(bigint), concurrency_settings(bigint)
+schedule: workspace_id(char), path(char), edited_by(char), edited_at(ts), schedule(char), enabled(bool), script_path(char), args(jsonb), extra_perms(jsonb), is_flow(bool), email(char), error(text), timezone(char), on_failure(char), on_recovery(char), on_failure_times(int), on_failure_exact(bool), on_failure_extra_args(jsonb), on_recovery_times(int), on_recovery_extra_args(jsonb), ws_error_handler_muted(bool), retry(jsonb), summary(char), no_flow_overlap(bool), tag(char), paused_until(ts), on_success(char), on_success_extra_args(jsonb), cron_version(text), description(text), dynamic_skip(char)
+ FK: (workspace_id) -> workspace(id)
+script: workspace_id(char), hash(bigint), path(char), parent_hashes(bigint[]), summary(text), description(text), content(text), created_by(char), created_at(ts), archived(bool), schema(json), deleted(bool), is_template(bool), extra_perms(jsonb), lock(text), lock_error_logs(text), language(script_lang), kind(script_kind), tag(char), draft_only(bool), envs(char), concurrent_limit(int), concurrency_time_window_s(int), cache_ttl(int), dedicated_worker(bool), ws_error_handler_muted(bool), priority(smallint), timeout(int), delete_after_use(bool), restart_unless_cancelled(bool), concurrency_key(char), visible_to_runner_only(bool), no_main_func(bool), codebase(char), has_preprocessor(bool), on_behalf_of_email(text), schema_validation(bool), assets(jsonb), debounce_key(char), debounce_delay_s(int), cache_ignore_s3_path(bool), runnable_settings_handle(bigint)
+ FK: (workspace_id) -> workspace(id)
+skip_workspace_diff_tally: workspace_id(char), added_at(ts)
+sqs_trigger: path(char), queue_url(char), aws_resource_path(char), message_attributes(text[]), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error(text), server_id(char), last_server_ping(ts), aws_auth_resource_type(aws_auth_resource_type), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
+ FK: (workspace_id) -> workspace(id)
+token: token(char), label(char), expiration(ts), workspace_id(char), owner(char), email(char), super_admin(bool), created_at(ts), last_used_at(ts), scopes(text[]), job(uuid)
+ FK: (workspace_id) -> workspace(id)
+tutorial_progress: email(char), progress(bit64), skipped_all(bool)
+unique_ext_jwt_token: jwt_hash(bigint), last_used_at(ts)
+usage: id(char), is_workspace(bool), month_(int), usage(int)
+usr: workspace_id(char), username(char), email(char), is_admin(bool), created_at(ts), operator(bool), disabled(bool), role(char), added_via(jsonb)
+ FK: (workspace_id) -> workspace(id)
+usr_to_group: workspace_id(char), group_(char), usr(char)
+ FK: (workspace_id, group_) -> group_(workspace_id, name) | (workspace_id) -> workspace(id)
+v2_job: id(uuid), raw_code(text), raw_lock(text), raw_flow(jsonb), tag(char), workspace_id(char), created_at(ts), created_by(char), permissioned_as(char), permissioned_as_email(char), kind(job_kind), runnable_id(bigint), runnable_path(char), parent_job(uuid), root_job(uuid), script_lang(script_lang), script_entrypoint_override(char), flow_step(int), flow_step_id(char), flow_innermost_root_job(uuid), trigger(char), trigger_kind(job_trigger_kind), same_worker(bool), visible_to_owner(bool), concurrent_limit(int), concurrency_time_window_s(int), cache_ttl(int), timeout(int), priority(smallint), preprocessed(bool), args(jsonb), labels(text[]), pre_run_error(text)
+v2_job_completed: id(uuid), workspace_id(char), duration_ms(bigint), result(jsonb), deleted(bool), canceled_by(char), canceled_reason(text), flow_status(jsonb), started_at(ts), memory_peak(int), status(job_status), completed_at(ts), worker(char), workflow_as_code_status(jsonb), result_columns(text[]), retries(uuid[]), extras(jsonb)
+v2_job_debounce_batch: id(uuid), debounce_batch(bigint)
+v2_job_queue: id(uuid), workspace_id(char), created_at(ts), started_at(ts), scheduled_for(ts), running(bool), canceled_by(char), canceled_reason(text), suspend(int), suspend_until(ts), tag(char), priority(smallint), worker(char), extras(jsonb), cache_ignore_s3_path(bool), runnable_settings_handle(bigint)
+v2_job_runtime: id(uuid), ping(ts), memory_peak(int)
+ FK: (id) -> v2_job_queue(id)
+v2_job_status: id(uuid), flow_status(jsonb), flow_leaf_jobs(jsonb), workflow_as_code_status(jsonb)
+ FK: (id) -> v2_job_queue(id)
+variable: workspace_id(char), path(char), value(char), is_secret(bool), description(char), extra_perms(jsonb), account(int), is_oauth(bool), expires_at(ts)
+ FK: (workspace_id) -> workspace(id)
+websocket_trigger: path(char), url(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), filters(jsonb[]), initial_messages(jsonb[]), url_runnable_args(jsonb), can_return_message(bool), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), can_return_error_result(bool), mode(trigger_mode)
+windmill_migrations: name(text), created_at(ts)
+worker_group_job_stats: hour(bigint), worker_group(text), script_lang(char), workspace_id(char), job_count(int), total_duration_ms(bigint)
+ FK: (workspace_id) -> workspace(id)
+worker_ping: worker(char), worker_instance(char), ping_at(ts), started_at(ts), ip(char), jobs_executed(int), custom_tags(text[]), worker_group(char), dedicated_worker(char), wm_version(char), current_job_id(uuid), current_job_workspace_id(char), vcpus(bigint), memory(bigint), occupancy_rate(float), memory_usage(bigint), wm_memory_usage(bigint), occupancy_rate_15s(float), occupancy_rate_5m(float), occupancy_rate_30m(float), job_isolation(text), dedicated_workers(text[])
+workspace: id(char), name(char), owner(char), deleted(bool), premium(bool), parent_workspace_id(char)
+ FK: (parent_workspace_id) -> workspace(id)
+workspace_dependencies: id(bigint), name(char), content(text), language(script_lang), description(text), archived(bool), workspace_id(char), created_at(ts)
+workspace_diff: source_workspace_id(char), fork_workspace_id(char), path(char), kind(char), ahead(int), behind(int), has_changes(bool), exists_in_source(bool), exists_in_fork(bool)
+workspace_env: workspace_id(char), name(char), value(char)
+workspace_integrations: workspace_id(char), service_name(native_trigger_service), oauth_data(jsonb), created_at(ts), updated_at(ts), created_by(char)
+ FK: (workspace_id) -> workspace(id)
+workspace_invite: workspace_id(char), email(char), is_admin(bool), operator(bool)
+ FK: (workspace_id) -> workspace(id)
+workspace_key: workspace_id(char), kind(workspace_key_kind), key(char)
+ FK: (workspace_id) -> workspace(id)
+workspace_protection_rule: workspace_id(char), name(char), rules(int), bypass_groups(text[]), bypass_users(text[]), created_at(ts)
+ FK: (workspace_id) -> workspace(id)
+workspace_runnable_dependencies: flow_path(char), runnable_path(char), script_hash(bigint), runnable_is_flow(bool), workspace_id(char), app_path(char)
+ FK: (app_path, workspace_id) -> app(path, workspace_id) | (flow_path, workspace_id) -> flow(path, workspace_id)
+workspace_settings: workspace_id(char), slack_team_id(char), slack_name(char), slack_command_script(char), slack_email(char), customer_id(char), plan(char), webhook(text), deploy_to(char), ai_config(jsonb), large_file_storage(jsonb), git_sync(jsonb), default_app(char), default_scripts(jsonb), deploy_ui(jsonb), mute_critical_alerts(bool), color(char), operator_settings(jsonb), teams_command_script(text), teams_team_id(text), teams_team_name(text), git_app_installations(jsonb), ducklake(jsonb), slack_oauth_client_id(char), slack_oauth_client_secret(char), datatable(jsonb), teams_team_guid(text), auto_invite(jsonb), error_handler(jsonb), success_handler(jsonb), public_app_execution_limit_per_minute(int)
+ FK: (workspace_id) -> workspace(id)
+zombie_job_counter: job_id(uuid), counter(int)
+ FK: (job_id) -> v2_job(id)
diff --git a/backend/tests/agent_workers.rs b/backend/tests/agent_workers.rs
index 26c4003212..b6414dc24e 100644
--- a/backend/tests/agent_workers.rs
+++ b/backend/tests/agent_workers.rs
@@ -1,8 +1,6 @@
#![cfg(all(feature = "private", feature = "agent_worker_server"))]
-mod common;
-
-use common::*;
+use windmill_test_utils::*;
use serde_json::json;
use sqlx::{Pool, Postgres};
use windmill_common::{
diff --git a/backend/tests/bun_jobs.rs b/backend/tests/bun_jobs.rs
index cf3ce4d350..534d530095 100644
--- a/backend/tests/bun_jobs.rs
+++ b/backend/tests/bun_jobs.rs
@@ -1,5 +1,4 @@
-mod common;
-use crate::common::*;
+use windmill_test_utils::*;
use sqlx::postgres::Postgres;
use sqlx::Pool;
use windmill_common::jobs::{JobPayload, RawCode};
@@ -860,7 +859,7 @@ export function main() {
// ============================================================================
mod dedicated_worker_protocol {
- use crate::common::{parse_dedicated_worker_line, DedicatedWorkerResult};
+ use windmill_test_utils::{parse_dedicated_worker_line, DedicatedWorkerResult};
use std::io::{BufRead, BufReader, Write};
use std::process::{Command, Stdio};
use windmill_worker::{
diff --git a/backend/tests/dependency_map.rs b/backend/tests/dependency_map.rs
index d217b710d6..bb9510c688 100644
--- a/backend/tests/dependency_map.rs
+++ b/backend/tests/dependency_map.rs
@@ -2,8 +2,9 @@ use sqlx::{Pool, Postgres};
use tokio_stream::StreamExt;
use windmill_api_client::types::NewScript;
-mod common;
-use common::{in_test_worker, init_client, listen_for_completed_jobs, ApiServer};
+use windmill_test_utils::{
+ in_test_worker, init_client, listen_for_completed_jobs, rebuild_dmap, ApiServer,
+};
mod dependency_map {
use super::*;
@@ -170,7 +171,7 @@ mod dependency_map {
let (client, _port, _s) = init(db.clone()).await;
assert_dmap(&db, None, CORRECT_DMAP.clone()).await;
// rebuild map
- assert!(common::rebuild_dmap(&client).await);
+ assert!(rebuild_dmap(&client).await);
assert_dmap(&db, None, CORRECT_DMAP.clone()).await;
Ok(())
}
@@ -183,7 +184,7 @@ mod dependency_map {
// Spawn first rebuild
let handle = {
let client = client.clone();
- tokio::spawn(async move { common::rebuild_dmap(&client).await })
+ tokio::spawn(async move { rebuild_dmap(&client).await })
};
// Immidiately spawn another
diff --git a/backend/tests/error_handler.rs b/backend/tests/error_handler.rs
index cad9336ab7..b117cbfba3 100644
--- a/backend/tests/error_handler.rs
+++ b/backend/tests/error_handler.rs
@@ -1,7 +1,6 @@
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
/// Test that workspace error handler can be set and removed via database operations
#[cfg(feature = "deno_core")]
diff --git a/backend/tests/flow_engine_parity.rs b/backend/tests/flow_engine_parity.rs
index 875897094e..58b76dc50d 100644
--- a/backend/tests/flow_engine_parity.rs
+++ b/backend/tests/flow_engine_parity.rs
@@ -25,8 +25,7 @@ use windmill_common::{
scripts::ScriptLang,
};
-mod common;
-use common::*;
+use windmill_test_utils::*;
/// Helper to create a FlowModule with default fields
fn flow_module(id: &str, value: FlowModuleValue) -> FlowModule {
diff --git a/backend/tests/instance_config.rs b/backend/tests/instance_config.rs
new file mode 100644
index 0000000000..4c85906563
--- /dev/null
+++ b/backend/tests/instance_config.rs
@@ -0,0 +1,994 @@
+/*!
+ * Integration tests for windmill-common instance_config module.
+ *
+ * Tests verify the DB-level operations:
+ * - `InstanceConfig::from_db()` reads global_settings + worker configs
+ * - `apply_settings_diff()` applies upserts and deletes to global_settings
+ * - `apply_configs_diff()` applies upserts and deletes to config table
+ * - Full roundtrip: write → read → modify → diff → apply → read → verify
+ *
+ * Note: the test DB is created from migrations which seed default settings
+ * and worker configs. Tests either clean up first or assert on specific keys
+ * rather than exact counts.
+ */
+
+use std::collections::BTreeMap;
+
+use sqlx::{Pool, Postgres};
+use windmill_common::instance_config::{
+ apply_configs_diff, apply_settings_diff, diff_global_settings, diff_worker_configs, ApplyMode,
+ ConfigsDiff, InstanceConfig, SettingsDiff,
+};
+
+// ========================================================================
+// Helpers
+// ========================================================================
+
+async fn get_global_setting(db: &Pool, name: &str) -> Option {
+ sqlx::query_as::<_, (serde_json::Value,)>("SELECT value FROM global_settings WHERE name = $1")
+ .bind(name)
+ .fetch_optional(db)
+ .await
+ .expect("query should succeed")
+ .map(|(v,)| v)
+}
+
+async fn get_config(db: &Pool, name: &str) -> Option {
+ sqlx::query_as::<_, (serde_json::Value,)>("SELECT config FROM config WHERE name = $1")
+ .bind(name)
+ .fetch_optional(db)
+ .await
+ .expect("query should succeed")
+ .map(|(v,)| v)
+}
+
+async fn insert_global_setting(db: &Pool, name: &str, value: serde_json::Value) {
+ sqlx::query(
+ "INSERT INTO global_settings (name, value) VALUES ($1, $2) \
+ ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value",
+ )
+ .bind(name)
+ .bind(&value)
+ .execute(db)
+ .await
+ .expect("insert should succeed");
+}
+
+async fn insert_config(db: &Pool, name: &str, config: serde_json::Value) {
+ sqlx::query(
+ "INSERT INTO config (name, config) VALUES ($1, $2) \
+ ON CONFLICT (name) DO UPDATE SET config = EXCLUDED.config",
+ )
+ .bind(name)
+ .bind(&config)
+ .execute(db)
+ .await
+ .expect("insert should succeed");
+}
+
+async fn count_global_settings(db: &Pool) -> i64 {
+ sqlx::query_as::<_, (i64,)>("SELECT COUNT(*) FROM global_settings")
+ .fetch_one(db)
+ .await
+ .expect("count query should succeed")
+ .0
+}
+
+/// Clear all migration-seeded data so tests start from a clean slate.
+async fn clear_settings_and_configs(db: &Pool) {
+ sqlx::query("DELETE FROM global_settings")
+ .execute(db)
+ .await
+ .expect("clear global_settings should succeed");
+ sqlx::query("DELETE FROM config WHERE name LIKE 'worker__%'")
+ .execute(db)
+ .await
+ .expect("clear worker configs should succeed");
+}
+
+// ========================================================================
+// InstanceConfig::from_db() tests
+// ========================================================================
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_empty(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ let config = InstanceConfig::from_db(&db)
+ .await
+ .expect("from_db should succeed on empty DB");
+ assert!(config.global_settings.base_url.is_none());
+ assert!(config.global_settings.license_key.is_none());
+ assert!(config.worker_configs.is_empty());
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_with_typed_global_settings(db: Pool) {
+ insert_global_setting(&db, "base_url", serde_json::json!("https://windmill.test")).await;
+ insert_global_setting(&db, "retention_period_secs", serde_json::json!(86400)).await;
+ insert_global_setting(&db, "expose_metrics", serde_json::json!(true)).await;
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ assert_eq!(
+ config.global_settings.base_url.as_deref(),
+ Some("https://windmill.test")
+ );
+ assert_eq!(config.global_settings.retention_period_secs, Some(86400));
+ assert_eq!(config.global_settings.expose_metrics, Some(true));
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_with_structured_settings(db: Pool) {
+ insert_global_setting(
+ &db,
+ "smtp_settings",
+ serde_json::json!({
+ "smtp_host": "mail.test.com",
+ "smtp_port": 587,
+ "smtp_tls_implicit": false
+ }),
+ )
+ .await;
+ insert_global_setting(
+ &db,
+ "otel",
+ serde_json::json!({
+ "metrics_enabled": true,
+ "logs_enabled": false,
+ "otel_exporter_otlp_endpoint": "http://otel:4317"
+ }),
+ )
+ .await;
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+
+ let smtp = config.global_settings.smtp_settings.as_ref().unwrap();
+ assert_eq!(smtp.smtp_host.as_deref(), Some("mail.test.com"));
+ assert_eq!(smtp.smtp_port, Some(587));
+ assert_eq!(smtp.smtp_tls_implicit, Some(false));
+
+ let otel = config.global_settings.otel.as_ref().unwrap();
+ assert_eq!(otel.metrics_enabled, Some(true));
+ assert_eq!(otel.logs_enabled, Some(false));
+ assert_eq!(
+ otel.otel_exporter_otlp_endpoint.as_deref(),
+ Some("http://otel:4317")
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_unknown_settings_go_to_extra(db: Pool) {
+ insert_global_setting(&db, "future_setting_xyz", serde_json::json!({"nested": 42})).await;
+ insert_global_setting(&db, "another_unknown", serde_json::json!("hello")).await;
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ assert_eq!(
+ config.global_settings.extra["future_setting_xyz"],
+ serde_json::json!({"nested": 42})
+ );
+ assert_eq!(
+ config.global_settings.extra["another_unknown"],
+ serde_json::json!("hello")
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_with_worker_configs(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ insert_config(
+ &db,
+ "worker__default",
+ serde_json::json!({"init_bash": "echo default"}),
+ )
+ .await;
+ insert_config(
+ &db,
+ "worker__gpu",
+ serde_json::json!({
+ "dedicated_worker": "ws:f/gpu_script",
+ "worker_tags": ["gpu", "cuda"]
+ }),
+ )
+ .await;
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ assert_eq!(config.worker_configs.len(), 2);
+ assert_eq!(
+ config.worker_configs["default"].init_bash.as_deref(),
+ Some("echo default")
+ );
+ assert_eq!(
+ config.worker_configs["gpu"].dedicated_worker.as_deref(),
+ Some("ws:f/gpu_script")
+ );
+ assert_eq!(
+ config.worker_configs["gpu"].worker_tags.as_ref().unwrap(),
+ &["gpu", "cuda"]
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_ignores_non_worker_configs(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ // Insert a config without worker__ prefix — should not appear
+ insert_config(&db, "server_config", serde_json::json!({"important": true})).await;
+ insert_config(
+ &db,
+ "worker__actual",
+ serde_json::json!({"init_bash": "echo hi"}),
+ )
+ .await;
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ assert_eq!(config.worker_configs.len(), 1);
+ assert!(config.worker_configs.contains_key("actual"));
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_worker_config_prefix_stripping(db: Pool) {
+ insert_config(
+ &db,
+ "worker__my_group_name",
+ serde_json::json!({"cache_clear": 5}),
+ )
+ .await;
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ assert!(
+ config.worker_configs.contains_key("my_group_name"),
+ "worker__ prefix should be stripped"
+ );
+ assert_eq!(config.worker_configs["my_group_name"].cache_clear, Some(5));
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_worker_config_unknown_fields_in_extra(db: Pool) {
+ insert_config(
+ &db,
+ "worker__test_extra",
+ serde_json::json!({
+ "init_bash": "echo hello",
+ "future_field": 999,
+ "another_future": {"nested": true}
+ }),
+ )
+ .await;
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ let wc = &config.worker_configs["test_extra"];
+ assert_eq!(wc.init_bash.as_deref(), Some("echo hello"));
+ assert_eq!(wc.extra["future_field"], serde_json::json!(999));
+ assert_eq!(
+ wc.extra["another_future"],
+ serde_json::json!({"nested": true})
+ );
+}
+
+// ========================================================================
+// apply_settings_diff() tests
+// ========================================================================
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_settings_diff_upserts_only(db: Pool) {
+ let diff = SettingsDiff {
+ upserts: {
+ let mut m = BTreeMap::new();
+ m.insert("key_a".to_string(), serde_json::json!("val_a"));
+ m.insert("key_b".to_string(), serde_json::json!(123));
+ m
+ },
+ deletes: vec![],
+ };
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ assert_eq!(
+ get_global_setting(&db, "key_a").await,
+ Some(serde_json::json!("val_a"))
+ );
+ assert_eq!(
+ get_global_setting(&db, "key_b").await,
+ Some(serde_json::json!(123))
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_settings_diff_deletes_only(db: Pool) {
+ insert_global_setting(&db, "to_delete_1", serde_json::json!("bye")).await;
+ insert_global_setting(&db, "to_delete_2", serde_json::json!("gone")).await;
+ insert_global_setting(&db, "to_keep", serde_json::json!("stay")).await;
+
+ let diff = SettingsDiff {
+ upserts: BTreeMap::new(),
+ deletes: vec!["to_delete_1".to_string(), "to_delete_2".to_string()],
+ };
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ assert!(get_global_setting(&db, "to_delete_1").await.is_none());
+ assert!(get_global_setting(&db, "to_delete_2").await.is_none());
+ assert!(get_global_setting(&db, "to_keep").await.is_some());
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_settings_diff_upserts_and_deletes(db: Pool) {
+ insert_global_setting(&db, "old_key", serde_json::json!("old")).await;
+
+ let diff = SettingsDiff {
+ upserts: {
+ let mut m = BTreeMap::new();
+ m.insert("new_key".to_string(), serde_json::json!("new"));
+ m
+ },
+ deletes: vec!["old_key".to_string()],
+ };
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ assert!(get_global_setting(&db, "old_key").await.is_none());
+ assert_eq!(
+ get_global_setting(&db, "new_key").await,
+ Some(serde_json::json!("new"))
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_settings_diff_empty_noop(db: Pool) {
+ insert_global_setting(&db, "preexisting", serde_json::json!("value")).await;
+
+ let diff = SettingsDiff::default();
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ assert_eq!(
+ get_global_setting(&db, "preexisting").await,
+ Some(serde_json::json!("value"))
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_settings_diff_upsert_overwrites(db: Pool) {
+ insert_global_setting(&db, "overwrite_me", serde_json::json!("old_value")).await;
+
+ let diff = SettingsDiff {
+ upserts: {
+ let mut m = BTreeMap::new();
+ m.insert("overwrite_me".to_string(), serde_json::json!("new_value"));
+ m
+ },
+ deletes: vec![],
+ };
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ assert_eq!(
+ get_global_setting(&db, "overwrite_me").await,
+ Some(serde_json::json!("new_value"))
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_settings_diff_complex_json(db: Pool) {
+ let complex_value = serde_json::json!({
+ "host": "smtp.example.com",
+ "port": 587,
+ "auth": {"user": "admin", "pass": "secret"},
+ "tags": [1, 2, 3],
+ "nested": {"deep": {"value": null}}
+ });
+
+ let diff = SettingsDiff {
+ upserts: {
+ let mut m = BTreeMap::new();
+ m.insert("complex_setting".to_string(), complex_value.clone());
+ m
+ },
+ deletes: vec![],
+ };
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ let stored = get_global_setting(&db, "complex_setting").await.unwrap();
+ assert_eq!(stored, complex_value);
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_settings_diff_delete_nonexistent_is_noop(db: Pool) {
+ let diff =
+ SettingsDiff { upserts: BTreeMap::new(), deletes: vec!["does_not_exist".to_string()] };
+
+ // Should not error
+ apply_settings_diff(&db, &diff).await.unwrap();
+}
+
+// ========================================================================
+// apply_configs_diff() tests
+// ========================================================================
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_configs_diff_upserts_with_prefix(db: Pool) {
+ let diff = ConfigsDiff {
+ upserts: {
+ let mut m = BTreeMap::new();
+ m.insert(
+ "mygroup".to_string(),
+ serde_json::json!({"init_bash": "echo hi"}),
+ );
+ m
+ },
+ deletes: vec![],
+ };
+
+ apply_configs_diff(&db, &diff).await.unwrap();
+
+ let stored = get_config(&db, "worker__mygroup").await.unwrap();
+ assert_eq!(stored["init_bash"], "echo hi");
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_configs_diff_deletes_with_prefix(db: Pool) {
+ insert_config(&db, "worker__to_remove", serde_json::json!({"a": 1})).await;
+
+ let diff = ConfigsDiff { upserts: BTreeMap::new(), deletes: vec!["to_remove".to_string()] };
+
+ apply_configs_diff(&db, &diff).await.unwrap();
+
+ assert!(get_config(&db, "worker__to_remove").await.is_none());
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_configs_diff_upsert_overwrites(db: Pool) {
+ insert_config(&db, "worker__grp", serde_json::json!({"old": true})).await;
+
+ let diff = ConfigsDiff {
+ upserts: {
+ let mut m = BTreeMap::new();
+ m.insert("grp".to_string(), serde_json::json!({"new": true}));
+ m
+ },
+ deletes: vec![],
+ };
+
+ apply_configs_diff(&db, &diff).await.unwrap();
+
+ let stored = get_config(&db, "worker__grp").await.unwrap();
+ assert_eq!(stored, serde_json::json!({"new": true}));
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_configs_diff_empty_noop(db: Pool) {
+ insert_config(&db, "worker__keep", serde_json::json!({"keep": true})).await;
+
+ let diff = ConfigsDiff::default();
+ apply_configs_diff(&db, &diff).await.unwrap();
+
+ assert!(get_config(&db, "worker__keep").await.is_some());
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_apply_configs_diff_does_not_touch_non_worker_configs(db: Pool) {
+ insert_config(&db, "server_config", serde_json::json!({"x": 1})).await;
+
+ let diff = ConfigsDiff { upserts: BTreeMap::new(), deletes: vec!["server_config".to_string()] };
+
+ apply_configs_diff(&db, &diff).await.unwrap();
+
+ // The delete targets "worker__server_config", not "server_config"
+ assert!(
+ get_config(&db, "server_config").await.is_some(),
+ "Non-worker config should not be affected"
+ );
+}
+
+// ========================================================================
+// Full roundtrip tests
+// ========================================================================
+
+#[sqlx::test(fixtures("base"))]
+async fn test_roundtrip_write_read_modify_apply(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ // Step 1: Seed initial state
+ insert_global_setting(&db, "base_url", serde_json::json!("https://v1.test")).await;
+ insert_global_setting(&db, "retention_period_secs", serde_json::json!(3600)).await;
+ insert_config(
+ &db,
+ "worker__default",
+ serde_json::json!({"init_bash": "echo v1"}),
+ )
+ .await;
+
+ // Step 2: Read via from_db
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ assert_eq!(
+ config.global_settings.base_url.as_deref(),
+ Some("https://v1.test")
+ );
+ assert_eq!(config.global_settings.retention_period_secs, Some(3600));
+ assert_eq!(config.worker_configs.len(), 1);
+
+ // Step 3: Modify — change base_url, add a new setting, remove retention
+ let mut desired_settings = config.global_settings.clone();
+ desired_settings.base_url = Some("https://v2.test".to_string());
+ desired_settings.expose_metrics = Some(true);
+ desired_settings.retention_period_secs = None;
+
+ let current_map = config.global_settings.to_settings_map();
+ let desired_map = desired_settings.to_settings_map();
+
+ // Step 4: Diff + apply (Merge mode — no deletes)
+ let diff = diff_global_settings(¤t_map, &desired_map, ApplyMode::Merge);
+ assert!(diff.upserts.contains_key("base_url"));
+ assert!(diff.upserts.contains_key("expose_metrics"));
+ assert!(diff.deletes.is_empty());
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ // Step 5: Read back and verify
+ let config2 = InstanceConfig::from_db(&db).await.unwrap();
+ assert_eq!(
+ config2.global_settings.base_url.as_deref(),
+ Some("https://v2.test")
+ );
+ assert_eq!(config2.global_settings.expose_metrics, Some(true));
+ // retention_period_secs still in DB because Merge mode doesn't delete
+ assert_eq!(config2.global_settings.retention_period_secs, Some(3600));
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_roundtrip_replace_mode_deletes(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ // Seed
+ insert_global_setting(&db, "base_url", serde_json::json!("https://old.test")).await;
+ insert_global_setting(&db, "retention_period_secs", serde_json::json!(7200)).await;
+ insert_global_setting(&db, "expose_metrics", serde_json::json!(false)).await;
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ let current_map = config.global_settings.to_settings_map();
+
+ // Desired: only base_url — retention and expose_metrics should be deleted
+ let mut desired_map = BTreeMap::new();
+ desired_map.insert(
+ "base_url".to_string(),
+ serde_json::json!("https://old.test"),
+ );
+
+ let diff = diff_global_settings(¤t_map, &desired_map, ApplyMode::Replace);
+ assert!(diff.upserts.is_empty());
+ assert!(diff.deletes.contains(&"retention_period_secs".to_string()));
+ assert!(diff.deletes.contains(&"expose_metrics".to_string()));
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ assert!(get_global_setting(&db, "retention_period_secs")
+ .await
+ .is_none());
+ assert!(get_global_setting(&db, "expose_metrics").await.is_none());
+ assert!(get_global_setting(&db, "base_url").await.is_some());
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_roundtrip_worker_configs(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ // Seed two worker configs
+ insert_config(
+ &db,
+ "worker__default",
+ serde_json::json!({"init_bash": "echo default"}),
+ )
+ .await;
+ insert_config(
+ &db,
+ "worker__legacy",
+ serde_json::json!({"init_bash": "echo legacy"}),
+ )
+ .await;
+
+ // Read
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ assert_eq!(config.worker_configs.len(), 2);
+
+ // Desired: replace default, add gpu, remove legacy
+ let current_map: BTreeMap = config
+ .worker_configs
+ .iter()
+ .map(|(k, v)| (k.clone(), serde_json::to_value(v).unwrap()))
+ .collect();
+
+ let mut desired_map = BTreeMap::new();
+ desired_map.insert(
+ "default".to_string(),
+ serde_json::json!({"init_bash": "echo default v2"}),
+ );
+ desired_map.insert(
+ "gpu".to_string(),
+ serde_json::json!({"dedicated_worker": "ws:f/gpu"}),
+ );
+
+ let diff = diff_worker_configs(¤t_map, &desired_map, ApplyMode::Replace);
+ assert!(diff.upserts.contains_key("default")); // changed
+ assert!(diff.upserts.contains_key("gpu")); // new
+ assert_eq!(diff.deletes, vec!["legacy".to_string()]);
+
+ apply_configs_diff(&db, &diff).await.unwrap();
+
+ // Verify
+ let config2 = InstanceConfig::from_db(&db).await.unwrap();
+ assert_eq!(config2.worker_configs.len(), 2);
+ assert_eq!(
+ config2.worker_configs["default"].init_bash.as_deref(),
+ Some("echo default v2")
+ );
+ assert_eq!(
+ config2.worker_configs["gpu"].dedicated_worker.as_deref(),
+ Some("ws:f/gpu")
+ );
+ assert!(!config2.worker_configs.contains_key("legacy"));
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_roundtrip_to_settings_map_from_db_consistency(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ // Write a GlobalSettings via to_settings_map + apply, then read back via from_db
+ let original = windmill_common::instance_config::GlobalSettings {
+ base_url: Some("https://roundtrip.test".to_string()),
+ retention_period_secs: Some(43200),
+ expose_metrics: Some(true),
+ smtp_settings: Some(windmill_common::instance_config::SmtpSettings {
+ smtp_host: Some("smtp.roundtrip.test".to_string()),
+ smtp_port: Some(465),
+ ..Default::default()
+ }),
+ custom_tags: Some(vec!["tag1".to_string(), "tag2".to_string()]),
+ ..Default::default()
+ };
+
+ let map = original.to_settings_map();
+ let diff = SettingsDiff { upserts: map.into_iter().collect(), deletes: vec![] };
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ assert_eq!(config.global_settings.base_url, original.base_url);
+ assert_eq!(
+ config.global_settings.retention_period_secs,
+ original.retention_period_secs
+ );
+ assert_eq!(
+ config.global_settings.expose_metrics,
+ original.expose_metrics
+ );
+ assert_eq!(
+ config
+ .global_settings
+ .smtp_settings
+ .as_ref()
+ .unwrap()
+ .smtp_host,
+ original.smtp_settings.as_ref().unwrap().smtp_host
+ );
+ assert_eq!(
+ config
+ .global_settings
+ .smtp_settings
+ .as_ref()
+ .unwrap()
+ .smtp_port,
+ original.smtp_settings.as_ref().unwrap().smtp_port
+ );
+ assert_eq!(config.global_settings.custom_tags, original.custom_tags);
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_idempotent_apply(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ let diff = SettingsDiff {
+ upserts: {
+ let mut m = BTreeMap::new();
+ m.insert("idem_key".to_string(), serde_json::json!("idem_value"));
+ m
+ },
+ deletes: vec![],
+ };
+
+ // Apply twice
+ apply_settings_diff(&db, &diff).await.unwrap();
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ assert_eq!(
+ get_global_setting(&db, "idem_key").await,
+ Some(serde_json::json!("idem_value"))
+ );
+ assert_eq!(count_global_settings(&db).await, 1);
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_mixed_typed_and_extra(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ // Insert both typed and untyped settings
+ insert_global_setting(&db, "base_url", serde_json::json!("https://mixed.test")).await;
+ insert_global_setting(&db, "expose_metrics", serde_json::json!(true)).await;
+ insert_global_setting(
+ &db,
+ "unknown_future_setting",
+ serde_json::json!({"key": "val"}),
+ )
+ .await;
+ insert_global_setting(&db, "another_custom", serde_json::json!([1, 2, 3])).await;
+
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+
+ // Typed fields
+ assert_eq!(
+ config.global_settings.base_url.as_deref(),
+ Some("https://mixed.test")
+ );
+ assert_eq!(config.global_settings.expose_metrics, Some(true));
+
+ // Extra fields
+ assert_eq!(
+ config.global_settings.extra["unknown_future_setting"],
+ serde_json::json!({"key": "val"})
+ );
+ assert_eq!(
+ config.global_settings.extra["another_custom"],
+ serde_json::json!([1, 2, 3])
+ );
+
+ // Roundtrip: to_settings_map should include everything
+ let map = config.global_settings.to_settings_map();
+ assert!(map.contains_key("base_url"));
+ assert!(map.contains_key("expose_metrics"));
+ assert!(map.contains_key("unknown_future_setting"));
+ assert!(map.contains_key("another_custom"));
+ assert_eq!(map.len(), 4);
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_full_config_roundtrip(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ // Seed a realistic configuration
+ insert_global_setting(
+ &db,
+ "base_url",
+ serde_json::json!("https://prod.windmill.dev"),
+ )
+ .await;
+ insert_global_setting(&db, "license_key", serde_json::json!("prod-license-key")).await;
+ insert_global_setting(&db, "retention_period_secs", serde_json::json!(2592000)).await;
+ insert_global_setting(
+ &db,
+ "smtp_settings",
+ serde_json::json!({
+ "smtp_host": "smtp.prod.com",
+ "smtp_port": 587,
+ "smtp_from": "noreply@prod.com",
+ "smtp_tls_implicit": true
+ }),
+ )
+ .await;
+ insert_global_setting(
+ &db,
+ "critical_error_channels",
+ serde_json::json!([
+ {"email": "admin@prod.com"},
+ {"slack_channel": "#prod-alerts"}
+ ]),
+ )
+ .await;
+ insert_global_setting(
+ &db,
+ "otel",
+ serde_json::json!({
+ "metrics_enabled": true,
+ "tracing_enabled": true,
+ "otel_exporter_otlp_endpoint": "http://otel-collector:4317"
+ }),
+ )
+ .await;
+
+ insert_config(
+ &db,
+ "worker__default",
+ serde_json::json!({
+ "init_bash": "apt-get update",
+ "worker_tags": ["default", "deno", "bun"],
+ "cache_clear": 7
+ }),
+ )
+ .await;
+ insert_config(
+ &db,
+ "worker__gpu",
+ serde_json::json!({
+ "dedicated_worker": "ws:f/gpu_inference",
+ "autoscaling": {
+ "enabled": true,
+ "min_workers": 0,
+ "max_workers": 4,
+ "integration": {"type": "kubernetes"}
+ }
+ }),
+ )
+ .await;
+
+ // Read full config
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+
+ assert_eq!(
+ config.global_settings.base_url.as_deref(),
+ Some("https://prod.windmill.dev")
+ );
+ assert_eq!(
+ config
+ .global_settings
+ .license_key
+ .as_ref()
+ .and_then(|v| v.as_literal()),
+ Some("prod-license-key")
+ );
+ assert_eq!(config.global_settings.retention_period_secs, Some(2592000));
+
+ let smtp = config.global_settings.smtp_settings.as_ref().unwrap();
+ assert_eq!(smtp.smtp_host.as_deref(), Some("smtp.prod.com"));
+ assert_eq!(smtp.smtp_from.as_deref(), Some("noreply@prod.com"));
+
+ let channels = config
+ .global_settings
+ .critical_error_channels
+ .as_ref()
+ .unwrap();
+ assert_eq!(channels.len(), 2);
+
+ let otel = config.global_settings.otel.as_ref().unwrap();
+ assert_eq!(otel.metrics_enabled, Some(true));
+ assert_eq!(otel.tracing_enabled, Some(true));
+
+ assert_eq!(config.worker_configs.len(), 2);
+ assert_eq!(config.worker_configs["default"].cache_clear, Some(7));
+ let gpu_auto = config.worker_configs["gpu"].autoscaling.as_ref().unwrap();
+ assert!(gpu_auto.enabled);
+ assert_eq!(gpu_auto.min_workers, Some(0));
+ assert_eq!(gpu_auto.max_workers, Some(4));
+
+ // Verify settings count matches
+ let settings_map = config.global_settings.to_settings_map();
+ let db_count = count_global_settings(&db).await;
+ assert_eq!(
+ settings_map.len() as i64,
+ db_count,
+ "to_settings_map should produce same count as DB rows"
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_diff_apply_only_touches_changed_rows(db: Pool) {
+ clear_settings_and_configs(&db).await;
+
+ // Seed 3 settings
+ insert_global_setting(&db, "unchanged_1", serde_json::json!("val1")).await;
+ insert_global_setting(&db, "unchanged_2", serde_json::json!("val2")).await;
+ insert_global_setting(&db, "to_change", serde_json::json!("old")).await;
+
+ let mut current = BTreeMap::new();
+ current.insert("unchanged_1".to_string(), serde_json::json!("val1"));
+ current.insert("unchanged_2".to_string(), serde_json::json!("val2"));
+ current.insert("to_change".to_string(), serde_json::json!("old"));
+
+ let mut desired = current.clone();
+ desired.insert("to_change".to_string(), serde_json::json!("new"));
+ desired.insert("added".to_string(), serde_json::json!("fresh"));
+
+ let diff = diff_global_settings(¤t, &desired, ApplyMode::Merge);
+
+ // Only "to_change" and "added" should be in upserts
+ assert_eq!(diff.upserts.len(), 2);
+ assert!(diff.upserts.contains_key("to_change"));
+ assert!(diff.upserts.contains_key("added"));
+ assert!(!diff.upserts.contains_key("unchanged_1"));
+ assert!(!diff.upserts.contains_key("unchanged_2"));
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ // Verify all 4 settings present
+ assert_eq!(count_global_settings(&db).await, 4);
+ assert_eq!(
+ get_global_setting(&db, "to_change").await,
+ Some(serde_json::json!("new"))
+ );
+ assert_eq!(
+ get_global_setting(&db, "added").await,
+ Some(serde_json::json!("fresh"))
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_from_db_reads_migration_defaults(db: Pool) {
+ // Verify that from_db correctly reads the migration-seeded state
+ // without clearing — tests that pre-existing data is properly deserialized
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+
+ // Migrations seed at least base_url, license_key, etc.
+ // Just verify from_db doesn't error and returns a populated struct
+ let map = config.global_settings.to_settings_map();
+ assert!(
+ !map.is_empty(),
+ "Migration-seeded DB should produce non-empty settings"
+ );
+ assert!(
+ !config.worker_configs.is_empty(),
+ "Migration-seeded DB should have worker configs"
+ );
+}
+
+#[sqlx::test(fixtures("base"))]
+async fn test_replace_mode_protects_settings_in_integration(db: Pool) {
+ // Seed a protected setting
+ insert_global_setting(
+ &db,
+ "ducklake_settings",
+ serde_json::json!({"ducklakes": {}}),
+ )
+ .await;
+ insert_global_setting(&db, "ducklake_user_pg_pwd", serde_json::json!("secret_pwd")).await;
+ insert_global_setting(
+ &db,
+ "custom_instance_pg_databases",
+ serde_json::json!({"databases": {}}),
+ )
+ .await;
+ insert_global_setting(&db, "normal_setting", serde_json::json!("will_be_deleted")).await;
+
+ // Read current state
+ let config = InstanceConfig::from_db(&db).await.unwrap();
+ let current_map = config.global_settings.to_settings_map();
+
+ // Desired: only keep_me — everything else should be deleted except protected
+ let mut desired_map = BTreeMap::new();
+ desired_map.insert("keep_me".to_string(), serde_json::json!("yes"));
+
+ let diff = diff_global_settings(¤t_map, &desired_map, ApplyMode::Replace);
+
+ // Protected keys should NOT be in deletes
+ assert!(
+ !diff.deletes.contains(&"ducklake_settings".to_string()),
+ "ducklake_settings is protected"
+ );
+ assert!(
+ !diff.deletes.contains(&"ducklake_user_pg_pwd".to_string()),
+ "ducklake_user_pg_pwd is protected"
+ );
+ assert!(
+ !diff
+ .deletes
+ .contains(&"custom_instance_pg_databases".to_string()),
+ "custom_instance_pg_databases is protected"
+ );
+ // But normal_setting should be deleted
+ assert!(diff.deletes.contains(&"normal_setting".to_string()));
+
+ apply_settings_diff(&db, &diff).await.unwrap();
+
+ // Verify protected settings survived
+ assert!(get_global_setting(&db, "ducklake_settings").await.is_some());
+ assert!(get_global_setting(&db, "ducklake_user_pg_pwd")
+ .await
+ .is_some());
+ assert!(get_global_setting(&db, "custom_instance_pg_databases")
+ .await
+ .is_some());
+ // Normal setting is gone
+ assert!(get_global_setting(&db, "normal_setting").await.is_none());
+ // New setting is present
+ assert_eq!(
+ get_global_setting(&db, "keep_me").await,
+ Some(serde_json::json!("yes"))
+ );
+}
diff --git a/backend/tests/job_payload.rs b/backend/tests/job_payload.rs
index 2321db5bcf..87253807be 100644
--- a/backend/tests/job_payload.rs
+++ b/backend/tests/job_payload.rs
@@ -1,5 +1,3 @@
-mod common;
-
mod job_payload {
use serde_json::json;
use sqlx::{Pool, Postgres};
@@ -8,7 +6,7 @@ mod job_payload {
use windmill_common::scripts::{ScriptHash, ScriptLang};
use windmill_common::flow_status::RestartedFrom;
- use crate::common::*;
+ use windmill_test_utils::*;
use windmill_common::min_version::{
MIN_VERSION, MIN_VERSION_IS_AT_LEAST_1_427, MIN_VERSION_IS_AT_LEAST_1_432,
MIN_VERSION_IS_AT_LEAST_1_440,
diff --git a/backend/tests/list_jobs.rs b/backend/tests/list_jobs.rs
index a3d87385f9..65451bcbb7 100644
--- a/backend/tests/list_jobs.rs
+++ b/backend/tests/list_jobs.rs
@@ -7,8 +7,7 @@ use windmill_common::{
scripts::ScriptLang,
};
-mod common;
-use common::*;
+use windmill_test_utils::*;
#[derive(Debug, Deserialize)]
struct ListJobsResponse {
diff --git a/backend/tests/nativets_jobs.rs b/backend/tests/nativets_jobs.rs
index c654882589..eaf3a96652 100644
--- a/backend/tests/nativets_jobs.rs
+++ b/backend/tests/nativets_jobs.rs
@@ -14,10 +14,7 @@
*/
#[cfg(feature = "deno_core")]
-mod common;
-
-#[cfg(feature = "deno_core")]
-use common::*;
+use windmill_test_utils::*;
#[cfg(feature = "deno_core")]
use futures::StreamExt;
diff --git a/backend/tests/nativets_stress.rs b/backend/tests/nativets_stress.rs
index cf3710d86c..9717403830 100644
--- a/backend/tests/nativets_stress.rs
+++ b/backend/tests/nativets_stress.rs
@@ -11,10 +11,7 @@
*/
#[cfg(feature = "deno_core")]
-mod common;
-
-#[cfg(feature = "deno_core")]
-use common::*;
+use windmill_test_utils::*;
#[cfg(feature = "deno_core")]
use std::time::Instant;
diff --git a/backend/tests/operator_db_sync.rs b/backend/tests/operator_db_sync.rs
new file mode 100644
index 0000000000..fb7a9e1e39
--- /dev/null
+++ b/backend/tests/operator_db_sync.rs
@@ -0,0 +1,448 @@
+/*!
+ * Integration tests for windmill-operator db_sync module.
+ *
+ * Tests verify full declarative sync of global_settings and worker configs:
+ * - Upsert desired settings into DB
+ * - Delete settings present in DB but absent from desired state
+ * - Protect certain internal settings from deletion
+ */
+
+#[cfg(feature = "operator")]
+mod tests {
+ use std::collections::BTreeMap;
+
+ use sqlx::{Pool, Postgres};
+
+ // ========================================================================
+ // Helpers
+ // ========================================================================
+
+ async fn get_global_setting(db: &Pool, name: &str) -> Option {
+ sqlx::query_as::<_, (serde_json::Value,)>(
+ "SELECT value FROM global_settings WHERE name = $1",
+ )
+ .bind(name)
+ .fetch_optional(db)
+ .await
+ .expect("query should succeed")
+ .map(|(v,)| v)
+ }
+
+ async fn get_config(db: &Pool, name: &str) -> Option {
+ sqlx::query_as::<_, (serde_json::Value,)>("SELECT config FROM config WHERE name = $1")
+ .bind(name)
+ .fetch_optional(db)
+ .await
+ .expect("query should succeed")
+ .map(|(v,)| v)
+ }
+
+ async fn insert_global_setting(db: &Pool, name: &str, value: serde_json::Value) {
+ sqlx::query(
+ "INSERT INTO global_settings (name, value) VALUES ($1, $2) \
+ ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value",
+ )
+ .bind(name)
+ .bind(&value)
+ .execute(db)
+ .await
+ .expect("insert should succeed");
+ }
+
+ async fn insert_config(db: &Pool, name: &str, config: serde_json::Value) {
+ sqlx::query(
+ "INSERT INTO config (name, config) VALUES ($1, $2) \
+ ON CONFLICT (name) DO UPDATE SET config = EXCLUDED.config",
+ )
+ .bind(name)
+ .bind(&config)
+ .execute(db)
+ .await
+ .expect("insert should succeed");
+ }
+
+ // ========================================================================
+ // sync_global_settings tests
+ // ========================================================================
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_global_settings_upserts(db: Pool) {
+ let mut desired = BTreeMap::new();
+ desired.insert(
+ "test_op_setting_a".to_string(),
+ serde_json::json!("value_a"),
+ );
+ desired.insert("test_op_setting_b".to_string(), serde_json::json!(42));
+
+ windmill_operator::db_sync::sync_global_settings(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ assert_eq!(
+ get_global_setting(&db, "test_op_setting_a").await,
+ Some(serde_json::json!("value_a"))
+ );
+ assert_eq!(
+ get_global_setting(&db, "test_op_setting_b").await,
+ Some(serde_json::json!(42))
+ );
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_global_settings_updates_existing(db: Pool) {
+ // Pre-populate a setting
+ insert_global_setting(&db, "test_op_existing", serde_json::json!("old")).await;
+
+ // Sync with new value
+ let mut desired = BTreeMap::new();
+ desired.insert("test_op_existing".to_string(), serde_json::json!("new"));
+
+ windmill_operator::db_sync::sync_global_settings(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ assert_eq!(
+ get_global_setting(&db, "test_op_existing").await,
+ Some(serde_json::json!("new"))
+ );
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_global_settings_deletes_absent(db: Pool) {
+ // Pre-populate settings
+ insert_global_setting(&db, "test_op_keep", serde_json::json!("keep")).await;
+ insert_global_setting(&db, "test_op_remove", serde_json::json!("remove")).await;
+
+ // Sync with only one of them
+ let mut desired = BTreeMap::new();
+ desired.insert("test_op_keep".to_string(), serde_json::json!("keep"));
+
+ windmill_operator::db_sync::sync_global_settings(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ assert!(get_global_setting(&db, "test_op_keep").await.is_some());
+ assert!(
+ get_global_setting(&db, "test_op_remove").await.is_none(),
+ "Setting absent from desired should be deleted"
+ );
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_global_settings_protects_ducklake(db: Pool) {
+ // Pre-populate a protected setting
+ insert_global_setting(
+ &db,
+ "ducklake_settings",
+ serde_json::json!({"protected": true}),
+ )
+ .await;
+
+ // Sync with empty desired — protected key should survive
+ let desired = BTreeMap::new();
+
+ windmill_operator::db_sync::sync_global_settings(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ assert!(
+ get_global_setting(&db, "ducklake_settings").await.is_some(),
+ "Protected setting ducklake_settings should not be deleted"
+ );
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_global_settings_protects_all_protected_keys(db: Pool) {
+ let protected_keys = [
+ "ducklake_user_pg_pwd",
+ "ducklake_settings",
+ "custom_instance_pg_databases",
+ ];
+
+ for key in &protected_keys {
+ insert_global_setting(&db, key, serde_json::json!("protected_value")).await;
+ }
+
+ // Sync with empty desired
+ let desired = BTreeMap::new();
+ windmill_operator::db_sync::sync_global_settings(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ for key in &protected_keys {
+ assert!(
+ get_global_setting(&db, key).await.is_some(),
+ "Protected key {key} should not be deleted"
+ );
+ }
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_global_settings_empty_desired(db: Pool) {
+ // Pre-populate a non-protected setting
+ insert_global_setting(&db, "test_op_ephemeral", serde_json::json!("gone")).await;
+
+ let desired = BTreeMap::new();
+ windmill_operator::db_sync::sync_global_settings(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ assert!(
+ get_global_setting(&db, "test_op_ephemeral").await.is_none(),
+ "Non-protected settings should be deleted when desired is empty"
+ );
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_global_settings_complex_json_values(db: Pool) {
+ let mut desired = BTreeMap::new();
+ desired.insert(
+ "test_op_complex".to_string(),
+ serde_json::json!({
+ "host": "smtp.example.com",
+ "port": 587,
+ "tls": true,
+ "nested": {"array": [1, 2, 3]}
+ }),
+ );
+
+ windmill_operator::db_sync::sync_global_settings(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ let stored = get_global_setting(&db, "test_op_complex")
+ .await
+ .expect("Setting should exist");
+ assert_eq!(stored["host"], "smtp.example.com");
+ assert_eq!(stored["port"], 587);
+ assert_eq!(stored["nested"]["array"][1], 2);
+ }
+
+ // ========================================================================
+ // sync_worker_configs tests
+ // ========================================================================
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_worker_configs_upserts_with_prefix(db: Pool) {
+ let mut desired = BTreeMap::new();
+ desired.insert(
+ "test_group".to_string(),
+ serde_json::json!({"dedicated_worker": false}),
+ );
+
+ windmill_operator::db_sync::sync_worker_configs(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ let config = get_config(&db, "worker__test_group")
+ .await
+ .expect("Config should exist with worker__ prefix");
+ assert_eq!(config["dedicated_worker"], false);
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_worker_configs_updates_existing(db: Pool) {
+ // Pre-populate
+ insert_config(
+ &db,
+ "worker__test_wc_existing",
+ serde_json::json!({"old": true}),
+ )
+ .await;
+
+ let mut desired = BTreeMap::new();
+ desired.insert(
+ "test_wc_existing".to_string(),
+ serde_json::json!({"new": true}),
+ );
+
+ windmill_operator::db_sync::sync_worker_configs(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ let config = get_config(&db, "worker__test_wc_existing")
+ .await
+ .expect("Config should exist");
+ assert_eq!(config["new"], true);
+ assert!(config.get("old").is_none());
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_worker_configs_deletes_absent(db: Pool) {
+ // Pre-populate two worker configs
+ insert_config(
+ &db,
+ "worker__test_wc_keep",
+ serde_json::json!({"keep": true}),
+ )
+ .await;
+ insert_config(
+ &db,
+ "worker__test_wc_remove",
+ serde_json::json!({"remove": true}),
+ )
+ .await;
+
+ // Sync with only one
+ let mut desired = BTreeMap::new();
+ desired.insert(
+ "test_wc_keep".to_string(),
+ serde_json::json!({"keep": true}),
+ );
+
+ windmill_operator::db_sync::sync_worker_configs(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ assert!(get_config(&db, "worker__test_wc_keep").await.is_some());
+ assert!(
+ get_config(&db, "worker__test_wc_remove").await.is_none(),
+ "Worker config absent from desired should be deleted"
+ );
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_worker_configs_does_not_touch_non_worker_configs(db: Pool) {
+ // Insert a non-worker config (no worker__ prefix)
+ insert_config(&db, "server_config", serde_json::json!({"important": true})).await;
+
+ // Sync with empty worker configs
+ let desired = BTreeMap::new();
+ windmill_operator::db_sync::sync_worker_configs(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ assert!(
+ get_config(&db, "server_config").await.is_some(),
+ "Non-worker configs should not be touched"
+ );
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_worker_configs_multiple_groups(db: Pool) {
+ let mut desired = BTreeMap::new();
+ desired.insert(
+ "default".to_string(),
+ serde_json::json!({"init_bash": "echo default"}),
+ );
+ desired.insert(
+ "gpu".to_string(),
+ serde_json::json!({"dedicated_worker": true}),
+ );
+ desired.insert(
+ "native".to_string(),
+ serde_json::json!({"init_bash": "echo native"}),
+ );
+
+ windmill_operator::db_sync::sync_worker_configs(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ assert!(get_config(&db, "worker__default").await.is_some());
+ assert!(get_config(&db, "worker__gpu").await.is_some());
+ assert!(get_config(&db, "worker__native").await.is_some());
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_sync_worker_configs_empty_desired(db: Pool) {
+ insert_config(
+ &db,
+ "worker__test_wc_gone",
+ serde_json::json!({"ephemeral": true}),
+ )
+ .await;
+
+ let desired = BTreeMap::new();
+ windmill_operator::db_sync::sync_worker_configs(&db, &desired)
+ .await
+ .expect("sync should succeed");
+
+ assert!(
+ get_config(&db, "worker__test_wc_gone").await.is_none(),
+ "Worker config should be deleted when desired is empty"
+ );
+ }
+
+ // ========================================================================
+ // End-to-end: both syncs together
+ // ========================================================================
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_full_declarative_sync(db: Pool) {
+ // Pre-populate some existing state
+ insert_global_setting(&db, "test_op_stale_setting", serde_json::json!("stale")).await;
+ insert_config(
+ &db,
+ "worker__test_stale_group",
+ serde_json::json!({"stale": true}),
+ )
+ .await;
+
+ // Define desired state
+ let mut global_settings = BTreeMap::new();
+ global_settings.insert(
+ "test_op_base_url".to_string(),
+ serde_json::json!("https://windmill.example.com"),
+ );
+ global_settings.insert(
+ "test_op_license_key".to_string(),
+ serde_json::json!("my-license"),
+ );
+
+ let mut worker_configs = BTreeMap::new();
+ worker_configs.insert(
+ "default".to_string(),
+ serde_json::json!({"init_bash": "echo hello"}),
+ );
+
+ // Sync both
+ windmill_operator::db_sync::sync_global_settings(&db, &global_settings)
+ .await
+ .expect("global sync should succeed");
+ windmill_operator::db_sync::sync_worker_configs(&db, &worker_configs)
+ .await
+ .expect("worker sync should succeed");
+
+ // Verify desired state is present
+ assert_eq!(
+ get_global_setting(&db, "test_op_base_url").await,
+ Some(serde_json::json!("https://windmill.example.com"))
+ );
+ assert_eq!(
+ get_global_setting(&db, "test_op_license_key").await,
+ Some(serde_json::json!("my-license"))
+ );
+ assert!(get_config(&db, "worker__default").await.is_some());
+
+ // Verify stale state is removed
+ assert!(
+ get_global_setting(&db, "test_op_stale_setting")
+ .await
+ .is_none(),
+ "Stale global setting should be removed"
+ );
+ assert!(
+ get_config(&db, "worker__test_stale_group").await.is_none(),
+ "Stale worker config should be removed"
+ );
+ }
+
+ #[sqlx::test(fixtures("base"))]
+ async fn test_idempotent_sync(db: Pool) {
+ let mut desired = BTreeMap::new();
+ desired.insert("test_op_idempotent".to_string(), serde_json::json!("value"));
+
+ // Run sync twice — should be idempotent
+ windmill_operator::db_sync::sync_global_settings(&db, &desired)
+ .await
+ .expect("first sync should succeed");
+ windmill_operator::db_sync::sync_global_settings(&db, &desired)
+ .await
+ .expect("second sync should succeed");
+
+ assert_eq!(
+ get_global_setting(&db, "test_op_idempotent").await,
+ Some(serde_json::json!("value"))
+ );
+ }
+}
diff --git a/backend/tests/python_jobs.rs b/backend/tests/python_jobs.rs
index 47a554afd5..dd494de007 100644
--- a/backend/tests/python_jobs.rs
+++ b/backend/tests/python_jobs.rs
@@ -1,5 +1,4 @@
-mod common;
-use crate::common::*;
+use windmill_test_utils::*;
use sqlx::postgres::Postgres;
use sqlx::Pool;
use windmill_common::scripts::ScriptLang;
diff --git a/backend/tests/relock_skip.rs b/backend/tests/relock_skip.rs
new file mode 100644
index 0000000000..ce274796bc
--- /dev/null
+++ b/backend/tests/relock_skip.rs
@@ -0,0 +1,378 @@
+use sqlx::{Pool, Postgres};
+use tokio_stream::StreamExt;
+use windmill_api_client::types::NewScript;
+use windmill_test_utils::*;
+
+mod relock_skip {
+ use super::*;
+
+ fn quick_ns(
+ content: &str,
+ language: windmill_api_client::types::ScriptLang,
+ path: &str,
+ lock: Option,
+ parent_hash: Option,
+ ) -> NewScript {
+ NewScript {
+ content: content.into(),
+ language,
+ lock,
+ parent_hash,
+ path: path.into(),
+ concurrent_limit: None,
+ concurrency_time_window_s: None,
+ cache_ttl: None,
+ dedicated_worker: None,
+ description: "".to_string(),
+ draft_only: None,
+ envs: vec![],
+ is_template: None,
+ kind: None,
+ summary: "".to_string(),
+ tag: None,
+ schema: std::collections::HashMap::new(),
+ ws_error_handler_muted: Some(false),
+ priority: None,
+ delete_after_use: None,
+ timeout: None,
+ restart_unless_cancelled: None,
+ deployment_message: None,
+ concurrency_key: None,
+ visible_to_runner_only: None,
+ no_main_func: None,
+ codebase: None,
+ has_preprocessor: None,
+ on_behalf_of_email: None,
+ assets: vec![],
+ }
+ }
+
+ async fn init(db: Pool) -> (windmill_api_client::Client, u16, ApiServer) {
+ init_client(db).await
+ }
+
+ /// Counts occurrences of a pattern in job logs for all jobs created after a given time
+ async fn count_pattern_in_job_logs(
+ db: &Pool,
+ pattern: &str,
+ after: chrono::DateTime,
+ ) -> i64 {
+ let logs = sqlx::query_scalar!(
+ "SELECT logs FROM job_logs WHERE created_at > $1",
+ after
+ )
+ .fetch_all(db)
+ .await
+ .unwrap();
+
+ logs.iter()
+ .filter_map(|l| l.as_ref())
+ .map(|l| l.matches(pattern).count() as i64)
+ .sum()
+ }
+
+ /// Waits for exactly N jobs to complete. Returns the timestamp before waiting.
+ async fn wait_for_jobs(
+ completed: &mut (impl futures::Stream- + Unpin),
+ count: usize,
+ ) -> chrono::DateTime {
+ let before = chrono::Utc::now();
+ for _ in 0..count {
+ completed.next().await;
+ }
+ before
+ }
+
+ /// Waits for at least N jobs to complete, then drains any additional jobs
+ /// that complete within a short timeout. Returns the timestamp before waiting.
+ async fn wait_for_jobs_ge(
+ completed: &mut (impl futures::Stream
- + Unpin),
+ min_count: usize,
+ ) -> chrono::DateTime {
+ let before = chrono::Utc::now();
+ for _ in 0..min_count {
+ completed.next().await;
+ }
+ // Drain any additional jobs that complete within 5 seconds
+ loop {
+ match tokio::time::timeout(std::time::Duration::from_secs(1), completed.next()).await {
+ Ok(Some(_)) => continue,
+ _ => break,
+ }
+ }
+ before
+ }
+
+ #[cfg(feature = "python")]
+ #[sqlx::test(fixtures("base", "dependency_map"))]
+ async fn relock_skip_on_script_redeployment(db: Pool) -> anyhow::Result<()> {
+ std::env::set_var("DEPENDENCY_JOB_DEBOUNCE_DELAY", "0");
+ let (client, port, _s) = init(db.clone()).await;
+ let mut completed = listen_for_completed_jobs(&db).await;
+
+ in_test_worker(&db, async {
+ // Step 1: Redeploy leaf_1 - first time, no hashes exist, all should relock
+ let before = chrono::Utc::now();
+ client
+ .create_script(
+ "test-workspace",
+ &quick_ns(
+ "
+def main():
+ return 'leaf1'
+ ",
+ windmill_api_client::types::ScriptLang::Python3,
+ "f/rel/leaf_1",
+ None,
+ Some("0000000000051658".into()),
+ ),
+ )
+ .await
+ .unwrap();
+
+ // leaf_1(1) + branch(1) + root_script(2: leaf_1+branch) + root_flow(2) + root_app(2) = 8 jobs
+ wait_for_jobs(&mut completed, 8).await;
+
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ let relocking_count = count_pattern_in_job_logs(&db, "Relocking", before).await;
+ assert_eq!(skipping_count, 0, "First deployment should not skip");
+ assert!(relocking_count > 0, "First deployment should have relocking jobs");
+
+ // Step 2: Redeploy leaf_2 - first time for leaf_2, should relock
+ let before = chrono::Utc::now();
+ client
+ .create_script(
+ "test-workspace",
+ &quick_ns(
+ "
+def main():
+ return 'leaf2'
+ ",
+ windmill_api_client::types::ScriptLang::Python3,
+ "f/rel/leaf_2",
+ None,
+ Some("0000000000051659".into()),
+ ),
+ )
+ .await
+ .unwrap();
+
+ // leaf_2(1) + root_script(1) + root_flow(1) + root_app(1) = 4 jobs (no cascade, branch doesn't depend on leaf_2)
+ wait_for_jobs(&mut completed, 4).await;
+
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ let relocking_count = count_pattern_in_job_logs(&db, "Relocking", before).await;
+ assert_eq!(skipping_count, 0, "leaf_2 first deployment should not skip");
+ assert!(relocking_count > 0, "leaf_2 first deployment should have relocking jobs");
+
+ // Step 3: Redeploy leaf_2 with trivial change (comment) - lock stays same, should SKIP
+ // Get current parent hash for leaf_2
+ let leaf2_hash = sqlx::query_scalar!(
+ "SELECT hash FROM script WHERE path = 'f/rel/leaf_2' AND workspace_id = 'test-workspace' AND archived = false ORDER BY created_at DESC LIMIT 1"
+ )
+ .fetch_one(&db)
+ .await
+ .unwrap();
+
+ let before = chrono::Utc::now();
+ client
+ .create_script(
+ "test-workspace",
+ &quick_ns(
+ "
+# comment to change hash but not lock
+def main():
+ return 'leaf2'
+ ",
+ windmill_api_client::types::ScriptLang::Python3,
+ "f/rel/leaf_2",
+ None,
+ Some(format!("{:016X}", leaf2_hash)),
+ ),
+ )
+ .await
+ .unwrap();
+
+ // Same as leaf_2 first deployment: 4 jobs
+ wait_for_jobs(&mut completed, 4).await;
+
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ assert!(skipping_count > 0, "Trivial change (comment only) should skip - lock unchanged");
+
+ // Step 4: Redeploy leaf_2 with actual dependency change (add tiny via comment) - should NOT skip
+ let leaf2_hash = sqlx::query_scalar!(
+ "SELECT hash FROM script WHERE path = 'f/rel/leaf_2' AND workspace_id = 'test-workspace' AND archived = false ORDER BY created_at DESC LIMIT 1"
+ )
+ .fetch_one(&db)
+ .await
+ .unwrap();
+
+ let before = chrono::Utc::now();
+ client
+ .create_script(
+ "test-workspace",
+ &quick_ns(
+ "
+# requirements:
+# tiny
+
+def main():
+ return 'leaf2 with tiny'
+ ",
+ windmill_api_client::types::ScriptLang::Python3,
+ "f/rel/leaf_2",
+ None,
+ Some(format!("{:016X}", leaf2_hash)),
+ ),
+ )
+ .await
+ .unwrap();
+
+ // Same as leaf_2 first deployment: 4 jobs
+ wait_for_jobs(&mut completed, 4).await;
+
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ assert_eq!(skipping_count, 0, "Changed dependencies should not skip");
+ }, port).await;
+
+ Ok(())
+ }
+
+ #[cfg(feature = "python")]
+ #[sqlx::test(fixtures("base", "dependency_map"))]
+ async fn relock_skip_on_workspace_deps_redeployment(db: Pool) -> anyhow::Result<()> {
+ use windmill_common::scripts::ScriptLang;
+ use windmill_dep_map::workspace_dependencies::NewWorkspaceDependencies;
+
+ std::env::set_var("DEPENDENCY_JOB_DEBOUNCE_DELAY", "0");
+ std::env::set_var("EXISTS_CACHE_TIMEOUT_MS", "0");
+
+ let (_client, port, _s) = init(db.clone()).await;
+ let mut completed = listen_for_completed_jobs(&db).await;
+
+ // Step 1: Redeploy default (unnamed) workspace deps - first time, should relock
+ let before = chrono::Utc::now();
+ NewWorkspaceDependencies {
+ workspace_id: "test-workspace".into(),
+ language: ScriptLang::Python3,
+ content: "".into(),
+ name: None, // Default/unnamed
+ description: None,
+ }
+ .create(("".to_owned(), "".to_owned(), "".to_owned()), db.clone())
+ .await
+ .unwrap();
+
+ in_test_worker(&db, wait_for_jobs_ge(&mut completed, 10), port).await;
+
+ // Note: within a cascade, the same script may be triggered multiple times.
+ // After the first trigger relocks and stores the hash, subsequent triggers skip.
+ // We allow up to 3 skips from cascade re-triggers.
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ let relocking_count = count_pattern_in_job_logs(&db, "Relocking", before).await;
+ assert!(skipping_count <= 3, "First deployment should have at most 3 skips from cascade");
+ assert!(relocking_count >= 3, "First deployment should have at least 3 relocking jobs");
+
+ // Step 2: Redeploy default workspace deps again - should SKIP
+ let before = chrono::Utc::now();
+ NewWorkspaceDependencies {
+ workspace_id: "test-workspace".into(),
+ language: ScriptLang::Python3,
+ content: "".into(),
+ name: None,
+ description: None,
+ }
+ .create(("".to_owned(), "".to_owned(), "".to_owned()), db.clone())
+ .await
+ .unwrap();
+
+ in_test_worker(&db, wait_for_jobs_ge(&mut completed, 10), port).await;
+
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ assert!(skipping_count >= 3, "Second deployment of same content should skip at least 3 times");
+
+ // Step 3: Redeploy default workspace deps with different content - should NOT skip
+ let before = chrono::Utc::now();
+ NewWorkspaceDependencies {
+ workspace_id: "test-workspace".into(),
+ language: ScriptLang::Python3,
+ content: "tiny".into(),
+ name: None,
+ description: None,
+ }
+ .create(("".to_owned(), "".to_owned(), "".to_owned()), db.clone())
+ .await
+ .unwrap();
+
+ in_test_worker(&db, wait_for_jobs_ge(&mut completed, 10), port).await;
+
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ let relocking_count = count_pattern_in_job_logs(&db, "Relocking", before).await;
+ assert!(skipping_count <= 4, "Changed content should have at most 3 skips from cascade");
+ assert!(relocking_count >= 3, "Changed content should trigger at least 3 relocking jobs");
+
+ // Step 4: Deploy named workspace deps first time - should relock (no hash exists yet)
+ // Named deps trigger exactly 3 independent objects with no cascade
+ let before = chrono::Utc::now();
+ NewWorkspaceDependencies {
+ workspace_id: "test-workspace".into(),
+ language: ScriptLang::Python3,
+ content: "".into(),
+ name: Some("test".to_owned()),
+ description: None,
+ }
+ .create(("".to_owned(), "".to_owned(), "".to_owned()), db.clone())
+ .await
+ .unwrap();
+
+ in_test_worker(&db, wait_for_jobs(&mut completed, 3), port).await;
+
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ let relocking_count = count_pattern_in_job_logs(&db, "Relocking", before).await;
+ assert_eq!(skipping_count, 0, "Named workspace deps first deployment should not skip");
+ assert!(relocking_count > 0, "Named workspace deps first deployment should relock");
+
+ // Step 5: Deploy named workspace deps again with no change - should SKIP
+ let before = chrono::Utc::now();
+ NewWorkspaceDependencies {
+ workspace_id: "test-workspace".into(),
+ language: ScriptLang::Python3,
+ content: "".into(),
+ name: Some("test".to_owned()),
+ description: None,
+ }
+ .create(("".to_owned(), "".to_owned(), "".to_owned()), db.clone())
+ .await
+ .unwrap();
+
+ in_test_worker(&db, wait_for_jobs(&mut completed, 3), port).await;
+
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ let relocking_count = count_pattern_in_job_logs(&db, "Relocking", before).await;
+
+ assert!(skipping_count > 0, "Named workspace deps second deployment should skip");
+ assert_eq!(relocking_count, 0, "Named workspace deps second deployment should not relock");
+
+ // Step 6: Deploy named workspace deps with small change - should NOT skip
+ let before = chrono::Utc::now();
+ NewWorkspaceDependencies {
+ workspace_id: "test-workspace".into(),
+ language: ScriptLang::Python3,
+ content: "tiny".into(),
+ name: Some("test".to_owned()),
+ description: None,
+ }
+ .create(("".to_owned(), "".to_owned(), "".to_owned()), db.clone())
+ .await
+ .unwrap();
+
+ in_test_worker(&db, wait_for_jobs(&mut completed, 3), port).await;
+
+ let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
+ let relocking_count = count_pattern_in_job_logs(&db, "Relocking", before).await;
+ assert_eq!(skipping_count, 0, "Named workspace deps with change should not skip");
+ assert!(relocking_count > 0, "Named workspace deps with change should relock");
+
+ Ok(())
+ }
+}
diff --git a/backend/tests/retry.rs b/backend/tests/retry.rs
index 60b81573db..cb77e4546b 100644
--- a/backend/tests/retry.rs
+++ b/backend/tests/retry.rs
@@ -1,8 +1,6 @@
-mod common;
-
#[cfg(feature = "deno_core")]
mod retry {
- use crate::common::*;
+ use windmill_test_utils::*;
use serde_json::json;
use sqlx::{Pool, Postgres};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
diff --git a/backend/tests/success_handler.rs b/backend/tests/success_handler.rs
index e3c733100e..2f580e4dcb 100644
--- a/backend/tests/success_handler.rs
+++ b/backend/tests/success_handler.rs
@@ -1,7 +1,6 @@
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
/// Test that the workspace success handler cache works correctly with 60s TTL
#[cfg(feature = "deno_core")]
diff --git a/backend/tests/suspend_resume.rs b/backend/tests/suspend_resume.rs
index a3e4cc456f..f2347af57a 100644
--- a/backend/tests/suspend_resume.rs
+++ b/backend/tests/suspend_resume.rs
@@ -1,11 +1,9 @@
-mod common;
-
mod suspend_resume {
#[cfg(feature = "deno_core")]
use serde_json::json;
#[cfg(feature = "deno_core")]
- use crate::common::*;
+ use windmill_test_utils::*;
#[cfg(feature = "deno_core")]
use futures::{Stream, StreamExt};
diff --git a/backend/tests/worker.rs b/backend/tests/worker.rs
index f98e1e3ad7..d084a0177c 100644
--- a/backend/tests/worker.rs
+++ b/backend/tests/worker.rs
@@ -25,8 +25,7 @@ use windmill_common::{
jobs::{JobPayload, RawCode},
scripts::ScriptLang,
};
-mod common;
-use common::*;
+use windmill_test_utils::*;
#[cfg(feature = "enterprise")]
use futures::StreamExt;
diff --git a/backend/tests/workspace_dependencies.rs b/backend/tests/workspace_dependencies.rs
index 124e727e91..4f1023d54d 100644
--- a/backend/tests/workspace_dependencies.rs
+++ b/backend/tests/workspace_dependencies.rs
@@ -1,9 +1,8 @@
-mod common;
mod workspace_dependencies {
- use crate::common::in_test_worker;
- use crate::common::init_client;
- use crate::common::listen_for_completed_jobs;
+ use windmill_test_utils::in_test_worker;
+ use windmill_test_utils::init_client;
+ use windmill_test_utils::listen_for_completed_jobs;
use sqlx::{Pool, Postgres};
use tokio_stream::StreamExt;
use windmill_common::scripts::ScriptLang;
@@ -122,14 +121,6 @@ mod workspace_dependencies {
);
// Verify built-in fixtures exist
- // Check that the setup_app exists
- let app_exists =
- sqlx::query_scalar!("SELECT EXISTS(SELECT 1 FROM app WHERE path = 'g/all/setup_app')")
- .fetch_one(db)
- .await
- .unwrap();
- assert!(app_exists.unwrap(), "Expected g/all/setup_app to exist");
-
// Check that hub_sync script exists and is a Bun script
let hub_sync_lang = sqlx::query_scalar!(
r#"SELECT language AS "language: ScriptLang" FROM script WHERE path = 'u/admin/hub_sync'"#
diff --git a/backend/update_sqlx.sh b/backend/update_sqlx.sh
index f87fd72d5c..4101ed6168 100755
--- a/backend/update_sqlx.sh
+++ b/backend/update_sqlx.sh
@@ -12,9 +12,9 @@ if [[ "$(uname)" == "Darwin" ]]; then
# Run cargo sqlx prepare with deno_core_mac
echo "Running cargo sqlx prepare with deno_core_mac..."
- cargo sqlx prepare --workspace -- --all-targets --features all_sqlx_features,private,deno_core_mac
+ cargo sqlx prepare --workspace -- --workspace --all-targets --features all_sqlx_features,private,deno_core_mac,deno_core,enterprise,mcp
else
# Run cargo sqlx prepare
echo "Running cargo sqlx prepare..."
- cargo sqlx prepare --workspace -- --all-targets --features all_sqlx_features,ee
+ cargo sqlx prepare --workspace -- --workspace --all-targets --features all_sqlx_features,ee,deno_core,private,enterprise,mcp
fi
diff --git a/backend/windmill-api-configs/src/lib.rs b/backend/windmill-api-configs/src/lib.rs
index 35ace8d6a3..59ad1625a4 100644
--- a/backend/windmill-api-configs/src/lib.rs
+++ b/backend/windmill-api-configs/src/lib.rs
@@ -23,7 +23,7 @@ use windmill_common::{
DB,
};
-use windmill_api_auth::{ApiAuthed, require_devops_role};
+use windmill_api_auth::{require_devops_role, ApiAuthed};
pub fn global_service() -> Router {
Router::new()
@@ -128,12 +128,16 @@ async fn update_config(
require_devops_role(&db, &authed.email).await?;
#[cfg(not(feature = "enterprise"))]
- if name.starts_with("worker__") {
- return Err(error::Error::BadRequest(
- "Worker groups configurable from UI available only in the enterprise version"
- .to_string(),
- ));
- }
+ let config = if name.starts_with("worker__") {
+ // In CE, only allow setting worker_tags, cache_clear, and init_bash
+ serde_json::json!({
+ "worker_tags": config.get("worker_tags"),
+ "cache_clear": config.get("cache_clear"),
+ "init_bash": config.get("init_bash")
+ })
+ } else {
+ config
+ };
if name.starts_with("worker__") {
let periodic_script_bash = config
diff --git a/backend/windmill-api-flows/Cargo.toml b/backend/windmill-api-flows/Cargo.toml
new file mode 100644
index 0000000000..5407e38068
--- /dev/null
+++ b/backend/windmill-api-flows/Cargo.toml
@@ -0,0 +1,31 @@
+[package]
+name = "windmill-api-flows"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+
+[lib]
+name = "windmill_api_flows"
+path = "src/lib.rs"
+
+[features]
+default = []
+enterprise = ["windmill-common/enterprise"]
+private = ["windmill-common/private"]
+
+[dependencies]
+windmill-common = { workspace = true, default-features = false }
+windmill-api-auth.workspace = true
+windmill-queue.workspace = true
+windmill-audit.workspace = true
+windmill-git-sync.workspace = true
+windmill-dep-map.workspace = true
+
+axum.workspace = true
+hyper.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+sql-builder.workspace = true
+sqlx.workspace = true
+tracing.workspace = true
+chrono.workspace = true
diff --git a/backend/windmill-api-scripts/src/flows.rs b/backend/windmill-api-flows/src/flows.rs
similarity index 100%
rename from backend/windmill-api-scripts/src/flows.rs
rename to backend/windmill-api-flows/src/flows.rs
diff --git a/backend/windmill-api-flows/src/lib.rs b/backend/windmill-api-flows/src/lib.rs
new file mode 100644
index 0000000000..3a8530f178
--- /dev/null
+++ b/backend/windmill-api-flows/src/lib.rs
@@ -0,0 +1,9 @@
+/*
+ * Author: Ruben Fiszel
+ * Copyright: Windmill Labs, Inc 2022
+ * This file and its contents are licensed under the AGPLv3 License.
+ * Please see the included NOTICE for copyright information and
+ * LICENSE-AGPL for a copy of the license.
+ */
+
+pub mod flows;
diff --git a/backend/windmill-api-integration-tests/Cargo.toml b/backend/windmill-api-integration-tests/Cargo.toml
new file mode 100644
index 0000000000..1936a13fd9
--- /dev/null
+++ b/backend/windmill-api-integration-tests/Cargo.toml
@@ -0,0 +1,36 @@
+[package]
+name = "windmill-api-integration-tests"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+
+[lib]
+name = "windmill_api_integration_tests"
+path = "src/lib.rs"
+
+[features]
+default = []
+private = ["windmill-test-utils/private", "dep:aws-config", "dep:aws-credential-types", "dep:aws-sdk-sqs"]
+enterprise = ["windmill-test-utils/enterprise", "dep:base64"]
+deno_core = ["windmill-test-utils/deno_core"]
+mcp = []
+
+[dependencies]
+windmill-test-utils.workspace = true
+windmill-api-client.workspace = true
+windmill-common = { workspace = true, default-features = false }
+sqlx.workspace = true
+serde_json.workspace = true
+serde.workspace = true
+reqwest.workspace = true
+tokio.workspace = true
+anyhow.workspace = true
+uuid.workspace = true
+rand.workspace = true
+rumqttc.workspace = true
+rdkafka.workspace = true
+async-nats.workspace = true
+aws-config = { workspace = true, optional = true }
+aws-credential-types = { workspace = true, optional = true }
+aws-sdk-sqs = { workspace = true, optional = true }
+base64 = { workspace = true, optional = true }
diff --git a/backend/windmill-api-integration-tests/src/lib.rs b/backend/windmill-api-integration-tests/src/lib.rs
new file mode 100644
index 0000000000..00682b90bc
--- /dev/null
+++ b/backend/windmill-api-integration-tests/src/lib.rs
@@ -0,0 +1,2 @@
+// This crate exists only to host integration tests.
+// See tests/ directory for the actual test files.
diff --git a/backend/tests/apps.rs b/backend/windmill-api-integration-tests/tests/apps.rs
similarity index 98%
rename from backend/tests/apps.rs
rename to backend/windmill-api-integration-tests/tests/apps.rs
index 869858a265..55c85711ae 100644
--- a/backend/tests/apps.rs
+++ b/backend/windmill-api-integration-tests/tests/apps.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn app_url(port: u16, endpoint: &str, path: &str) -> String {
format!("http://localhost:{port}/api/w/test-workspace/apps/{endpoint}/{path}")
@@ -40,7 +39,7 @@ fn new_app(path: &str, summary: &str) -> serde_json::Value {
})
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_app_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/drafts.rs b/backend/windmill-api-integration-tests/tests/drafts.rs
similarity index 97%
rename from backend/tests/drafts.rs
rename to backend/windmill-api-integration-tests/tests/drafts.rs
index e479d0b97c..d86c91b6a1 100644
--- a/backend/tests/drafts.rs
+++ b/backend/windmill-api-integration-tests/tests/drafts.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn client() -> reqwest::Client {
reqwest::Client::new()
@@ -12,7 +11,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
builder.header("Authorization", "Bearer SECRET_TOKEN")
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_draft_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/windmill-api-integration-tests/tests/fixtures/base.sql b/backend/windmill-api-integration-tests/tests/fixtures/base.sql
new file mode 100644
index 0000000000..7db9918fba
--- /dev/null
+++ b/backend/windmill-api-integration-tests/tests/fixtures/base.sql
@@ -0,0 +1,146 @@
+-- used for backend automated testing
+-- https://docs.rs/sqlx/latest/sqlx/attr.test.html
+
+INSERT INTO workspace
+ (id, name, owner)
+ VALUES ('test-workspace', 'test-workspace', 'test-user');
+
+INSERT INTO usr(workspace_id, email, username, is_admin, role) VALUES
+ ('test-workspace', 'test@windmill.dev', 'test-user', true, 'Admin');
+
+INSERT INTO workspace_key(workspace_id, kind, key) VALUES
+ ('test-workspace', 'cloud', 'test-key');
+
+
+INSERT INTO workspace_settings (workspace_id) VALUES
+ ('test-workspace');
+
+INSERT INTO group_ (workspace_id, name, summary, extra_perms) VALUES
+ ('test-workspace', 'all', 'All users', '{}');
+
+INSERT INTO password(email, password_hash, login_type, super_admin, verified, name, username)
+ VALUES ('test@windmill.dev', 'not-a-real-hash', 'password', true, true, 'Test User', 'test-user');
+
+INSERT INTO password(email, password_hash, login_type, super_admin, verified, name)
+ VALUES ('test2@windmill.dev', 'not-a-real-hash', 'password', false, true, 'Test User 2');
+
+INSERT INTO password(email, password_hash, login_type, super_admin, verified, name)
+ VALUES ('test3@windmill.dev', 'not-a-real-hash', 'password', false, true, 'Test User 3');
+
+INSERT INTO usr(workspace_id, email, username, is_admin, role) VALUES
+ ('test-workspace', 'test2@windmill.dev', 'test-user-2', false, 'User');
+
+INSERT INTO usr(workspace_id, email, username, is_admin, role) VALUES
+ ('test-workspace', 'test3@windmill.dev', 'test-user-3', false, 'User');
+
+insert INTO token(token, email, label, super_admin) VALUES ('SECRET_TOKEN', 'test@windmill.dev', 'test token', true);
+insert INTO token(token, email, label, super_admin) VALUES ('SECRET_TOKEN_2', 'test2@windmill.dev', 'test token 2', false);
+insert INTO token(token, email, label, super_admin) VALUES ('SECRET_TOKEN_3', 'test3@windmill.dev', 'test token 3', false);
+
+GRANT ALL PRIVILEGES ON TABLE workspace_key TO windmill_admin;
+GRANT ALL PRIVILEGES ON TABLE workspace_key TO windmill_user;
+
+CREATE FUNCTION "notify_insert_on_completed_job" ()
+RETURNS TRIGGER AS $$
+BEGIN
+ PERFORM pg_notify('completed', NEW.id::text);
+ RETURN NEW;
+END;
+$$ LANGUAGE PLPGSQL;
+
+ CREATE TRIGGER "notify_insert_on_completed_job"
+ AFTER INSERT ON "v2_job_completed"
+ FOR EACH ROW
+EXECUTE FUNCTION "notify_insert_on_completed_job" ();
+
+
+CREATE FUNCTION "notify_queue" ()
+RETURNS TRIGGER AS $$
+BEGIN
+ PERFORM pg_notify('queued', NEW.id::text);
+ RETURN NEW;
+END;
+$$ LANGUAGE PLPGSQL;
+
+ CREATE TRIGGER "notify_queue_after_insert"
+ AFTER INSERT ON "v2_job_queue"
+ FOR EACH ROW
+EXECUTE FUNCTION "notify_queue" ();
+
+ CREATE TRIGGER "notify_queue_after_flow_status_update"
+ AFTER UPDATE ON "v2_job_status"
+ FOR EACH ROW
+ WHEN (NEW.flow_status IS DISTINCT FROM OLD.flow_status)
+EXECUTE FUNCTION "notify_queue" ();
+
+-- Apply phase 4:
+DROP FUNCTION IF EXISTS v2_job_after_update CASCADE;
+DROP FUNCTION IF EXISTS v2_job_completed_before_insert CASCADE;
+DROP FUNCTION IF EXISTS v2_job_completed_before_update CASCADE;
+DROP FUNCTION IF EXISTS v2_job_queue_after_insert CASCADE;
+DROP FUNCTION IF EXISTS v2_job_queue_before_insert CASCADE;
+DROP FUNCTION IF EXISTS v2_job_queue_before_update CASCADE;
+DROP FUNCTION IF EXISTS v2_job_runtime_before_insert CASCADE;
+DROP FUNCTION IF EXISTS v2_job_runtime_before_update CASCADE;
+DROP FUNCTION IF EXISTS v2_job_status_before_insert CASCADE;
+DROP FUNCTION IF EXISTS v2_job_status_before_update CASCADE;
+
+DROP VIEW IF EXISTS completed_job, completed_job_view, job, queue, queue_view CASCADE;
+
+ALTER TABLE v2_job_queue
+ DROP COLUMN IF EXISTS __parent_job CASCADE,
+ DROP COLUMN IF EXISTS __created_by CASCADE,
+ DROP COLUMN IF EXISTS __script_hash CASCADE,
+ DROP COLUMN IF EXISTS __script_path CASCADE,
+ DROP COLUMN IF EXISTS __args CASCADE,
+ DROP COLUMN IF EXISTS __logs CASCADE,
+ DROP COLUMN IF EXISTS __raw_code CASCADE,
+ DROP COLUMN IF EXISTS __canceled CASCADE,
+ DROP COLUMN IF EXISTS __last_ping CASCADE,
+ DROP COLUMN IF EXISTS __job_kind CASCADE,
+ DROP COLUMN IF EXISTS __env_id CASCADE,
+ DROP COLUMN IF EXISTS __schedule_path CASCADE,
+ DROP COLUMN IF EXISTS __permissioned_as CASCADE,
+ DROP COLUMN IF EXISTS __flow_status CASCADE,
+ DROP COLUMN IF EXISTS __raw_flow CASCADE,
+ DROP COLUMN IF EXISTS __is_flow_step CASCADE,
+ DROP COLUMN IF EXISTS __language CASCADE,
+ DROP COLUMN IF EXISTS __same_worker CASCADE,
+ DROP COLUMN IF EXISTS __raw_lock CASCADE,
+ DROP COLUMN IF EXISTS __pre_run_error CASCADE,
+ DROP COLUMN IF EXISTS __email CASCADE,
+ DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
+ DROP COLUMN IF EXISTS __mem_peak CASCADE,
+ DROP COLUMN IF EXISTS __root_job CASCADE,
+ DROP COLUMN IF EXISTS __leaf_jobs CASCADE,
+ DROP COLUMN IF EXISTS __concurrent_limit CASCADE,
+ DROP COLUMN IF EXISTS __concurrency_time_window_s CASCADE,
+ DROP COLUMN IF EXISTS __timeout CASCADE,
+ DROP COLUMN IF EXISTS __flow_step_id CASCADE,
+ DROP COLUMN IF EXISTS __cache_ttl CASCADE;
+
+LOCK TABLE v2_job_queue IN ACCESS EXCLUSIVE MODE;
+ALTER TABLE v2_job_completed
+ DROP COLUMN IF EXISTS __parent_job CASCADE,
+ DROP COLUMN IF EXISTS __created_by CASCADE,
+ DROP COLUMN IF EXISTS __created_at CASCADE,
+ DROP COLUMN IF EXISTS __success CASCADE,
+ DROP COLUMN IF EXISTS __script_hash CASCADE,
+ DROP COLUMN IF EXISTS __script_path CASCADE,
+ DROP COLUMN IF EXISTS __args CASCADE,
+ DROP COLUMN IF EXISTS __logs CASCADE,
+ DROP COLUMN IF EXISTS __raw_code CASCADE,
+ DROP COLUMN IF EXISTS __canceled CASCADE,
+ DROP COLUMN IF EXISTS __job_kind CASCADE,
+ DROP COLUMN IF EXISTS __env_id CASCADE,
+ DROP COLUMN IF EXISTS __schedule_path CASCADE,
+ DROP COLUMN IF EXISTS __permissioned_as CASCADE,
+ DROP COLUMN IF EXISTS __raw_flow CASCADE,
+ DROP COLUMN IF EXISTS __is_flow_step CASCADE,
+ DROP COLUMN IF EXISTS __language CASCADE,
+ DROP COLUMN IF EXISTS __is_skipped CASCADE,
+ DROP COLUMN IF EXISTS __raw_lock CASCADE,
+ DROP COLUMN IF EXISTS __email CASCADE,
+ DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
+ DROP COLUMN IF EXISTS __tag CASCADE,
+ DROP COLUMN IF EXISTS __priority CASCADE;
diff --git a/backend/windmill-api-integration-tests/tests/fixtures/permissions_test.sql b/backend/windmill-api-integration-tests/tests/fixtures/permissions_test.sql
new file mode 100644
index 0000000000..a9006f5233
--- /dev/null
+++ b/backend/windmill-api-integration-tests/tests/fixtures/permissions_test.sql
@@ -0,0 +1,238 @@
+-- Permissions test fixture
+-- This sets up a comprehensive permission testing scenario
+
+-- ============================================
+-- USERS
+-- ============================================
+
+-- Admin user (may already exist from base.sql, use ON CONFLICT)
+INSERT INTO usr (workspace_id, email, username, is_admin, role)
+VALUES ('test-workspace', 'admin@windmill.dev', 'admin', true, 'Admin')
+ON CONFLICT (workspace_id, username) DO NOTHING;
+
+-- Regular users (non-admin)
+INSERT INTO usr (workspace_id, email, username, is_admin, role)
+VALUES
+ ('test-workspace', 'alice@windmill.dev', 'alice', false, 'Developer'),
+ ('test-workspace', 'bob@windmill.dev', 'bob', false, 'Developer'),
+ ('test-workspace', 'charlie@windmill.dev', 'charlie', false, 'Developer');
+
+-- Operator user (can execute but cannot create/update scripts, flows, apps)
+INSERT INTO usr (workspace_id, email, username, is_admin, operator, role)
+VALUES
+ ('test-workspace', 'operator@windmill.dev', 'operator', false, true, 'Operator');
+
+-- Add users to password table (use ON CONFLICT since admin may exist from base.sql)
+INSERT INTO password (email, password_hash, login_type, super_admin, verified, name)
+VALUES
+ ('admin@windmill.dev', 'dummy_hash', 'password', false, true, 'Admin User'),
+ ('alice@windmill.dev', 'dummy_hash', 'password', false, true, 'Alice'),
+ ('bob@windmill.dev', 'dummy_hash', 'password', false, true, 'Bob'),
+ ('charlie@windmill.dev', 'dummy_hash', 'password', false, true, 'Charlie'),
+ ('operator@windmill.dev', 'dummy_hash', 'password', false, true, 'Operator')
+ON CONFLICT (email) DO NOTHING;
+
+-- ============================================
+-- TOKENS for authentication
+-- ============================================
+
+-- Tokens associated with emails (workspace-scoped)
+-- The auth system will look up the user by email in the usr table
+-- Note: tokens must be at least 10 characters (TOKEN_PREFIX_LEN)
+INSERT INTO token (token, email, label, super_admin, owner, workspace_id)
+VALUES
+ ('ADMIN_TOKEN_TEST', 'admin@windmill.dev', 'Admin token', false, 'u/admin', 'test-workspace'),
+ ('ALICE_TOKEN_TEST', 'alice@windmill.dev', 'Alice token', false, 'u/alice', 'test-workspace'),
+ ('BOB_TOKEN_TEST12', 'bob@windmill.dev', 'Bob token', false, 'u/bob', 'test-workspace'),
+ ('CHARLIE_TOKEN_01', 'charlie@windmill.dev', 'Charlie token', false, 'u/charlie', 'test-workspace'),
+ ('OPERATOR_TOKEN_1', 'operator@windmill.dev', 'Operator token', false, 'u/operator', 'test-workspace');
+
+-- ============================================
+-- GROUPS
+-- ============================================
+
+-- 'developers' group - Charlie is a member
+INSERT INTO group_ (workspace_id, name, summary, extra_perms)
+VALUES ('test-workspace', 'developers', 'Developer group', '{}');
+
+-- 'editors' group - Bob is a member (has write access to some folders)
+INSERT INTO group_ (workspace_id, name, summary, extra_perms)
+VALUES ('test-workspace', 'editors', 'Editor group', '{}');
+
+-- Group memberships
+INSERT INTO usr_to_group (workspace_id, group_, usr)
+VALUES
+ ('test-workspace', 'developers', 'charlie'),
+ ('test-workspace', 'editors', 'bob');
+
+-- ============================================
+-- FOLDERS
+-- ============================================
+
+-- 'shared' folder:
+-- - Alice has read-only access (extra_perms: u/alice -> false)
+-- - Bob has write access (extra_perms: u/bob -> true)
+INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
+VALUES ('test-workspace', 'shared', 'Shared Folder', '{"u/admin"}',
+ '{"u/alice": false, "u/bob": true}', 'admin');
+
+-- 'team' folder:
+-- - 'developers' group has read-only access
+INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
+VALUES ('test-workspace', 'team', 'Team Folder', '{"u/admin"}',
+ '{"g/developers": false}', 'admin');
+
+-- 'editable' folder:
+-- - 'editors' group has write access
+INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
+VALUES ('test-workspace', 'editable', 'Editable Folder', '{"u/admin"}',
+ '{"g/editors": true}', 'admin');
+
+-- 'admin_only' folder:
+-- - Only admin has access (but we'll add item-level perms for specific items)
+INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
+VALUES ('test-workspace', 'admin_only', 'Admin Only Folder', '{"u/admin"}',
+ '{}', 'admin');
+
+-- 'alice_owned' folder:
+-- - Alice is an owner (owners must also be in extra_perms for get_folders_for_user to find them)
+INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
+VALUES ('test-workspace', 'alice_owned', 'Alice Owned Folder', '{"u/alice"}',
+ '{"u/alice": true}', 'alice');
+
+-- ============================================
+-- SCRIPTS
+-- ============================================
+
+-- Alice's personal script
+INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
+VALUES ('test-workspace', 1001, 'u/alice/my_script',
+ 'export function main() { return "alice script"; }',
+ 'deno', 'script', 'alice', '{}', 'Alice script', '', '', '{}');
+
+-- Bob's personal script
+INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
+VALUES ('test-workspace', 1002, 'u/bob/my_script',
+ 'export function main() { return "bob script"; }',
+ 'deno', 'script', 'bob', '{}', 'Bob script', '', '', '{}');
+
+-- Script in shared folder (accessible by Alice read-only, Bob write)
+INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
+VALUES ('test-workspace', 1003, 'f/shared/public_script',
+ 'export function main() { return "public"; }',
+ 'deno', 'script', 'admin', '{}', 'Public script', '', '', '{}');
+
+-- Script in team folder (accessible by developers group)
+INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
+VALUES ('test-workspace', 1004, 'f/team/team_script',
+ 'export function main() { return "team"; }',
+ 'deno', 'script', 'admin', '{}', 'Team script', '', '', '{}');
+
+-- Script in admin_only folder but with explicit share to Alice
+INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
+VALUES ('test-workspace', 1005, 'f/admin_only/shared_with_alice',
+ 'export function main() { return "shared"; }',
+ 'deno', 'script', 'admin', '{}', 'Shared with Alice', '', '',
+ '{"u/alice": false}');
+
+-- Script in alice_owned folder
+INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
+VALUES ('test-workspace', 1006, 'f/alice_owned/owner_script',
+ 'export function main() { return "owner"; }',
+ 'deno', 'script', 'alice', '{}', 'Owner script', '', '', '{}');
+
+-- Alice's script with extra_perms sharing to Bob (read-only)
+INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
+VALUES ('test-workspace', 1007, 'u/alice/extra_shared_script',
+ 'export function main() { return "extra shared"; }',
+ 'deno', 'script', 'alice', '{}', 'Extra shared script', '', '',
+ '{"u/bob": false}');
+
+-- ============================================
+-- FLOWS (with flow_versions)
+-- ============================================
+
+-- Create flows first (without versions)
+INSERT INTO flow (workspace_id, path, summary, description, value, edited_by, edited_at, schema, extra_perms)
+VALUES
+ ('test-workspace', 'u/alice/my_flow', 'Alice flow', '', '{"modules": []}', 'alice', NOW(), '{}', '{}'),
+ ('test-workspace', 'u/bob/my_flow', 'Bob flow', '', '{"modules": []}', 'bob', NOW(), '{}', '{}'),
+ ('test-workspace', 'f/shared/shared_flow', 'Shared flow', '', '{"modules": []}', 'admin', NOW(), '{}', '{}');
+
+-- Create flow versions
+INSERT INTO flow_version (id, workspace_id, path, value, schema, created_by, created_at)
+VALUES
+ (1001, 'test-workspace', 'u/alice/my_flow', '{"modules": []}', '{}', 'alice', NOW()),
+ (1002, 'test-workspace', 'u/bob/my_flow', '{"modules": []}', '{}', 'bob', NOW()),
+ (1003, 'test-workspace', 'f/shared/shared_flow', '{"modules": []}', '{}', 'admin', NOW());
+
+-- Update flows with version references
+UPDATE flow SET versions = ARRAY[1001::bigint] WHERE path = 'u/alice/my_flow' AND workspace_id = 'test-workspace';
+UPDATE flow SET versions = ARRAY[1002::bigint] WHERE path = 'u/bob/my_flow' AND workspace_id = 'test-workspace';
+UPDATE flow SET versions = ARRAY[1003::bigint] WHERE path = 'f/shared/shared_flow' AND workspace_id = 'test-workspace';
+
+-- ============================================
+-- RESOURCES
+-- ============================================
+
+-- Alice's personal resource
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/alice/my_resource', '{"key": "alice_value"}',
+ 'Alice resource', 'object', '{}', 'alice');
+
+-- Bob's personal resource
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/bob/my_resource', '{"key": "bob_value"}',
+ 'Bob resource', 'object', '{}', 'bob');
+
+-- ============================================
+-- VARIABLES
+-- ============================================
+
+-- Alice's personal variable (non-secret for testing permissions, not encryption)
+INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
+VALUES ('test-workspace', 'u/alice/my_variable', 'alice_value', false,
+ 'Alice variable', '{}');
+
+-- Bob's personal variable (non-secret for testing permissions, not encryption)
+INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
+VALUES ('test-workspace', 'u/bob/my_variable', 'bob_value', false,
+ 'Bob variable', '{}');
+
+-- ============================================
+-- SCHEDULES
+-- ============================================
+
+-- Alice's personal schedule
+INSERT INTO schedule (workspace_id, path, edited_by, edited_at, schedule, enabled, script_path, args, is_flow, email, timezone, extra_perms)
+VALUES ('test-workspace', 'u/alice/my_schedule', 'alice', NOW(), '0 * * * *', false,
+ 'u/alice/my_script', '{}', false, 'alice@windmill.dev', 'UTC', '{}');
+
+-- Bob's personal schedule
+INSERT INTO schedule (workspace_id, path, edited_by, edited_at, schedule, enabled, script_path, args, is_flow, email, timezone, extra_perms)
+VALUES ('test-workspace', 'u/bob/my_schedule', 'bob', NOW(), '0 * * * *', false,
+ 'u/bob/my_script', '{}', false, 'bob@windmill.dev', 'UTC', '{}');
+
+-- ============================================
+-- APPS (with app_versions)
+-- ============================================
+
+-- Alice's personal app
+INSERT INTO app (id, workspace_id, path, summary, versions, policy, extra_perms)
+VALUES (2001, 'test-workspace', 'u/alice/my_app', 'Alice app', '{}',
+ '{"on_behalf_of": "u/alice", "on_behalf_of_email": "alice@windmill.dev", "execution_mode": "viewer"}', '{}');
+
+-- Shared folder app
+INSERT INTO app (id, workspace_id, path, summary, versions, policy, extra_perms)
+VALUES (2002, 'test-workspace', 'f/shared/shared_app', 'Shared app', '{}',
+ '{"on_behalf_of": "u/admin", "on_behalf_of_email": "admin@windmill.dev", "execution_mode": "viewer"}', '{}');
+
+-- Create app versions
+INSERT INTO app_version (id, app_id, value, created_by, created_at)
+VALUES
+ (2001, 2001, '{"grid": []}', 'alice', NOW()),
+ (2002, 2002, '{"grid": []}', 'admin', NOW());
+
+-- Update apps with version references
+UPDATE app SET versions = ARRAY[2001::bigint] WHERE id = 2001;
+UPDATE app SET versions = ARRAY[2002::bigint] WHERE id = 2002;
diff --git a/backend/windmill-api-integration-tests/tests/fixtures/resources_test.sql b/backend/windmill-api-integration-tests/tests/fixtures/resources_test.sql
new file mode 100644
index 0000000000..1d267256cd
--- /dev/null
+++ b/backend/windmill-api-integration-tests/tests/fixtures/resources_test.sql
@@ -0,0 +1,69 @@
+-- Combined fixture for resource endpoint tests
+
+-- === resource type test data ===
+
+INSERT INTO resource_type (workspace_id, name, schema, description, created_by)
+VALUES ('test-workspace', 'test_db', '{"type": "object", "properties": {"host": {"type": "string"}}}',
+ 'Test DB type', 'test-user');
+
+-- === get_value_interpolated test data ===
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/simple_resource', '{"host": "localhost", "port": 5432}',
+ 'Simple resource', 'object', '{}', 'test-user');
+
+INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
+VALUES ('test-workspace', 'u/test-user/db_password', 'hunter2', false, 'DB password', '{}');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/resource_with_var', '{"host": "localhost", "password": "$var:u/test-user/db_password"}',
+ 'Resource with var ref', 'object', '{}', 'test-user');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/db_credentials', '{"user": "admin", "password": "secret123"}',
+ 'DB credentials', 'object', '{}', 'test-user');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/resource_with_res', '{"host": "localhost", "credentials": "$res:u/test-user/db_credentials"}',
+ 'Resource with res ref', 'object', '{}', 'test-user');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/resource_mixed', '{"host": "localhost", "password": "$var:u/test-user/db_password", "credentials": "$res:u/test-user/db_credentials"}',
+ 'Resource with mixed refs', 'object', '{}', 'test-user');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/null_resource', null,
+ 'Null resource', 'object', '{}', 'test-user');
+
+INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
+VALUES ('test-workspace', 'u/test-user/api_key', 'sk-abc123', false, 'API key', '{}');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/inner_resource', '{"key": "$var:u/test-user/api_key"}',
+ 'Inner resource', 'object', '{}', 'test-user');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/chained_resource', '{"service": "myapi", "auth": "$res:u/test-user/inner_resource"}',
+ 'Chained resource', 'object', '{}', 'test-user');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/resource_with_array', '{"hosts": ["host1", "host2"], "port": 5432}',
+ 'Resource with array', 'object', '{}', 'test-user');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/scalar_var_resource', '"$var:u/test-user/db_password"',
+ 'Scalar var ref', 'string', '{}', 'test-user');
+
+-- === mcp_tools test data ===
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/mcp_valid', '{"name": "test-mcp", "url": "http://127.0.0.1:19999/mcp"}',
+ 'Valid MCP resource (unreachable)', 'mcp_server', '{}', 'test-user');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/mcp_invalid_format', '{"host": "localhost", "port": 5432}',
+ 'Not an MCP resource', 'object', '{}', 'test-user');
+
+INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
+VALUES ('test-workspace', 'u/test-user/mcp_null', null,
+ 'Null MCP resource', 'mcp_server', '{}', 'test-user');
diff --git a/backend/windmill-api-integration-tests/tests/fixtures/variables_test.sql b/backend/windmill-api-integration-tests/tests/fixtures/variables_test.sql
new file mode 100644
index 0000000000..0d3e99e313
--- /dev/null
+++ b/backend/windmill-api-integration-tests/tests/fixtures/variables_test.sql
@@ -0,0 +1,10 @@
+-- Fixture for variable endpoint tests
+
+INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
+VALUES ('test-workspace', 'u/test-user/plain_var', 'hello world', false, 'A plain variable', '{}');
+
+INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
+VALUES ('test-workspace', 'u/test-user/secret_var', 'supersecret', true, 'A secret variable', '{}');
+
+INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
+VALUES ('test-workspace', 'u/test-user/another_var', 'foobar', false, 'Another variable', '{}');
diff --git a/backend/tests/flows.rs b/backend/windmill-api-integration-tests/tests/flows.rs
similarity index 99%
rename from backend/tests/flows.rs
rename to backend/windmill-api-integration-tests/tests/flows.rs
index 848231f2fc..ff3f86bf2d 100644
--- a/backend/tests/flows.rs
+++ b/backend/windmill-api-integration-tests/tests/flows.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn flow_url(port: u16, endpoint: &str, path: &str) -> String {
format!("http://localhost:{port}/api/w/test-workspace/flows/{endpoint}/{path}")
@@ -40,7 +39,7 @@ fn new_flow(path: &str, summary: &str) -> serde_json::Value {
})
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_flow_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/folders.rs b/backend/windmill-api-integration-tests/tests/folders.rs
similarity index 98%
rename from backend/tests/folders.rs
rename to backend/windmill-api-integration-tests/tests/folders.rs
index 075eea69eb..3d2ff5b4dd 100644
--- a/backend/tests/folders.rs
+++ b/backend/windmill-api-integration-tests/tests/folders.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn folder_url(port: u16, endpoint: &str, name: &str) -> String {
format!("http://localhost:{port}/api/w/test-workspace/folders/{endpoint}/{name}")
@@ -16,7 +15,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
builder.header("Authorization", "Bearer SECRET_TOKEN")
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_folder_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/groups.rs b/backend/windmill-api-integration-tests/tests/groups.rs
similarity index 99%
rename from backend/tests/groups.rs
rename to backend/windmill-api-integration-tests/tests/groups.rs
index 453a15916e..0fd8ee7e08 100644
--- a/backend/tests/groups.rs
+++ b/backend/windmill-api-integration-tests/tests/groups.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn group_url(port: u16, endpoint: &str, name: &str) -> String {
format!("http://localhost:{port}/api/w/test-workspace/groups/{endpoint}/{name}")
@@ -16,7 +15,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
builder.header("Authorization", "Bearer SECRET_TOKEN")
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_group_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/permissions.rs b/backend/windmill-api-integration-tests/tests/permissions.rs
similarity index 98%
rename from backend/tests/permissions.rs
rename to backend/windmill-api-integration-tests/tests/permissions.rs
index 0b1604fbb1..4342c61235 100644
--- a/backend/tests/permissions.rs
+++ b/backend/windmill-api-integration-tests/tests/permissions.rs
@@ -1,10 +1,13 @@
+#[cfg(feature = "deno_core")]
use serde_json::json;
+#[cfg(feature = "deno_core")]
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+#[cfg(feature = "deno_core")]
+use windmill_test_utils::*;
/// Helper to create a client authenticated as a specific user
+#[cfg(feature = "deno_core")]
async fn create_client_for_user(_port: u16, token: &str) -> reqwest::Client {
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(
@@ -18,12 +21,14 @@ async fn create_client_for_user(_port: u16, token: &str) -> reqwest::Client {
}
/// Test helper to check if a GET request succeeds
+#[cfg(feature = "deno_core")]
async fn can_read(client: &reqwest::Client, url: &str) -> bool {
let resp = client.get(url).send().await.unwrap();
resp.status().is_success()
}
/// Test helper to check if a POST request succeeds (for write operations)
+#[cfg(feature = "deno_core")]
async fn can_write(client: &reqwest::Client, url: &str, body: serde_json::Value) -> bool {
let resp = client.post(url).json(&body).send().await.unwrap();
let status = resp.status();
@@ -44,7 +49,7 @@ async fn can_write(client: &reqwest::Client, url: &str, body: serde_json::Value)
/// `cargo test --features deno_core permissions -- --ignored`
#[ignore]
#[cfg(feature = "deno_core")]
-#[sqlx::test(fixtures("base", "permissions_test"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base", "permissions_test"))]
async fn test_permissions_exhaustive(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
@@ -477,7 +482,7 @@ async fn test_permissions_exhaustive(db: Pool) -> anyhow::Result<()> {
/// Additional test for verifying group permission inheritance
#[ignore]
#[cfg(feature = "deno_core")]
-#[sqlx::test(fixtures("base", "permissions_test"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base", "permissions_test"))]
async fn test_group_permission_inheritance(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
@@ -547,7 +552,7 @@ async fn test_group_permission_inheritance(db: Pool) -> anyhow::Result
/// Test that permissions work correctly for all item types
#[ignore]
#[cfg(feature = "deno_core")]
-#[sqlx::test(fixtures("base", "permissions_test"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base", "permissions_test"))]
async fn test_all_item_types_permissions(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
@@ -588,7 +593,7 @@ async fn test_all_item_types_permissions(db: Pool) -> anyhow::Result<(
/// Operators have limited permissions - they can execute but cannot manage resources
#[ignore]
#[cfg(feature = "deno_core")]
-#[sqlx::test(fixtures("base", "permissions_test"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base", "permissions_test"))]
async fn test_operator_cannot_create_update(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/protection_rules.rs b/backend/windmill-api-integration-tests/tests/protection_rules.rs
similarity index 98%
rename from backend/tests/protection_rules.rs
rename to backend/windmill-api-integration-tests/tests/protection_rules.rs
index 31198f9c9c..9469554999 100644
--- a/backend/tests/protection_rules.rs
+++ b/backend/windmill-api-integration-tests/tests/protection_rules.rs
@@ -7,8 +7,7 @@ use serde_json::json;
use sqlx::{Pool, Postgres};
use windmill_common::workspaces::invalidate_protection_rules_cache;
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn client() -> reqwest::Client {
reqwest::Client::new()
@@ -51,7 +50,7 @@ fn new_flow(path: &str, summary: &str) -> serde_json::Value {
/// Comprehensive test for protection rules functionality.
/// Tests all essential cases in a single test to avoid cache interference.
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_protection_rules(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
invalidate_protection_rules_cache("test-workspace");
diff --git a/backend/tests/resources.rs b/backend/windmill-api-integration-tests/tests/resources.rs
similarity index 98%
rename from backend/tests/resources.rs
rename to backend/windmill-api-integration-tests/tests/resources.rs
index a81daf029e..6294c67308 100644
--- a/backend/tests/resources.rs
+++ b/backend/windmill-api-integration-tests/tests/resources.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn resource_url(port: u16, endpoint: &str, path: &str) -> String {
format!("http://localhost:{port}/api/w/test-workspace/resources/{endpoint}/{path}")
@@ -23,7 +22,7 @@ async fn authed_get(port: u16, endpoint: &str, path: &str) -> reqwest::Response
.unwrap()
}
-#[sqlx::test(fixtures("base", "resources_test"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base", "resources_test"))]
async fn test_resource_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
@@ -400,7 +399,7 @@ async fn test_resource_endpoints(db: Pool) -> anyhow::Result<()> {
}
#[cfg(feature = "mcp")]
-#[sqlx::test(fixtures("base", "resources_test"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base", "resources_test"))]
async fn test_mcp_tools(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/schedules.rs b/backend/windmill-api-integration-tests/tests/schedules.rs
similarity index 98%
rename from backend/tests/schedules.rs
rename to backend/windmill-api-integration-tests/tests/schedules.rs
index ee66264c5f..89ba0ec2cc 100644
--- a/backend/tests/schedules.rs
+++ b/backend/windmill-api-integration-tests/tests/schedules.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn schedule_url(port: u16, endpoint: &str, path: &str) -> String {
format!("http://localhost:{port}/api/w/test-workspace/schedules/{endpoint}/{path}")
@@ -23,7 +22,7 @@ async fn authed_get(port: u16, endpoint: &str, path: &str) -> reqwest::Response
.unwrap()
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_schedule_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/scripts.rs b/backend/windmill-api-integration-tests/tests/scripts.rs
similarity index 99%
rename from backend/tests/scripts.rs
rename to backend/windmill-api-integration-tests/tests/scripts.rs
index 3f55f36a64..74fd9c8611 100644
--- a/backend/tests/scripts.rs
+++ b/backend/windmill-api-integration-tests/tests/scripts.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn script_url(port: u16, endpoint: &str, path: &str) -> String {
format!("http://localhost:{port}/api/w/test-workspace/scripts/{endpoint}/{path}")
@@ -39,7 +38,7 @@ fn new_script(path: &str, summary: &str, content: &str) -> serde_json::Value {
})
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_script_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/trigger_e2e.rs b/backend/windmill-api-integration-tests/tests/trigger_e2e.rs
similarity index 98%
rename from backend/tests/trigger_e2e.rs
rename to backend/windmill-api-integration-tests/tests/trigger_e2e.rs
index 7bfb735a5c..3b0e32749a 100644
--- a/backend/tests/trigger_e2e.rs
+++ b/backend/windmill-api-integration-tests/tests/trigger_e2e.rs
@@ -24,8 +24,7 @@ use serde_json::json;
use sqlx::{Pool, Postgres};
use std::time::Duration;
-mod common;
-use common::*;
+use windmill_test_utils::*;
// ============================================================================
// Helpers
@@ -137,7 +136,7 @@ async fn insert_resource(
/// -- --ignored --nocapture
/// ```
#[ignore = "requires running MQTT broker on localhost:1883"]
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_mqtt_e2e(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -230,7 +229,7 @@ async fn test_mqtt_e2e(db: Pool) -> anyhow::Result<()> {
/// -- --ignored --nocapture
/// ```
#[ignore = "requires running WebSocket echo server on localhost:8765"]
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_websocket_e2e(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -286,7 +285,7 @@ async fn test_websocket_e2e(db: Pool) -> anyhow::Result<()> {
/// -- --ignored --nocapture
/// ```
#[ignore = "requires PostgreSQL with wal_level=logical"]
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_postgres_e2e(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -387,7 +386,7 @@ async fn test_postgres_e2e(db: Pool) -> anyhow::Result<()> {
/// ```
#[cfg(all(feature = "enterprise", feature = "private"))]
#[ignore = "requires running Kafka broker on localhost:9092"]
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_kafka_e2e(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -478,7 +477,7 @@ async fn test_kafka_e2e(db: Pool) -> anyhow::Result<()> {
/// ```
#[cfg(all(feature = "enterprise", feature = "private"))]
#[ignore = "requires running NATS server on localhost:4222"]
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_nats_e2e(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -553,7 +552,7 @@ async fn test_nats_e2e(db: Pool) -> anyhow::Result<()> {
/// ```
#[cfg(all(feature = "enterprise", feature = "private"))]
#[ignore = "requires LocalStack SQS on localhost:4566"]
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_sqs_e2e(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -641,7 +640,7 @@ async fn test_sqs_e2e(db: Pool) -> anyhow::Result<()> {
/// ```
#[cfg(all(feature = "enterprise", feature = "private"))]
#[ignore = "requires GCP Pub/Sub emulator on localhost:8085"]
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_gcp_e2e(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
diff --git a/backend/tests/triggers.rs b/backend/windmill-api-integration-tests/tests/triggers.rs
similarity index 95%
rename from backend/tests/triggers.rs
rename to backend/windmill-api-integration-tests/tests/triggers.rs
index ff7d34decd..46854d566e 100644
--- a/backend/tests/triggers.rs
+++ b/backend/windmill-api-integration-tests/tests/triggers.rs
@@ -12,14 +12,13 @@ use serde::Deserialize;
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
// ============================================================================
// Capture Config Tests (direct DB)
// ============================================================================
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_config_insert_and_query(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -56,7 +55,7 @@ async fn test_capture_config_insert_and_query(db: Pool) -> anyhow::Res
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_config_upsert(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -104,7 +103,7 @@ async fn test_capture_config_upsert(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_config_ping_updates_timestamp(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -159,7 +158,7 @@ async fn test_capture_config_ping_updates_timestamp(db: Pool) -> anyho
// Capture Payload Tests (direct DB)
// ============================================================================
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_insert_and_list(db: Pool) -> anyhow::Result<()> {
for i in 0..2 {
sqlx::query!(
@@ -192,7 +191,7 @@ async fn test_capture_insert_and_list(db: Pool) -> anyhow::Result<()>
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_delete(db: Pool) -> anyhow::Result<()> {
let id = sqlx::query_scalar!(
r#"
@@ -227,7 +226,7 @@ async fn test_capture_delete(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_filter_by_trigger_kind(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -304,7 +303,7 @@ struct CaptureResponse {
main_args: serde_json::Value,
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_api_set_config_and_list(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -348,7 +347,7 @@ async fn test_capture_api_set_config_and_list(db: Pool) -> anyhow::Res
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_api_list_captures(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -394,7 +393,7 @@ async fn test_capture_api_list_captures(db: Pool) -> anyhow::Result<()
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_api_get_single(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -441,7 +440,7 @@ async fn test_capture_api_get_single(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_api_delete(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -493,7 +492,7 @@ async fn test_capture_api_delete(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_capture_api_pagination(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
@@ -555,7 +554,7 @@ async fn test_capture_api_pagination(db: Pool) -> anyhow::Result<()> {
// HTTP Trigger Tests (direct DB)
// ============================================================================
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_http_trigger_insert_and_query(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -610,7 +609,7 @@ async fn test_http_trigger_insert_and_query(db: Pool) -> anyhow::Resul
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_http_trigger_multiple_methods(db: Pool) -> anyhow::Result<()> {
let methods = ["get", "post", "put", "delete", "patch"];
@@ -657,7 +656,7 @@ async fn test_http_trigger_multiple_methods(db: Pool) -> anyhow::Resul
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_http_trigger_authentication_methods(db: Pool) -> anyhow::Result<()> {
let auth_methods = ["none", "windmill", "api_key", "basic_http", "signature"];
@@ -708,7 +707,7 @@ async fn test_http_trigger_authentication_methods(db: Pool) -> anyhow:
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_http_trigger_update(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -761,7 +760,7 @@ async fn test_http_trigger_update(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_http_trigger_delete(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -813,7 +812,7 @@ async fn test_http_trigger_delete(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_http_trigger_mode_filtering(db: Pool) -> anyhow::Result<()> {
let modes = ["enabled", "disabled", "suspended"];
@@ -870,7 +869,7 @@ async fn test_http_trigger_mode_filtering(db: Pool) -> anyhow::Result<
// Other Trigger Types Tests (DB schema validation)
// ============================================================================
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_websocket_trigger_insert(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -909,7 +908,7 @@ async fn test_websocket_trigger_insert(db: Pool) -> anyhow::Result<()>
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_kafka_trigger_insert(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -952,7 +951,7 @@ async fn test_kafka_trigger_insert(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_postgres_trigger_insert(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -995,7 +994,7 @@ async fn test_postgres_trigger_insert(db: Pool) -> anyhow::Result<()>
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_nats_trigger_insert(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -1038,7 +1037,7 @@ async fn test_nats_trigger_insert(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_sqs_trigger_insert(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -1089,7 +1088,7 @@ async fn test_sqs_trigger_insert(db: Pool) -> anyhow::Result<()> {
// Cross-trigger tests
// ============================================================================
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_trigger_server_state_tracking(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -1144,7 +1143,7 @@ async fn test_trigger_server_state_tracking(db: Pool) -> anyhow::Resul
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_trigger_mode_filtering(db: Pool) -> anyhow::Result<()> {
let modes = ["enabled", "disabled", "enabled"];
@@ -1191,7 +1190,7 @@ async fn test_trigger_mode_filtering(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_multiple_capture_configs_per_path(db: Pool) -> anyhow::Result<()> {
let trigger_kinds = ["webhook", "email", "kafka"];
@@ -1229,7 +1228,7 @@ async fn test_multiple_capture_configs_per_path(db: Pool) -> anyhow::R
// Schedule Tests (DB-level)
// ============================================================================
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_schedule_insert_and_query(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -1277,7 +1276,7 @@ async fn test_schedule_insert_and_query(db: Pool) -> anyhow::Result<()
// MQTT Trigger Tests (DB-level)
// ============================================================================
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_mqtt_trigger_insert(db: Pool) -> anyhow::Result<()> {
sqlx::query(
r#"
@@ -1321,7 +1320,7 @@ async fn test_mqtt_trigger_insert(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_mqtt_trigger_update(db: Pool) -> anyhow::Result<()> {
sqlx::query(
r#"
@@ -1366,7 +1365,7 @@ async fn test_mqtt_trigger_update(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_mqtt_trigger_delete(db: Pool) -> anyhow::Result<()> {
sqlx::query(
r#"
@@ -1414,7 +1413,7 @@ async fn test_mqtt_trigger_delete(db: Pool) -> anyhow::Result<()> {
// GCP Trigger Tests (DB-level)
// ============================================================================
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_gcp_trigger_insert_pull(db: Pool) -> anyhow::Result<()> {
sqlx::query(
r#"
@@ -1465,7 +1464,7 @@ async fn test_gcp_trigger_insert_pull(db: Pool) -> anyhow::Result<()>
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_gcp_trigger_insert_push(db: Pool) -> anyhow::Result<()> {
sqlx::query(
r#"
@@ -1515,7 +1514,7 @@ async fn test_gcp_trigger_insert_push(db: Pool) -> anyhow::Result<()>
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_gcp_trigger_unique_constraint(db: Pool) -> anyhow::Result<()> {
let insert_query = r#"
INSERT INTO gcp_trigger (
@@ -1569,7 +1568,7 @@ async fn test_gcp_trigger_unique_constraint(db: Pool) -> anyhow::Resul
// Email Trigger Tests (DB-level)
// ============================================================================
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_email_trigger_insert(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -1612,7 +1611,7 @@ async fn test_email_trigger_insert(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_email_trigger_update(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
@@ -1658,7 +1657,7 @@ async fn test_email_trigger_update(db: Pool) -> anyhow::Result<()> {
Ok(())
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_email_trigger_delete(db: Pool) -> anyhow::Result<()> {
sqlx::query!(
r#"
diff --git a/backend/tests/users.rs b/backend/windmill-api-integration-tests/tests/users.rs
similarity index 99%
rename from backend/tests/users.rs
rename to backend/windmill-api-integration-tests/tests/users.rs
index 352b3cc5c6..61e174a002 100644
--- a/backend/tests/users.rs
+++ b/backend/windmill-api-integration-tests/tests/users.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn user_url(port: u16, endpoint: &str, name: &str) -> String {
format!("http://localhost:{port}/api/w/test-workspace/users/{endpoint}/{name}")
@@ -16,7 +15,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
builder.header("Authorization", "Bearer SECRET_TOKEN")
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_user_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/variables.rs b/backend/windmill-api-integration-tests/tests/variables.rs
similarity index 98%
rename from backend/tests/variables.rs
rename to backend/windmill-api-integration-tests/tests/variables.rs
index 22892e522a..0d4edaff91 100644
--- a/backend/tests/variables.rs
+++ b/backend/windmill-api-integration-tests/tests/variables.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn variable_url(port: u16, endpoint: &str, path: &str) -> String {
format!("http://localhost:{port}/api/w/test-workspace/variables/{endpoint}/{path}")
@@ -23,7 +22,7 @@ async fn authed_get(port: u16, endpoint: &str, path: &str) -> reqwest::Response
.unwrap()
}
-#[sqlx::test(fixtures("base", "variables_test"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base", "variables_test"))]
async fn test_variable_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/tests/workspace_comparison.rs b/backend/windmill-api-integration-tests/tests/workspace_comparison.rs
similarity index 99%
rename from backend/tests/workspace_comparison.rs
rename to backend/windmill-api-integration-tests/tests/workspace_comparison.rs
index 5761d6e051..f9cb6037c5 100644
--- a/backend/tests/workspace_comparison.rs
+++ b/backend/windmill-api-integration-tests/tests/workspace_comparison.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
/// Comprehensive integration test for the compare_workspaces endpoint.
///
@@ -12,7 +11,7 @@ use common::*;
/// 3. Making various changes in both workspaces (new items, modifications, conflicts, deletions, renames)
/// 4. Populating the workspace_diff table to simulate Git sync tracking
/// 5. Calling compare_workspaces and verifying all aspects of the comparison
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_compare_workspaces_comprehensive(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
diff --git a/backend/tests/workspaces.rs b/backend/windmill-api-integration-tests/tests/workspaces.rs
similarity index 99%
rename from backend/tests/workspaces.rs
rename to backend/windmill-api-integration-tests/tests/workspaces.rs
index 4a7507b155..58c07965dc 100644
--- a/backend/tests/workspaces.rs
+++ b/backend/windmill-api-integration-tests/tests/workspaces.rs
@@ -1,8 +1,7 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
-mod common;
-use common::*;
+use windmill_test_utils::*;
fn client() -> reqwest::Client {
reqwest::Client::new()
@@ -12,7 +11,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
builder.header("Authorization", "Bearer SECRET_TOKEN")
}
-#[sqlx::test(fixtures("base"))]
+#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_workspace_endpoints(db: Pool) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
diff --git a/backend/windmill-api-scripts/src/lib.rs b/backend/windmill-api-scripts/src/lib.rs
index aab68a4d52..9bc8318fc4 100644
--- a/backend/windmill-api-scripts/src/lib.rs
+++ b/backend/windmill-api-scripts/src/lib.rs
@@ -6,5 +6,4 @@
* LICENSE-AGPL for a copy of the license.
*/
-pub mod flows;
pub mod scripts;
diff --git a/backend/windmill-api-scripts/src/scripts.rs b/backend/windmill-api-scripts/src/scripts.rs
index 96968605b1..85ec0edae4 100644
--- a/backend/windmill-api-scripts/src/scripts.rs
+++ b/backend/windmill-api-scripts/src/scripts.rs
@@ -12,7 +12,10 @@ use windmill_api_auth::{
check_scopes, maybe_refresh_folders, require_owner_of_path, ApiAuthed,
};
use windmill_common::{
- utils::{BulkDeleteRequest, WithStarredInfoQuery, HTTP_CLIENT}, webhook::{WebhookMessage, WebhookShared}, workspaces::{check_user_against_rule, ProtectionRuleKind, RuleCheckResult}, DB
+ utils::{BulkDeleteRequest, WithStarredInfoQuery, HTTP_CLIENT},
+ webhook::{WebhookMessage, WebhookShared},
+ workspaces::{check_user_against_rule, ProtectionRuleKind, RuleCheckResult},
+ DB,
};
use windmill_queue::schedule::clear_schedule;
@@ -859,10 +862,13 @@ async fn create_script_internal<'c>(
}
};
- let runnable_settings_handle = windmill_common::runnable_settings::insert_rs(RunnableSettings {
- debouncing_settings: ns.debouncing_settings.insert_cached(&db).await?,
- concurrency_settings: ns.concurrency_settings.insert_cached(&db).await?,
- }, &db)
+ let runnable_settings_handle = windmill_common::runnable_settings::insert_rs(
+ RunnableSettings {
+ debouncing_settings: ns.debouncing_settings.insert_cached(&db).await?,
+ concurrency_settings: ns.concurrency_settings.insert_cached(&db).await?,
+ },
+ &db,
+ )
.await?;
let (
@@ -1072,7 +1078,9 @@ async fn create_script_internal<'c>(
}
if needs_lock_gen {
let tag = if ns.dedicated_worker.is_some_and(|x| x) {
- Some(format!("{}:{}", &w_id, &ns.path,))
+ Some(windmill_common::worker::dedicated_worker_tag(
+ &w_id, &ns.path,
+ ))
} else if ns.tag.as_ref().is_some_and(|x| x.contains("$args[")) {
None
} else {
@@ -1839,7 +1847,9 @@ async fn get_script_by_hash(
tx.commit().await?;
- Ok(Json(windmill_common::scripts::prefetch_cached_script_with_starred(r, &db).await?))
+ Ok(Json(
+ windmill_common::scripts::prefetch_cached_script_with_starred(r, &db).await?,
+ ))
}
async fn raw_script_by_hash(
@@ -2042,7 +2052,9 @@ async fn archive_script_by_hash(
WebhookMessage::DeleteScript { workspace: w_id, hash: hash.to_string() },
);
- Ok(Json(windmill_common::scripts::prefetch_cached_script(script, &db).await?))
+ Ok(Json(
+ windmill_common::scripts::prefetch_cached_script(script, &db).await?,
+ ))
}
async fn delete_script_by_hash(
@@ -2097,7 +2109,9 @@ async fn delete_script_by_hash(
WebhookMessage::DeleteScript { workspace: w_id, hash: hash.to_string() },
);
- Ok(Json(windmill_common::scripts::prefetch_cached_script(script, &db).await?))
+ Ok(Json(
+ windmill_common::scripts::prefetch_cached_script(script, &db).await?,
+ ))
}
#[derive(Deserialize)]
diff --git a/backend/windmill-api-settings/src/lib.rs b/backend/windmill-api-settings/src/lib.rs
index de234e33c2..e2768a8a0f 100644
--- a/backend/windmill-api-settings/src/lib.rs
+++ b/backend/windmill-api-settings/src/lib.rs
@@ -26,7 +26,6 @@ use axum::{
routing::{get, post},
Json, Router,
};
-
#[cfg(feature = "enterprise")]
use axum::extract::Query;
use serde_json::json;
@@ -45,6 +44,7 @@ use windmill_common::{
CRITICAL_ALERT_MUTE_UI_SETTING, EMAIL_DOMAIN_SETTING, ENV_SETTINGS,
HUB_ACCESSIBLE_URL_SETTING, HUB_BASE_URL_SETTING,
},
+ instance_config::{self, ApplyMode, InstanceConfig},
server::Smtp,
};
use windmill_common::{error::to_anyhow, PgDatabase};
@@ -58,6 +58,10 @@ pub fn global_service() -> Router {
post(set_global_setting).get(get_global_setting),
)
.route("/list_global", get(list_global_settings))
+ .route(
+ "/instance_config",
+ get(get_instance_config).put(set_instance_config),
+ )
.route("/test_smtp", post(test_email))
.route("/test_license_key", post(test_license_key))
.route("/send_stats", post(send_stats))
@@ -89,6 +93,10 @@ pub fn global_service() -> Router {
.route(
"/critical_alerts/acknowledge_all",
post(acknowledge_all_critical_alerts),
+ )
+ .route(
+ "/sync_cached_resource_types",
+ post(sync_cached_resource_types),
);
// Vault integration routes (EE only - requires both private and enterprise features)
@@ -267,9 +275,40 @@ pub async fn set_global_setting_internal(
key: String,
value: serde_json::Value,
) -> error::Result<()> {
- match key.as_str() {
+ run_setting_pre_write_hook(db, &key, &value).await?;
+
+ match value {
+ serde_json::Value::Null => {
+ delete_global_setting(db, &key).await?;
+ }
+ serde_json::Value::String(x) if x.is_empty() => {
+ delete_global_setting(db, &key).await?;
+ }
+ v => {
+ sqlx::query!(
+ "INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value, updated_at = now()",
+ key,
+ v
+ )
+ .execute(db)
+ .await?;
+ tracing::info!("Set global setting {} to {}", key, v);
+ }
+ };
+
+ Ok(())
+}
+
+/// Run side-effect hooks for specific settings before writing to DB.
+/// Extracted from `set_global_setting_internal` for reuse by the bulk endpoint.
+async fn run_setting_pre_write_hook(
+ db: &DB,
+ key: &str,
+ value: &serde_json::Value,
+) -> error::Result<()> {
+ match key {
AUTOMATE_USERNAME_CREATION_SETTING => {
- if value.clone().as_bool().unwrap_or(false) {
+ if value.as_bool().unwrap_or(false) {
generate_instance_username_for_all_users(db)
.await
.map_err(|err| {
@@ -281,14 +320,14 @@ pub async fn set_global_setting_internal(
}
}
CRITICAL_ALERT_MUTE_UI_SETTING => {
- if value.clone().as_bool().unwrap_or(false) {
+ if value.as_bool().unwrap_or(false) {
sqlx::query!("UPDATE alerts SET acknowledged = true")
.execute(db)
.await?;
}
}
APP_WORKSPACED_ROUTE_SETTING => {
- let serde_json::Value::Bool(workspaced_route) = &value else {
+ let serde_json::Value::Bool(workspaced_route) = value else {
return Err(error::Error::BadRequest(format!(
"{} setting Expected to be boolean",
APP_WORKSPACED_ROUTE_SETTING
@@ -308,15 +347,15 @@ pub async fn set_global_setting_internal(
SELECT
path,
custom_path
- FROM
+ FROM
app
- WHERE
+ WHERE
custom_path IN (
- SELECT
+ SELECT
custom_path
- FROM
+ FROM
app
- GROUP
+ GROUP
BY custom_path
HAVING COUNT(*) > 1
)
@@ -352,25 +391,79 @@ pub async fn set_global_setting_internal(
}
_ => {}
}
+ Ok(())
+}
- match value {
- serde_json::Value::Null => {
- delete_global_setting(db, &key).await?;
+// ---------------------------------------------------------------------------
+// Bulk instance config endpoints
+// ---------------------------------------------------------------------------
+
+async fn get_instance_config(
+ Extension(db): Extension,
+ authed: ApiAuthed,
+) -> JsonResult {
+ require_super_admin(&db, &authed.email).await?;
+ let config = InstanceConfig::from_db(&db)
+ .await
+ .map_err(|e| error::Error::internal_err(e.to_string()))?;
+ Ok(Json(config))
+}
+
+async fn set_instance_config(
+ Extension(db): Extension,
+ authed: ApiAuthed,
+ Json(desired): Json,
+) -> error::Result<()> {
+ require_super_admin(&db, &authed.email).await?;
+
+ let current = InstanceConfig::from_db(&db)
+ .await
+ .map_err(|e| error::Error::internal_err(e.to_string()))?;
+
+ let desired_map = desired.global_settings.to_settings_map();
+ if !desired_map.is_empty() {
+ let current_map = current.global_settings.to_settings_map();
+ let settings_diff =
+ instance_config::diff_global_settings(¤t_map, &desired_map, ApplyMode::Merge);
+
+ for (key, value) in &settings_diff.upserts {
+ run_setting_pre_write_hook(&db, key, value).await?;
}
- serde_json::Value::String(x) if x.is_empty() => {
- delete_global_setting(db, &key).await?;
- }
- v => {
- sqlx::query!(
- "INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value, updated_at = now()",
- key,
- v
- )
- .execute(db)
- .await?;
- tracing::info!("Set global setting {} to {}", key, v);
- }
- };
+
+ instance_config::apply_settings_diff(&db, &settings_diff)
+ .await
+ .map_err(|e| error::Error::internal_err(e.to_string()))?;
+ }
+
+ if !desired.worker_configs.is_empty() {
+ let current_wc: std::collections::BTreeMap = current
+ .worker_configs
+ .iter()
+ .map(|(k, v)| {
+ (
+ k.clone(),
+ serde_json::to_value(v)
+ .expect("WorkerGroupConfig serialization cannot fail"),
+ )
+ })
+ .collect();
+ let desired_wc: std::collections::BTreeMap = desired
+ .worker_configs
+ .iter()
+ .map(|(k, v)| {
+ (
+ k.clone(),
+ serde_json::to_value(v)
+ .expect("WorkerGroupConfig serialization cannot fail"),
+ )
+ })
+ .collect();
+ let configs_diff =
+ instance_config::diff_worker_configs(¤t_wc, &desired_wc, ApplyMode::Merge);
+ instance_config::apply_configs_diff(&db, &configs_diff)
+ .await
+ .map_err(|e| error::Error::internal_err(e.to_string()))?;
+ }
Ok(())
}
@@ -932,3 +1025,75 @@ pub async fn get_jwks() -> JsonResult {
Ok(Json(JwksResponse { keys: vec![] }))
}
}
+
+#[derive(serde::Deserialize, serde::Serialize)]
+struct CachedResourceType {
+ #[allow(dead_code)]
+ id: i64,
+ name: String,
+ schema: Option,
+ #[allow(dead_code)]
+ app: String,
+ description: Option,
+}
+
+async fn sync_cached_resource_types(
+ Extension(db): Extension,
+ authed: ApiAuthed,
+) -> error::Result {
+ require_super_admin(&db, &authed.email).await?;
+
+ use windmill_common::worker::HUB_RT_CACHE_DIR;
+ let cache_path = format!("{}/resource_types.json", HUB_RT_CACHE_DIR);
+
+ let content = tokio::fs::read_to_string(&cache_path)
+ .await
+ .map_err(|e| {
+ error::Error::NotFound(format!(
+ "No cached resource types found at {}: {}",
+ cache_path, e
+ ))
+ })?;
+
+ let cached_types: Vec =
+ serde_json::from_str(&content).map_err(|e| {
+ error::Error::InternalErr(format!("Failed to parse cached resource types: {}", e))
+ })?;
+
+ let mut synced_count = 0;
+
+ for rt in &cached_types {
+ let exists: Option = sqlx::query_scalar!(
+ "SELECT EXISTS(SELECT 1 FROM resource_type WHERE workspace_id = 'admins' AND name = $1 AND schema IS NOT DISTINCT FROM $2 AND description IS NOT DISTINCT FROM $3)",
+ &rt.name,
+ rt.schema.as_ref(),
+ rt.description.as_deref(),
+ )
+ .fetch_one(&db)
+ .await?;
+
+ if exists.unwrap_or(false) {
+ continue;
+ }
+
+ sqlx::query!(
+ "INSERT INTO resource_type (workspace_id, name, schema, description, edited_at)
+ VALUES ('admins', $1, $2, $3, now())
+ ON CONFLICT (workspace_id, name) DO UPDATE
+ SET schema = EXCLUDED.schema, description = EXCLUDED.description, edited_at = now()",
+ &rt.name,
+ rt.schema.as_ref(),
+ rt.description.as_deref(),
+ )
+ .execute(&db)
+ .await?;
+
+ synced_count += 1;
+ }
+
+ Ok(format!(
+ "Synced {} resource types ({} unchanged)",
+ synced_count,
+ cached_types.len() - synced_count
+ ))
+}
diff --git a/backend/windmill-api-users/src/users.rs b/backend/windmill-api-users/src/users.rs
index ee5fa2bd80..94e9e7cc9d 100644
--- a/backend/windmill-api-users/src/users.rs
+++ b/backend/windmill-api-users/src/users.rs
@@ -962,7 +962,7 @@ async fn join_workspace<'c>(
.await?
.map(|v| v.as_bool())
.flatten()
- .unwrap_or(false);
+ .unwrap_or(true);
let username = if automate_username_creation {
if username.is_some() && username.unwrap().len() > 0 {
diff --git a/backend/windmill-api-workspaces/src/workspaces.rs b/backend/windmill-api-workspaces/src/workspaces.rs
index f3581b787a..2b299c02f6 100644
--- a/backend/windmill-api-workspaces/src/workspaces.rs
+++ b/backend/windmill-api-workspaces/src/workspaces.rs
@@ -25,8 +25,8 @@ use regex::Regex;
use hex;
use sha2::{Digest, Sha256};
use std::collections::{HashMap, HashSet};
+use strum::IntoEnumIterator;
use uuid::Uuid;
-use strum::{IntoEnumIterator};
use windmill_audit::audit_oss::{audit_log, AuditAuthorable};
use windmill_audit::ActionKind;
use windmill_common::db::UserDB;
@@ -39,7 +39,9 @@ use windmill_common::workspaces::GitRepositorySettings;
#[cfg(feature = "enterprise")]
use windmill_common::workspaces::WorkspaceDeploymentUISettings;
use windmill_common::workspaces::{
- check_user_against_rule, get_datatable_resource_from_db_unchecked, DataTable, DataTableCatalogResourceType, ProtectionRuleKind, ProtectionRules, ProtectionRuleset, RuleCheckResult, WorkspaceGitSyncSettings
+ check_user_against_rule, get_datatable_resource_from_db_unchecked, DataTable,
+ DataTableCatalogResourceType, ProtectionRuleKind, ProtectionRules, ProtectionRuleset,
+ RuleCheckResult, WorkspaceGitSyncSettings,
};
use windmill_common::workspaces::{Ducklake, DucklakeCatalogResourceType};
use windmill_common::PgDatabase;
@@ -601,7 +603,10 @@ async fn get_settings(
tx.commit().await?;
- let settings = not_found_if_none(settings, "workspace settings", &w_id)?;
+ let mut settings = not_found_if_none(settings, "workspace settings", &w_id)?;
+ if !authed.is_admin {
+ settings.slack_oauth_client_secret = None;
+ }
Ok(Json(settings))
}
@@ -2748,7 +2753,7 @@ async fn create_workspace(
.await?
.map(|v| v.as_bool())
.flatten()
- .unwrap_or(false);
+ .unwrap_or(true);
let username = if automate_username_creation {
if nw.username.is_some() && nw.username.unwrap().len() > 0 {
@@ -3418,6 +3423,9 @@ async fn create_workspace_fork(
)));
}
+ #[cfg(not(feature = "enterprise"))]
+ _check_nb_of_workspaces(&db).await?;
+
if *DISABLE_WORKSPACE_FORK {
require_super_admin(&db, &authed.email).await?;
}
@@ -3804,7 +3812,7 @@ async fn add_user(
.await?
.map(|v| v.as_bool())
.flatten()
- .unwrap_or(false);
+ .unwrap_or(true);
let username = if automate_username_creation {
if nu.username.is_some() && nu.username.unwrap().len() > 0 {
@@ -4366,9 +4374,13 @@ async fn list_protection_rules(
Extension(db): Extension,
Path(w_id): Path,
) -> JsonResult> {
- let rules =
- (*windmill_common::workspaces::get_protection_rules(&w_id, &db).await?).clone();
- Ok(Json(rules.into_iter().map(ProtectionRulesetResponse::from).collect()))
+ let rules = (*windmill_common::workspaces::get_protection_rules(&w_id, &db).await?).clone();
+ Ok(Json(
+ rules
+ .into_iter()
+ .map(ProtectionRulesetResponse::from)
+ .collect(),
+ ))
}
/// Create a new protection rule
diff --git a/backend/windmill-api/Cargo.toml b/backend/windmill-api/Cargo.toml
index bb08985003..6d63b62cbf 100644
--- a/backend/windmill-api/Cargo.toml
+++ b/backend/windmill-api/Cargo.toml
@@ -11,7 +11,7 @@ path = "src/lib.rs"
[features]
default = []
private = ["windmill-audit/private", "windmill-common/private", "windmill-api-auth/private", "windmill-store/private", "windmill-api-users/private", "windmill-api-workspaces/private", "windmill-api-groups/private", "windmill-api-configs/private", "windmill-api-settings/private", "windmill-api-agent-workers?/private", "windmill-trigger-kafka?/private", "windmill-trigger-postgres?/private", "windmill-trigger-mqtt?/private", "windmill-trigger-websocket?/private", "windmill-trigger-nats?/private", "windmill-trigger-sqs?/private", "windmill-trigger-gcp?/private", "windmill-trigger-email?/private"]
-enterprise = ["windmill-queue/enterprise", "windmill-audit/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise", "windmill-worker?/enterprise", "windmill-api-auth/enterprise", "windmill-store/enterprise", "windmill-api-jobs/enterprise", "windmill-api-scripts/enterprise", "windmill-api-users/enterprise", "windmill-api-workspaces/enterprise", "windmill-api-groups/enterprise", "windmill-api-configs/enterprise", "windmill-api-settings/enterprise", "windmill-api-agent-workers?/enterprise", "windmill-trigger/enterprise", "windmill-trigger-kafka?/enterprise", "windmill-trigger-postgres?/enterprise", "windmill-trigger-mqtt?/enterprise", "windmill-trigger-websocket?/enterprise", "windmill-trigger-email?/enterprise", "windmill-trigger-nats?/enterprise", "windmill-trigger-sqs?/enterprise", "windmill-trigger-gcp?/enterprise", "windmill-trigger-http?/enterprise", "windmill-native-triggers?/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise"]
+enterprise = ["windmill-queue/enterprise", "windmill-audit/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise", "windmill-worker?/enterprise", "windmill-api-auth/enterprise", "windmill-store/enterprise", "windmill-api-jobs/enterprise", "windmill-api-scripts/enterprise", "windmill-api-flows/enterprise", "windmill-api-users/enterprise", "windmill-api-workspaces/enterprise", "windmill-api-groups/enterprise", "windmill-api-configs/enterprise", "windmill-api-settings/enterprise", "windmill-api-agent-workers?/enterprise", "windmill-trigger/enterprise", "windmill-trigger-kafka?/enterprise", "windmill-trigger-postgres?/enterprise", "windmill-trigger-mqtt?/enterprise", "windmill-trigger-websocket?/enterprise", "windmill-trigger-email?/enterprise", "windmill-trigger-nats?/enterprise", "windmill-trigger-sqs?/enterprise", "windmill-trigger-gcp?/enterprise", "windmill-trigger-http?/enterprise", "windmill-native-triggers?/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise"]
stripe = []
inline_preview = ["dep:windmill-worker", "windmill-api-configs/inline_preview"]
agent_worker_server = ["dep:windmill-worker", "dep:windmill-api-agent-workers"]
@@ -48,6 +48,7 @@ quickjs = ["windmill-jseval/quickjs"]
windmill-mcp = { workspace = true, optional = true }
windmill-api-auth.workspace = true
windmill-api-scripts.workspace = true
+windmill-api-flows.workspace = true
windmill-api-users.workspace = true
windmill-api-workspaces.workspace = true
windmill-api-groups.workspace = true
diff --git a/backend/windmill-api/openapi-deref.json b/backend/windmill-api/openapi-deref.json
index fc711cbbf1..ae3d54558e 100644
--- a/backend/windmill-api/openapi-deref.json
+++ b/backend/windmill-api/openapi-deref.json
@@ -1,7 +1,7 @@
{
"openapi": "3.0.3",
"info": {
- "version": "1.520.1",
+ "version": "1.633.1",
"title": "Windmill API",
"contact": {
"name": "Windmill Team",
@@ -55,6 +55,83 @@
}
}
},
+ "/health/status": {
+ "get": {
+ "summary": "health status",
+ "description": "Health status endpoint. Returns cached health status (database connectivity, worker count).\nCache TTL is fixed at 5 seconds. Use force=true query parameter to bypass cache.\nNote: This endpoint is intentionally different from Kubernetes probes to avoid confusion.\nFor k8s liveness/readiness probes, use /version endpoint.\n",
+ "operationId": "getHealthStatus",
+ "tags": [
+ "health"
+ ],
+ "security": [],
+ "parameters": [
+ {
+ "name": "force",
+ "in": "query",
+ "description": "Force a fresh check, bypassing the cache",
+ "required": false,
+ "schema": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "server is healthy or degraded",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HealthStatusResponse"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "server is unhealthy (database unreachable)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HealthStatusResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/health/detailed": {
+ "get": {
+ "summary": "detailed health status",
+ "description": "Returns detailed health information including database pool stats, worker details, and queue status.\nRequires authentication. Use for monitoring dashboards and debugging.\nThis endpoint always returns fresh data (no caching).\n",
+ "operationId": "getHealthDetailed",
+ "tags": [
+ "health"
+ ],
+ "responses": {
+ "200": {
+ "description": "server is healthy or degraded",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DetailedHealthResponse"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "server is unhealthy (database unreachable)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DetailedHealthResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/uptodate": {
"get": {
"summary": "is backend up to date",
@@ -97,6 +174,59 @@
}
}
},
+ "/inkeep": {
+ "post": {
+ "summary": "query Windmill AI documentation assistant (EE only)",
+ "operationId": "queryDocumentation",
+ "x-mcp-tool": true,
+ "tags": [
+ "documentation"
+ ],
+ "requestBody": {
+ "description": "query to send to the AI documentation assistant",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "query": {
+ "type": "string",
+ "description": "The documentation query to send to the AI assistant"
+ }
+ },
+ "required": [
+ "query"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "AI documentation assistant response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "description": "Response from Inkeep service"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Enterprise Edition required",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/openapi.yaml": {
"get": {
"summary": "get openapi yaml spec",
@@ -294,6 +424,121 @@
}
}
},
+ "/auth/is_smtp_configured": {
+ "get": {
+ "security": [],
+ "summary": "check if SMTP is configured for password reset",
+ "operationId": "isSmtpConfigured",
+ "tags": [
+ "user"
+ ],
+ "responses": {
+ "200": {
+ "description": "returns true if SMTP is configured",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/auth/request_password_reset": {
+ "post": {
+ "security": [],
+ "summary": "request password reset email",
+ "operationId": "requestPasswordReset",
+ "tags": [
+ "user"
+ ],
+ "requestBody": {
+ "description": "email to send password reset link to",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "email"
+ ],
+ "properties": {
+ "email": {
+ "type": "string",
+ "format": "email"
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "password reset email sent (if user exists)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PasswordResetResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "SMTP not configured"
+ }
+ }
+ }
+ },
+ "/auth/reset_password": {
+ "post": {
+ "security": [],
+ "summary": "reset password using token",
+ "operationId": "resetPassword",
+ "tags": [
+ "user"
+ ],
+ "requestBody": {
+ "description": "token and new password",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "token",
+ "new_password"
+ ],
+ "properties": {
+ "token": {
+ "type": "string"
+ },
+ "new_password": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "password reset successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PasswordResetResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "invalid or expired token"
+ }
+ }
+ }
+ },
"/w/{workspace}/users/get/{username}": {
"get": {
"summary": "get user (require admin privilege)",
@@ -853,6 +1098,45 @@
}
}
},
+ "/users/onboarding": {
+ "post": {
+ "summary": "Submit user onboarding data",
+ "operationId": "submitOnboardingData",
+ "tags": [
+ "user"
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "touch_point": {
+ "type": "string"
+ },
+ "use_case": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Onboarding data submitted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/users/delete/{username}": {
"delete": {
"summary": "delete user (require admin privilege)",
@@ -888,6 +1172,41 @@
}
}
},
+ "/w/{workspace}/users/convert_to_group/{username}": {
+ "post": {
+ "summary": "convert manual user to group user (require admin privilege)",
+ "operationId": "convertUserToGroup",
+ "tags": [
+ "user",
+ "admin"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "username",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "convert user to group user",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/github_app/connected_repositories": {
"get": {
"summary": "get connected repositories",
@@ -895,6 +1214,18 @@
"tags": [
"Git Sync"
],
+ "parameters": [
+ {
+ "name": "page",
+ "in": "query",
+ "description": "Page number for pagination (default 1)",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "default": 1
+ }
+ }
+ ],
"responses": {
"200": {
"description": "connected repositories",
@@ -975,6 +1306,32 @@
}
}
},
+ "/w/{workspace}/workspaces/get_as_superadmin": {
+ "get": {
+ "summary": "get workspace as super admin (require to be super admin)",
+ "operationId": "getWorkspaceAsSuperAdmin",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "workspace",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Workspace"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/workspaces/list_as_superadmin": {
"get": {
"summary": "list all workspaces as super admin (require to be super admin)",
@@ -1039,6 +1396,84 @@
}
}
},
+ "/w/{workspace}/workspaces/create_workspace_fork_branch": {
+ "post": {
+ "summary": "create forked workspace branch with git sync",
+ "operationId": "createWorkspaceForkGitBranch",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "new forked workspace",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateWorkspaceFork"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "forked workspace branch created",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspaces/create_fork": {
+ "post": {
+ "summary": "create forked workspace",
+ "operationId": "createWorkspaceFork",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "new forked workspace",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateWorkspaceFork"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "forked workspace created",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/workspaces/exists": {
"post": {
"summary": "exists workspace",
@@ -1122,35 +1557,43 @@
}
}
},
- "/settings/databases_exist": {
+ "/settings/refresh_custom_instance_user_pwd": {
"post": {
- "summary": "checks that all given databases exist or else return the ones that don't",
- "operationId": "databasesExist",
+ "summary": "Refreshes the password for the custom_instance_user",
+ "operationId": "refreshCustomInstanceUserPwd",
"tags": [
"setting"
],
- "requestBody": {
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "string"
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object"
}
}
}
}
- },
+ }
+ }
+ },
+ "/settings/list_custom_instance_pg_databases": {
+ "post": {
+ "summary": "Returns the set-up statuses of custom instance pg databases",
+ "operationId": "listCustomInstanceDbs",
+ "tags": [
+ "setting"
+ ],
"responses": {
"200": {
- "description": "databases that do not exist",
+ "description": "Statuses of all custom instance dbs",
"content": {
"application/json": {
"schema": {
- "type": "array",
- "items": {
- "type": "string"
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/components/schemas/CustomInstanceDb"
}
}
}
@@ -1159,13 +1602,28 @@
}
}
},
- "/settings/create_ducklake_database/{name}": {
+ "/settings/setup_custom_instance_pg_database/{name}": {
"post": {
- "summary": "Runs CREATE DATABASE on the Windmill Postgres and grants access to the ducklake_user",
- "operationId": "createDucklakeDatabase",
+ "summary": "Runs CREATE DATABASE on the Windmill Postgres and grants access to the custom_instance_user",
+ "operationId": "setupCustomInstanceDb",
"tags": [
"setting"
],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "tag": {
+ "$ref": "#/components/schemas/CustomInstanceDbTag"
+ }
+ }
+ }
+ }
+ }
+ },
"parameters": [
{
"in": "path",
@@ -1182,7 +1640,9 @@
"description": "status",
"content": {
"application/json": {
- "schema": {}
+ "schema": {
+ "$ref": "#/components/schemas/CustomInstanceDb"
+ }
}
}
}
@@ -1607,6 +2067,27 @@
}
}
},
+ "/settings/get_stats": {
+ "get": {
+ "summary": "get encrypted telemetry stats (EE only)",
+ "operationId": "getStats",
+ "tags": [
+ "setting"
+ ],
+ "responses": {
+ "200": {
+ "description": "base64-encoded encrypted telemetry blob",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/settings/latest_key_renewal_attempt": {
"get": {
"summary": "get latest key renewal attempt",
@@ -1760,6 +2241,158 @@
}
}
},
+ "/min_keep_alive_version": {
+ "get": {
+ "summary": "get minimum worker versions required to stay alive",
+ "operationId": "getMinKeepAliveVersion",
+ "tags": [
+ "setting"
+ ],
+ "responses": {
+ "200": {
+ "description": "minimum keep-alive versions for workers and agents",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "worker",
+ "agent"
+ ],
+ "properties": {
+ "worker": {
+ "type": "string",
+ "description": "minimum version for normal workers"
+ },
+ "agent": {
+ "type": "string",
+ "description": "minimum version for agent workers"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/.well-known/jwks.json": {
+ "get": {
+ "summary": "get JWKS for Vault JWT authentication",
+ "operationId": "getJwks",
+ "tags": [
+ "setting"
+ ],
+ "responses": {
+ "200": {
+ "description": "JSON Web Key Set",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/JwksResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/settings/test_secret_backend": {
+ "post": {
+ "summary": "test secret backend connection (HashiCorp Vault)",
+ "operationId": "testSecretBackend",
+ "tags": [
+ "setting"
+ ],
+ "requestBody": {
+ "description": "Vault settings to test",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/VaultSettings"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "connection successful",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/settings/migrate_secrets_to_vault": {
+ "post": {
+ "summary": "migrate secrets from database to HashiCorp Vault",
+ "operationId": "migrateSecretsToVault",
+ "tags": [
+ "setting"
+ ],
+ "requestBody": {
+ "description": "Vault settings for migration target",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/VaultSettings"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "migration report",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SecretMigrationReport"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/settings/migrate_secrets_to_database": {
+ "post": {
+ "summary": "migrate secrets from HashiCorp Vault to database",
+ "operationId": "migrateSecretsToDatabase",
+ "tags": [
+ "setting"
+ ],
+ "requestBody": {
+ "description": "Vault settings for migration source",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/VaultSettings"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "migration report",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SecretMigrationReport"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/users/email": {
"get": {
"summary": "get current user email (if logged in)",
@@ -1829,6 +2462,9 @@
"properties": {
"progress": {
"type": "integer"
+ },
+ "skipped_all": {
+ "type": "boolean"
}
}
}
@@ -1853,6 +2489,9 @@
"properties": {
"progress": {
"type": "integer"
+ },
+ "skipped_all": {
+ "type": "boolean"
}
}
}
@@ -1939,9 +2578,6 @@
"endpoint_sync": {
"type": "string"
},
- "endpoint_openai_sync": {
- "type": "string"
- },
"summary": {
"type": "string"
},
@@ -1956,7 +2592,6 @@
"workspace",
"endpoint_async",
"endpoint_sync",
- "endpoint_openai_sync",
"summary",
"kind"
]
@@ -2363,6 +2998,10 @@
},
"operator": {
"type": "boolean"
+ },
+ "parent_workspace_id": {
+ "type": "string",
+ "nullable": true
}
},
"required": [
@@ -2559,6 +3198,14 @@
"parameters": [
{
"$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "only_delete_forks",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "boolean"
+ }
}
],
"responses": {
@@ -2827,6 +3474,76 @@
}
}
},
+ "/w/{workspace}/workspaces/compare/{target_workspace_id}": {
+ "get": {
+ "operationId": "compareWorkspaces",
+ "summary": "Compare two workspaces",
+ "description": "Compares the current workspace with a target workspace to find differences in scripts, flows, apps, resources, and variables. Returns information about items that are ahead, behind, or in conflict.",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "target_workspace_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "description": "The ID of the workspace to compare with"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Workspace comparison results",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/WorkspaceComparison"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspaces/reset_diff_tally/{fork_workspace_id}": {
+ "post": {
+ "operationId": "resetDiffTally",
+ "summary": "Resets the ahead and behind deployement counter after a deployement",
+ "description": "This endpoint should be called after a fork deployement",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "fork_workspace_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "description": "The ID of the workspace to compare with"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "status",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ }
+ }
+ },
"/users/exists/{email}": {
"get": {
"summary": "exists email",
@@ -2959,6 +3676,12 @@
"slack_command_script": {
"type": "string"
},
+ "slack_oauth_client_id": {
+ "type": "string"
+ },
+ "slack_oauth_client_secret": {
+ "type": "string"
+ },
"teams_team_id": {
"type": "string"
},
@@ -2968,14 +3691,11 @@
"teams_team_name": {
"type": "string"
},
- "auto_invite_domain": {
+ "teams_team_guid": {
"type": "string"
},
- "auto_invite_operator": {
- "type": "boolean"
- },
- "auto_add": {
- "type": "boolean"
+ "auto_invite": {
+ "$ref": "#/components/schemas/AutoInviteConfig"
},
"plan": {
"type": "string"
@@ -2993,13 +3713,10 @@
"$ref": "#/components/schemas/AIConfig"
},
"error_handler": {
- "type": "string"
+ "$ref": "#/components/schemas/ErrorHandlerConfig"
},
- "error_handler_extra_args": {
- "$ref": "#/components/schemas/ScriptArgs"
- },
- "error_handler_muted_on_cancel": {
- "type": "boolean"
+ "success_handler": {
+ "$ref": "#/components/schemas/SuccessHandlerConfig"
},
"large_file_storage": {
"$ref": "#/components/schemas/LargeFileStorage"
@@ -3007,6 +3724,9 @@
"ducklake": {
"$ref": "#/components/schemas/DucklakeSettings"
},
+ "datatable": {
+ "$ref": "#/components/schemas/DataTableSettings"
+ },
"git_sync": {
"$ref": "#/components/schemas/WorkspaceGitSyncSettings"
},
@@ -3027,11 +3747,12 @@
},
"operator_settings": {
"$ref": "#/components/schemas/OperatorSettings"
+ },
+ "public_app_execution_limit_per_minute": {
+ "type": "integer",
+ "description": "Rate limit for public app executions per minute per server. NULL or 0 means disabled."
}
- },
- "required": [
- "error_handler_muted_on_cancel"
- ]
+ }
}
}
}
@@ -3106,6 +3827,14 @@
"parameters": [
{
"$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "skip_subscription_fetch",
+ "in": "query",
+ "description": "skip fetching subscription status from stripe",
+ "schema": {
+ "type": "boolean"
+ }
}
],
"responses": {
@@ -3127,11 +3856,18 @@
},
"status": {
"type": "string"
+ },
+ "is_past_due": {
+ "type": "boolean"
+ },
+ "max_tolerated_executions": {
+ "type": "number"
}
},
"required": [
"premium",
- "owner"
+ "owner",
+ "is_past_due"
]
}
}
@@ -3215,6 +3951,142 @@
}
}
},
+ "/w/{workspace}/workspaces/rebuild_dependency_map": {
+ "post": {
+ "summary": "rebuild dependency map",
+ "operationId": "rebuildDependencyMap",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "status",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspaces/get_dependents/{imported_path}": {
+ "get": {
+ "summary": "get dependents of an imported path",
+ "operationId": "getDependents",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "imported_path",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "description": "The imported path to get dependents for"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "list of dependents",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/DependencyDependent"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspaces/get_dependents_amounts": {
+ "post": {
+ "summary": "get dependents amounts for multiple imported paths",
+ "operationId": "getDependentsAmounts",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "List of imported paths to get dependents counts for",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "list of dependents amounts",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/DependentsAmount"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspaces/get_dependency_map": {
+ "get": {
+ "summary": "get dependency map",
+ "operationId": "getDependencyMap",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "dmap",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/DependencyMap"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/workspaces/edit_slack_command": {
"post": {
"summary": "edit slack command",
@@ -3257,6 +4129,114 @@
}
}
},
+ "/w/{workspace}/workspaces/slack_oauth_config": {
+ "get": {
+ "summary": "get workspace slack oauth config",
+ "operationId": "getWorkspaceSlackOauthConfig",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "slack oauth config",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "slack_oauth_client_id": {
+ "type": "string",
+ "nullable": true
+ },
+ "slack_oauth_client_secret": {
+ "type": "string",
+ "nullable": true,
+ "description": "Masked with *** if set"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "summary": "set workspace slack oauth config",
+ "operationId": "setWorkspaceSlackOauthConfig",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "Slack OAuth Configuration",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "slack_oauth_client_id",
+ "slack_oauth_client_secret"
+ ],
+ "properties": {
+ "slack_oauth_client_id": {
+ "type": "string"
+ },
+ "slack_oauth_client_secret": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "status",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "summary": "delete workspace slack oauth config",
+ "operationId": "deleteWorkspaceSlackOauthConfig",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "status",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/workspaces/edit_teams_command": {
"post": {
"summary": "edit teams command",
@@ -3309,6 +4289,24 @@
"parameters": [
{
"$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Search teams by name. If omitted, returns first page of all teams.",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "next_link",
+ "in": "query",
+ "description": "Pagination cursor URL from previous response. Pass this to fetch the next page of results.",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
}
],
"responses": {
@@ -3317,16 +4315,34 @@
"content": {
"application/json": {
"schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "team_name": {
- "type": "string"
- },
- "team_id": {
- "type": "string"
+ "type": "object",
+ "properties": {
+ "teams": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "team_name": {
+ "type": "string"
+ },
+ "team_id": {
+ "type": "string"
+ }
+ }
}
+ },
+ "total_count": {
+ "type": "integer",
+ "description": "Total number of teams across all pages"
+ },
+ "per_page": {
+ "type": "integer",
+ "description": "Number of teams per page (configurable via TEAMS_PER_PAGE env var)"
+ },
+ "next_link": {
+ "type": "string",
+ "nullable": true,
+ "description": "URL to fetch next page of results. Null if no more pages."
}
}
}
@@ -3338,7 +4354,7 @@
},
"/w/{workspace}/workspaces/available_teams_channels": {
"get": {
- "summary": "list available teams channels",
+ "summary": "list available channels for a specific team",
"operationId": "listAvailableTeamsChannels",
"tags": [
"workspace"
@@ -3346,30 +4362,41 @@
"parameters": [
{
"$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "team_id",
+ "in": "query",
+ "description": "Microsoft Teams team ID",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
}
],
"responses": {
"200": {
- "description": "status",
+ "description": "List of channels for the specified team",
"content": {
"application/json": {
"schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "channel_name": {
- "type": "string"
- },
- "channel_id": {
- "type": "string"
- },
- "service_url": {
- "type": "string"
- },
- "tenant_id": {
- "type": "string"
+ "type": "object",
+ "properties": {
+ "channels": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "channel_name": {
+ "type": "string"
+ },
+ "channel_id": {
+ "type": "string"
+ }
+ }
}
+ },
+ "total_count": {
+ "type": "integer"
}
}
}
@@ -3619,6 +4646,57 @@
}
}
},
+ "/w/{workspace}/workspaces/edit_instance_groups": {
+ "post": {
+ "summary": "edit instance groups",
+ "operationId": "editInstanceGroups",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "Instance Groups Configuration",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "roles": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "status",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/workspaces/edit_webhook": {
"post": {
"summary": "edit webhook",
@@ -3742,21 +4820,47 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "error_handler": {
- "type": "string"
- },
- "error_handler_extra_args": {
- "$ref": "#/components/schemas/ScriptArgs"
- },
- "error_handler_muted_on_cancel": {
- "type": "boolean"
- }
+ "$ref": "#/components/schemas/EditErrorHandler"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "status",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
}
}
}
}
+ }
+ }
+ },
+ "/w/{workspace}/workspaces/edit_success_handler": {
+ "post": {
+ "summary": "edit success handler",
+ "operationId": "editSuccessHandler",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "WorkspaceSuccessHandler",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/EditSuccessHandler"
+ }
+ }
+ }
},
"responses": {
"200": {
@@ -3841,6 +4945,64 @@
}
}
},
+ "/w/{workspace}/workspaces/list_datatables": {
+ "get": {
+ "summary": "list Datatables",
+ "operationId": "listDataTables",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "status",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspaces/list_datatable_schemas": {
+ "get": {
+ "summary": "list schemas of all connected Datatables",
+ "operationId": "listDataTableSchemas",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "schemas of all datatables",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/DataTableSchema"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/workspaces/edit_ducklake_config": {
"post": {
"summary": "edit ducklake settings",
@@ -3884,6 +5046,49 @@
}
}
},
+ "/w/{workspace}/workspaces/edit_datatable_config": {
+ "post": {
+ "summary": "edit datatable settings",
+ "operationId": "editDataTableConfig",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "DataTable settings",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "settings"
+ ],
+ "properties": {
+ "settings": {
+ "$ref": "#/components/schemas/DataTableSettings"
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "status",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/workspaces/edit_git_sync_config": {
"post": {
"summary": "edit workspace git sync settings",
@@ -4317,32 +5522,6 @@
}
}
},
- "/w/{workspace}/workspaces/get_large_file_storage_config": {
- "get": {
- "summary": "get large file storage config",
- "operationId": "getLargeFileStorageConfig",
- "tags": [
- "workspace"
- ],
- "parameters": [
- {
- "$ref": "#/components/parameters/WorkspaceId"
- }
- ],
- "responses": {
- "200": {
- "description": "status",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LargeFileStorage"
- }
- }
- }
- }
- }
- }
- },
"/w/{workspace}/workspaces/usage": {
"get": {
"summary": "get usage",
@@ -4412,6 +5591,12 @@
},
"sqs_used": {
"type": "boolean"
+ },
+ "email_used": {
+ "type": "boolean"
+ },
+ "nextcloud_used": {
+ "type": "boolean"
}
},
"required": [
@@ -4422,7 +5607,9 @@
"postgres_used",
"mqtt_used",
"gcp_used",
- "sqs_used"
+ "sqs_used",
+ "email_used",
+ "nextcloud_used"
]
}
}
@@ -4728,6 +5915,13 @@
"schema": {
"type": "string"
}
+ },
+ {
+ "name": "expires_in",
+ "in": "query",
+ "schema": {
+ "type": "number"
+ }
}
],
"responses": {
@@ -4857,6 +6051,57 @@
}
}
},
+ "/w/{workspace}/variables/delete_bulk": {
+ "delete": {
+ "summary": "delete variables in bulk",
+ "operationId": "deleteVariablesBulk",
+ "tags": [
+ "variable"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "paths to delete",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "paths": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "paths"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "deleted paths",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/variables/update/{path}": {
"post": {
"summary": "update variable",
@@ -4965,6 +6210,14 @@
},
{
"$ref": "#/components/parameters/Path"
+ },
+ {
+ "name": "allow_cache",
+ "description": "allow getting a cached value for improved performance\n",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
}
],
"responses": {
@@ -5093,6 +6346,16 @@
"parameters": [
{
"$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "include_default",
+ "in": "query",
+ "description": "If true, include \"_default_\" in the list if primary workspace storage is set",
+ "required": false,
+ "schema": {
+ "type": "boolean",
+ "default": false
+ }
}
],
"responses": {
@@ -5292,6 +6555,241 @@
}
}
},
+ "/w/{workspace}/workspaces/protection_rules": {
+ "get": {
+ "summary": "list all protection rules for a workspace",
+ "operationId": "listProtectionRules",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "list of protection rules",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ProtectionRuleset"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "summary": "create a new protection rule",
+ "operationId": "createProtectionRule",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "New protection rule configuration",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "name",
+ "rules",
+ "bypass_groups",
+ "bypass_users"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Unique name for the protection rule",
+ "example": "Production Protection"
+ },
+ "rules": {
+ "$ref": "#/components/schemas/ProtectionRules"
+ },
+ "bypass_groups": {
+ "$ref": "#/components/schemas/RuleBypasserGroups"
+ },
+ "bypass_users": {
+ "$ref": "#/components/schemas/RuleBypasserUsers"
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "protection rule created successfully",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "rule with this name already exists"
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspaces/protection_rules/{rule_name}": {
+ "post": {
+ "summary": "update an existing protection rule",
+ "operationId": "updateProtectionRule",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "rule_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "description": "Name of the protection rule to update"
+ }
+ ],
+ "requestBody": {
+ "description": "Updated protection rule configuration",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "rules",
+ "bypass_groups",
+ "bypass_users"
+ ],
+ "properties": {
+ "rules": {
+ "$ref": "#/components/schemas/ProtectionRules"
+ },
+ "bypass_groups": {
+ "$ref": "#/components/schemas/RuleBypasserGroups"
+ },
+ "bypass_users": {
+ "$ref": "#/components/schemas/RuleBypasserUsers"
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "protection rule updated successfully",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "protection rule not found"
+ }
+ }
+ },
+ "delete": {
+ "summary": "delete a protection rule",
+ "operationId": "deleteProtectionRule",
+ "tags": [
+ "workspace"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "rule_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "description": "Name of the protection rule to delete"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "protection rule deleted successfully",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "protection rule not found"
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspaces/public_app_rate_limit": {
+ "post": {
+ "summary": "Set public app rate limit for this workspace",
+ "operationId": "setPublicAppRateLimit",
+ "tags": [
+ "setting"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "Public app rate limit configuration",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "public_app_execution_limit_per_minute": {
+ "type": "integer",
+ "description": "Rate limit for public app executions per minute per server. NULL or 0 to disable.",
+ "example": 100
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successfully updated public app rate limit settings.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string",
+ "example": "Updated public app rate limit for workspace: workspace_id"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/oauth/login_callback/{client_name}": {
"post": {
"security": [],
@@ -5509,7 +7007,8 @@
"type": "object",
"properties": {
"refresh_token": {
- "type": "string"
+ "type": "string",
+ "description": "OAuth refresh token. For authorization_code flow, this contains the actual refresh token. For client_credentials flow, this must be set to an empty string."
},
"expires_in": {
"type": "integer"
@@ -5532,9 +7031,14 @@
"cc_token_url": {
"type": "string",
"description": "OAuth token URL override for resource-level authentication (client_credentials flow only)"
+ },
+ "mcp_server_url": {
+ "type": "string",
+ "description": "MCP server URL for MCP OAuth token refresh"
}
},
"required": [
+ "refresh_token",
"expires_in",
"client"
]
@@ -5871,30 +7375,6 @@
}
}
},
- "/teams/sync": {
- "post": {
- "operationId": "syncTeams",
- "summary": "synchronize Microsoft Teams information (teams/channels)",
- "tags": [
- "teams"
- ],
- "responses": {
- "200": {
- "description": "Teams information successfully synchronized",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/TeamInfo"
- }
- }
- }
- }
- }
- }
- }
- },
"/teams/activities": {
"post": {
"summary": "send update to Microsoft Teams activity",
@@ -6019,6 +7499,57 @@
}
}
},
+ "/w/{workspace}/resources/delete_bulk": {
+ "delete": {
+ "summary": "delete resources in bulk",
+ "operationId": "deleteResourcesBulk",
+ "tags": [
+ "resource"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "paths to delete",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "paths": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "paths"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "deleted paths",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/resources/update/{path}": {
"post": {
"summary": "update resource",
@@ -6155,6 +7686,14 @@
"type": "string",
"format": "uuid"
}
+ },
+ {
+ "name": "allow_cache",
+ "description": "allow getting a cached value for improved performance",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
}
],
"responses": {
@@ -6196,6 +7735,51 @@
}
}
},
+ "/w/{workspace}/resources/git_commit_hash/{path}": {
+ "get": {
+ "summary": "get git repository latest commit hash",
+ "operationId": "getGitCommitHash",
+ "tags": [
+ "resource"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Path"
+ },
+ {
+ "name": "git_ssh_identity",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "git commit hash",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "commit_hash": {
+ "type": "string",
+ "description": "Latest commit hash from git ls-remote"
+ }
+ },
+ "required": [
+ "commit_hash"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/resources/exists/{path}": {
"get": {
"summary": "does resource exists",
@@ -6324,6 +7908,53 @@
}
}
},
+ "/w/{workspace}/resources/mcp_tools/{path}": {
+ "get": {
+ "summary": "get MCP tools from resource",
+ "operationId": "getMcpTools",
+ "tags": [
+ "resource"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "list of MCP tools",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "parameters": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "name",
+ "parameters"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/resources/list_names/{name}": {
"get": {
"summary": "list resource names",
@@ -6615,6 +8246,218 @@
}
}
},
+ "/w/{workspace}/npm_proxy/metadata/{package}": {
+ "get": {
+ "summary": "get npm package metadata from private registry",
+ "operationId": "getNpmPackageMetadata",
+ "tags": [
+ "npm_proxy"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "package",
+ "description": "npm package name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "package metadata",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "tags": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "versions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/npm_proxy/resolve/{package}": {
+ "get": {
+ "summary": "resolve npm package version from private registry",
+ "operationId": "resolveNpmPackageVersion",
+ "tags": [
+ "npm_proxy"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "package",
+ "description": "npm package name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "tag",
+ "description": "version tag or reference",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "resolved version",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "string",
+ "nullable": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/npm_proxy/filetree/{package}/{version}": {
+ "get": {
+ "summary": "get npm package file tree from private registry",
+ "operationId": "getNpmPackageFiletree",
+ "tags": [
+ "npm_proxy"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "package",
+ "description": "npm package name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "version",
+ "description": "package version",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "package file tree",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "default": {
+ "type": "string"
+ },
+ "files": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/npm_proxy/file/{package}/{version}/{filepath}": {
+ "get": {
+ "summary": "get specific file from npm package in private registry",
+ "operationId": "getNpmPackageFile",
+ "tags": [
+ "npm_proxy"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "package",
+ "description": "npm package name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "version",
+ "description": "package version",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "filepath",
+ "description": "file path within package",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "file content",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/embeddings/query_resource_types": {
"get": {
"summary": "query resource types by similarity",
@@ -6913,6 +8756,50 @@
}
}
},
+ "/apps/hub/get_raw/{id}": {
+ "get": {
+ "summary": "get hub raw app by id",
+ "operationId": "getHubRawAppById",
+ "tags": [
+ "app"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/PathId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "raw app",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "app": {
+ "type": "object",
+ "properties": {
+ "summary": {
+ "type": "string"
+ },
+ "value": {}
+ },
+ "required": [
+ "summary",
+ "value"
+ ]
+ }
+ },
+ "required": [
+ "app"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/apps_u/public_app_by_custom_path/{custom_path}": {
"get": {
"summary": "get public app by custom path",
@@ -7022,6 +8909,40 @@
}
}
},
+ "/scripts/hub/pick/{path}": {
+ "get": {
+ "summary": "record hub script pick",
+ "operationId": "pickHubScriptByPath",
+ "tags": [
+ "script"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/ScriptPath"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "script pick recorded",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "success"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/scripts/hub/top": {
"get": {
"summary": "get top hub scripts",
@@ -7378,6 +9299,22 @@
"schema": {
"type": "string"
}
+ },
+ {
+ "name": "without_description",
+ "in": "query",
+ "description": "(default false)\nIf true, the description field will be omitted from the response.\n",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ {
+ "name": "dedicated_worker",
+ "in": "query",
+ "description": "(default regardless)\nIf true, show only scripts with dedicated_worker enabled.\nIf false, show only scripts with dedicated_worker disabled.\n",
+ "schema": {
+ "type": "boolean"
+ }
}
],
"responses": {
@@ -7527,6 +9464,18 @@
"post": {
"summary": "create script",
"operationId": "createScript",
+ "x-mcp-tool": true,
+ "x-mcp-instructions": "To create a script, specify the path (e.g., 'f/my_folder/my_script'), the content (source code), and the language. For TypeScript, use 'bun' unless deno-specific APIs are needed.",
+ "x-mcp-tool-include-fields": [
+ "path",
+ "content",
+ "language",
+ "summary",
+ "description",
+ "kind",
+ "tag",
+ "deployment_message"
+ ],
"tags": [
"script"
],
@@ -7613,14 +9562,6 @@
"worker"
],
"parameters": [
- {
- "name": "workspace",
- "in": "query",
- "schema": {
- "type": "string"
- },
- "required": false
- },
{
"name": "show_workspace_restriction",
"in": "query",
@@ -7647,6 +9588,35 @@
}
}
},
+ "/w/{workspace}/workers/custom_tags": {
+ "get": {
+ "summary": "get custom tags available for this workspace",
+ "operationId": "getCustomTagsForWorkspace",
+ "tags": [
+ "worker"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "list of custom tags for workspace",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/workers/get_default_tags": {
"get": {
"summary": "get all instance default tags",
@@ -7692,6 +9662,194 @@
}
}
},
+ "/w/{workspace}/workspace_dependencies/create": {
+ "post": {
+ "summary": "create workspace dependencies",
+ "operationId": "createWorkspaceDependencies",
+ "tags": [
+ "workspace_dependencies"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "New workspace dependencies",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NewWorkspaceDependencies"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "workspace dependencies created",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspace_dependencies/archive/{language}": {
+ "post": {
+ "summary": "archive workspace dependencies (require admin)",
+ "operationId": "archiveWorkspaceDependencies",
+ "tags": [
+ "workspace_dependencies"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "language",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ScriptLang"
+ }
+ },
+ {
+ "name": "name",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "result",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspace_dependencies/delete/{language}": {
+ "post": {
+ "summary": "delete workspace dependencies (require admin)",
+ "operationId": "deleteWorkspaceDependencies",
+ "tags": [
+ "workspace_dependencies"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "language",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ScriptLang"
+ }
+ },
+ {
+ "name": "name",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "result",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspace_dependencies/list": {
+ "get": {
+ "summary": "list all workspace dependencies",
+ "operationId": "listWorkspaceDependencies",
+ "tags": [
+ "workspace_dependencies"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "All workspace dependencies",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/WorkspaceDependencies"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/workspace_dependencies/get_latest/{language}": {
+ "get": {
+ "summary": "get latest workspace dependencies by language and name",
+ "operationId": "getLatestWorkspaceDependencies",
+ "tags": [
+ "workspace_dependencies"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "language",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ScriptLang"
+ }
+ },
+ {
+ "name": "name",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Latest workspace dependencies",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/WorkspaceDependencies"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/scripts/archive/p/{path}": {
"post": {
"summary": "archive script by path",
@@ -7754,6 +9912,7 @@
"post": {
"summary": "delete script by hash (erase content but keep hash, require admin)",
"operationId": "deleteScriptByHash",
+ "x-mcp-tool": true,
"tags": [
"script"
],
@@ -7783,6 +9942,7 @@
"post": {
"summary": "delete script at a given path (require admin)",
"operationId": "deleteScriptByPath",
+ "x-mcp-tool": true,
"tags": [
"script"
],
@@ -7816,6 +9976,57 @@
}
}
},
+ "/w/{workspace}/scripts/delete_bulk": {
+ "delete": {
+ "summary": "delete scripts in bulk",
+ "operationId": "deleteScriptsBulk",
+ "tags": [
+ "script"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "paths to delete",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "paths": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "paths"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "deleted paths",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/scripts/get/p/{path}": {
"get": {
"summary": "get script by path",
@@ -8274,6 +10485,10 @@
},
"lock_error_logs": {
"type": "string"
+ },
+ "job_id": {
+ "type": "string",
+ "format": "uuid"
}
}
}
@@ -8377,6 +10592,9 @@
"post": {
"summary": "run script by path",
"operationId": "runScriptByPath",
+ "x-mcp-tool": true,
+ "x-mcp-instructions": "You should first use getScriptByPath to retrieve the script's schema and understand what arguments are expected.",
+ "x-mcp-tool-include-query-params": [],
"tags": [
"job"
],
@@ -8459,56 +10677,6 @@
}
}
},
- "/w/{workspace}/jobs/openai_sync/p/{path}": {
- "post": {
- "summary": "run script by path in openai format",
- "operationId": "openaiSyncScriptByPath",
- "tags": [
- "job"
- ],
- "parameters": [
- {
- "$ref": "#/components/parameters/WorkspaceId"
- },
- {
- "$ref": "#/components/parameters/ScriptPath"
- },
- {
- "$ref": "#/components/parameters/ParentJob"
- },
- {
- "$ref": "#/components/parameters/NewJobId"
- },
- {
- "$ref": "#/components/parameters/IncludeHeader"
- },
- {
- "$ref": "#/components/parameters/QueueLimit"
- }
- ],
- "requestBody": {
- "description": "script args",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ScriptArgs"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "job result",
- "content": {
- "application/json": {
- "schema": {}
- }
- }
- }
- }
- }
- },
"/w/{workspace}/jobs/run_wait_result/p/{path}": {
"post": {
"summary": "run script by path",
@@ -8540,6 +10708,9 @@
},
{
"$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
}
],
"requestBody": {
@@ -8597,6 +10768,9 @@
},
{
"$ref": "#/components/parameters/Payload"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
}
],
"responses": {
@@ -8611,53 +10785,6 @@
}
}
},
- "/w/{workspace}/jobs/openai_sync/f/{path}": {
- "post": {
- "summary": "run flow by path and wait until completion in openai format",
- "operationId": "openaiSyncFlowByPath",
- "tags": [
- "job"
- ],
- "parameters": [
- {
- "$ref": "#/components/parameters/WorkspaceId"
- },
- {
- "$ref": "#/components/parameters/ScriptPath"
- },
- {
- "$ref": "#/components/parameters/IncludeHeader"
- },
- {
- "$ref": "#/components/parameters/QueueLimit"
- },
- {
- "$ref": "#/components/parameters/NewJobId"
- }
- ],
- "requestBody": {
- "description": "script args",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ScriptArgs"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "job result",
- "content": {
- "application/json": {
- "schema": {}
- }
- }
- }
- }
- }
- },
"/w/{workspace}/jobs/run_wait_result/f/{path}": {
"post": {
"summary": "run flow by path and wait until completion",
@@ -8680,6 +10807,18 @@
},
{
"$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
}
],
"requestBody": {
@@ -8705,6 +10844,672 @@
}
}
},
+ "/w/{workspace}/jobs/run_wait_result/fv/{version}": {
+ "post": {
+ "summary": "run flow by version and wait until completion",
+ "operationId": "runWaitResultFlowByVersion",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "version",
+ "description": "flow version ID",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "script args",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "job result",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ }
+ },
+ "get": {
+ "summary": "run flow by version with GET and wait until completion",
+ "operationId": "runWaitResultFlowByVersionGet",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "version",
+ "description": "flow version ID",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/Payload"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "job result",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/run_and_stream/f/{path}": {
+ "post": {
+ "summary": "run flow by path and stream updates via SSE",
+ "operationId": "runAndStreamFlowByPath",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/ScriptPath"
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ },
+ {
+ "name": "poll_delay_ms",
+ "description": "delay between polling for job updates in milliseconds",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "flow args",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "server-sent events stream of job updates",
+ "content": {
+ "text/event-stream": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "get": {
+ "summary": "run flow by path with GET and stream updates via SSE",
+ "operationId": "runAndStreamFlowByPathGet",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/ScriptPath"
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/Payload"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ },
+ {
+ "name": "poll_delay_ms",
+ "description": "delay between polling for job updates in milliseconds",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "server-sent events stream of job updates",
+ "content": {
+ "text/event-stream": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/run_and_stream/fv/{version}": {
+ "post": {
+ "summary": "run flow by version and stream updates via SSE",
+ "operationId": "runAndStreamFlowByVersion",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "version",
+ "description": "flow version ID",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ },
+ {
+ "name": "poll_delay_ms",
+ "description": "delay between polling for job updates in milliseconds",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "flow args",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "server-sent events stream of job updates",
+ "content": {
+ "text/event-stream": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "get": {
+ "summary": "run flow by version with GET and stream updates via SSE",
+ "operationId": "runAndStreamFlowByVersionGet",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "version",
+ "description": "flow version ID",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/Payload"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ },
+ {
+ "name": "poll_delay_ms",
+ "description": "delay between polling for job updates in milliseconds",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "server-sent events stream of job updates",
+ "content": {
+ "text/event-stream": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/run_and_stream/p/{path}": {
+ "post": {
+ "summary": "run script by path and stream updates via SSE",
+ "operationId": "runAndStreamScriptByPath",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/ScriptPath"
+ },
+ {
+ "$ref": "#/components/parameters/ParentJob"
+ },
+ {
+ "$ref": "#/components/parameters/WorkerTag"
+ },
+ {
+ "$ref": "#/components/parameters/CacheTtl"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "poll_delay_ms",
+ "description": "delay between polling for job updates in milliseconds",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "script args",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "server-sent events stream of job updates",
+ "content": {
+ "text/event-stream": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "get": {
+ "summary": "run script by path with GET and stream updates via SSE",
+ "operationId": "runAndStreamScriptByPathGet",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/ScriptPath"
+ },
+ {
+ "$ref": "#/components/parameters/ParentJob"
+ },
+ {
+ "$ref": "#/components/parameters/WorkerTag"
+ },
+ {
+ "$ref": "#/components/parameters/CacheTtl"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/Payload"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "poll_delay_ms",
+ "description": "delay between polling for job updates in milliseconds",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "server-sent events stream of job updates",
+ "content": {
+ "text/event-stream": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/run_and_stream/h/{hash}": {
+ "post": {
+ "summary": "run script by hash and stream updates via SSE",
+ "operationId": "runAndStreamScriptByHash",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "hash",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/ParentJob"
+ },
+ {
+ "$ref": "#/components/parameters/WorkerTag"
+ },
+ {
+ "$ref": "#/components/parameters/CacheTtl"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "poll_delay_ms",
+ "description": "delay between polling for job updates in milliseconds",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "script args",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "server-sent events stream of job updates",
+ "content": {
+ "text/event-stream": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "get": {
+ "summary": "run script by hash with GET and stream updates via SSE",
+ "operationId": "runAndStreamScriptByHashGet",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "hash",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/ParentJob"
+ },
+ {
+ "$ref": "#/components/parameters/WorkerTag"
+ },
+ {
+ "$ref": "#/components/parameters/CacheTtl"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "$ref": "#/components/parameters/QueueLimit"
+ },
+ {
+ "$ref": "#/components/parameters/Payload"
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "name": "poll_delay_ms",
+ "description": "delay between polling for job updates in milliseconds",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "server-sent events stream of job updates",
+ "content": {
+ "text/event-stream": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/jobs/result_by_id/{flow_job_id}/{node_id}": {
"get": {
"summary": "get job result by id",
@@ -8884,6 +11689,22 @@
"schema": {
"type": "boolean"
}
+ },
+ {
+ "name": "without_description",
+ "in": "query",
+ "description": "(default false)\nIf true, the description field will be omitted from the response.\n",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ {
+ "name": "dedicated_worker",
+ "in": "query",
+ "description": "(default regardless)\nIf true, show only flows with dedicated_worker enabled.\nIf false, show only flows with dedicated_worker disabled.\n",
+ "schema": {
+ "type": "boolean"
+ }
}
],
"responses": {
@@ -8995,6 +11816,13 @@
},
{
"$ref": "#/components/parameters/ScriptPath"
+ },
+ {
+ "name": "match_path_start",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
}
],
"responses": {
@@ -9014,7 +11842,7 @@
}
}
},
- "/w/{workspace}/flows/get/v/{version}/p/{path}": {
+ "/w/{workspace}/flows/get/v/{version}": {
"get": {
"summary": "get flow version",
"operationId": "getFlowVersion",
@@ -9029,9 +11857,6 @@
"schema": {
"type": "number"
}
- },
- {
- "$ref": "#/components/parameters/ScriptPath"
}
],
"tags": [
@@ -9051,7 +11876,7 @@
}
}
},
- "/w/{workspace}/flows/history_update/v/{version}/p/{path}": {
+ "/w/{workspace}/flows/history_update/v/{version}": {
"post": {
"summary": "update flow history",
"operationId": "updateFlowHistory",
@@ -9066,9 +11891,6 @@
"schema": {
"type": "number"
}
- },
- {
- "$ref": "#/components/parameters/ScriptPath"
}
],
"requestBody": {
@@ -9169,6 +11991,10 @@
"properties": {
"lock_error_logs": {
"type": "string"
+ },
+ "job_id": {
+ "type": "string",
+ "format": "uuid"
}
}
}
@@ -9358,6 +12184,20 @@
"post": {
"summary": "create flow",
"operationId": "createFlow",
+ "x-mcp-tool": true,
+ "x-mcp-tool-include-fields": [
+ "path",
+ "summary",
+ "description",
+ "value",
+ "schema",
+ "tag",
+ "deployment_message"
+ ],
+ "x-mcp-tool-opaque-fields": [
+ "value",
+ "schema"
+ ],
"tags": [
"flow"
],
@@ -9410,6 +12250,20 @@
"post": {
"summary": "update flow",
"operationId": "updateFlow",
+ "x-mcp-tool": true,
+ "x-mcp-tool-include-fields": [
+ "path",
+ "summary",
+ "description",
+ "value",
+ "schema",
+ "tag",
+ "deployment_message"
+ ],
+ "x-mcp-tool-opaque-fields": [
+ "value",
+ "schema"
+ ],
"tags": [
"flow"
],
@@ -9507,6 +12361,7 @@
"delete": {
"summary": "delete flow by path",
"operationId": "deleteFlowByPath",
+ "x-mcp-tool": true,
"tags": [
"flow"
],
@@ -9540,6 +12395,140 @@
}
}
},
+ "/w/{workspace}/flow_conversations/list": {
+ "get": {
+ "summary": "list flow conversations",
+ "operationId": "listFlowConversations",
+ "tags": [
+ "flow_conversation"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Page"
+ },
+ {
+ "$ref": "#/components/parameters/PerPage"
+ },
+ {
+ "name": "flow_path",
+ "description": "filter conversations by flow path",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "flow conversations list",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/FlowConversation"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/flow_conversations/delete/{conversation_id}": {
+ "delete": {
+ "summary": "delete flow conversation",
+ "operationId": "deleteFlowConversation",
+ "tags": [
+ "flow_conversation"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "conversation_id",
+ "description": "conversation id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "flow conversation deleted",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/flow_conversations/{conversation_id}/messages": {
+ "get": {
+ "summary": "list conversation messages",
+ "operationId": "listConversationMessages",
+ "tags": [
+ "flow_conversation"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Page"
+ },
+ {
+ "$ref": "#/components/parameters/PerPage"
+ },
+ {
+ "name": "conversation_id",
+ "description": "conversation id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ },
+ {
+ "name": "after_id",
+ "description": "id to fetch only the messages after that id",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "conversation messages",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/FlowConversationMessage"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/raw_apps/list": {
"get": {
"summary": "list all raw apps",
@@ -9605,51 +12594,24 @@
}
}
},
- "/w/{workspace}/raw_apps/exists/{path}": {
+ "/w/{workspace}/apps/get_data/v/{secretWithExtension}": {
"get": {
- "summary": "does an app exisst at path",
- "operationId": "existsRawApp",
- "tags": [
- "raw_app"
- ],
- "parameters": [
- {
- "$ref": "#/components/parameters/WorkspaceId"
- },
- {
- "$ref": "#/components/parameters/Path"
- }
- ],
- "responses": {
- "200": {
- "description": "app exists",
- "content": {
- "application/json": {
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
- }
- },
- "/w/{workspace}/apps/get_data/{version}/{path}": {
- "get": {
- "summary": "get app by path",
+ "summary": "get raw app data by",
"operationId": "getRawAppData",
"tags": [
- "raw_app"
+ "app"
],
"parameters": [
{
"$ref": "#/components/parameters/WorkspaceId"
},
{
- "$ref": "#/components/parameters/VersionId"
- },
- {
- "$ref": "#/components/parameters/ScriptPath"
+ "name": "secretWithExtension",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
}
],
"responses": {
@@ -9790,6 +12752,18 @@
"post": {
"summary": "create app",
"operationId": "createApp",
+ "x-mcp-tool": true,
+ "x-mcp-tool-include-fields": [
+ "path",
+ "value",
+ "summary",
+ "policy",
+ "deployment_message"
+ ],
+ "x-mcp-tool-opaque-fields": [
+ "value",
+ "policy"
+ ],
"tags": [
"app"
],
@@ -10277,6 +13251,35 @@
}
}
},
+ "/w/{workspace}/apps/secret_of_latest_version/{path}": {
+ "get": {
+ "summary": "get public secret of latest version of an app bundle",
+ "operationId": "getPublicSecretOfLatestVersionOfApp",
+ "tags": [
+ "app"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "app secret",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/apps/get/v/{id}": {
"get": {
"summary": "get app by version",
@@ -10306,139 +13309,6 @@
}
}
},
- "/w/{workspace}/raw_apps/create": {
- "post": {
- "summary": "create raw app",
- "operationId": "createRawApp",
- "tags": [
- "raw_app"
- ],
- "parameters": [
- {
- "$ref": "#/components/parameters/WorkspaceId"
- }
- ],
- "requestBody": {
- "description": "new raw app",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "path": {
- "type": "string"
- },
- "value": {
- "type": "string"
- },
- "summary": {
- "type": "string"
- }
- },
- "required": [
- "path",
- "value",
- "summary"
- ]
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "raw app created",
- "content": {
- "text/plain": {
- "schema": {
- "type": "string"
- }
- }
- }
- }
- }
- }
- },
- "/w/{workspace}/raw_apps/update/{path}": {
- "post": {
- "summary": "update app",
- "operationId": "updateRawApp",
- "tags": [
- "raw_app"
- ],
- "parameters": [
- {
- "$ref": "#/components/parameters/WorkspaceId"
- },
- {
- "$ref": "#/components/parameters/ScriptPath"
- }
- ],
- "requestBody": {
- "description": "updateraw app",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "path": {
- "type": "string"
- },
- "summary": {
- "type": "string"
- },
- "value": {
- "type": "string"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "app updated",
- "content": {
- "text/plain": {
- "schema": {
- "type": "string"
- }
- }
- }
- }
- }
- }
- },
- "/w/{workspace}/raw_apps/delete/{path}": {
- "delete": {
- "summary": "delete raw app",
- "operationId": "deleteRawApp",
- "tags": [
- "raw_app"
- ],
- "parameters": [
- {
- "$ref": "#/components/parameters/WorkspaceId"
- },
- {
- "$ref": "#/components/parameters/Path"
- }
- ],
- "responses": {
- "200": {
- "description": "app deleted",
- "content": {
- "text/plain": {
- "schema": {
- "type": "string"
- }
- }
- }
- }
- }
- }
- },
"/w/{workspace}/apps/delete/{path}": {
"delete": {
"summary": "delete app",
@@ -10472,6 +13342,18 @@
"post": {
"summary": "update app",
"operationId": "updateApp",
+ "x-mcp-tool": true,
+ "x-mcp-tool-include-fields": [
+ "path",
+ "value",
+ "summary",
+ "policy",
+ "deployment_message"
+ ],
+ "x-mcp-tool-opaque-fields": [
+ "value",
+ "policy"
+ ],
"tags": [
"app"
],
@@ -10746,6 +13628,10 @@
"items": {
"type": "string"
}
+ },
+ "run_query_params": {
+ "type": "object",
+ "description": "Runnable query parameters"
}
},
"required": [
@@ -10914,6 +13800,9 @@
"post": {
"summary": "run flow by path",
"operationId": "runFlowByPath",
+ "x-mcp-tool": true,
+ "x-mcp-instructions": "You should first use getFlowByPath to retrieve the flow's schema and understand what arguments are expected.",
+ "x-mcp-tool-include-query-params": [],
"tags": [
"job"
],
@@ -10942,12 +13831,7 @@
}
},
{
- "name": "skip_preprocessor",
- "description": "skip the preprocessor",
- "in": "query",
- "schema": {
- "type": "boolean"
- }
+ "$ref": "#/components/parameters/SkipPreprocessor"
},
{
"$ref": "#/components/parameters/ParentJob"
@@ -10968,6 +13852,112 @@
"schema": {
"type": "boolean"
}
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "flow args",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "job created",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/run/fv/{version}": {
+ "post": {
+ "summary": "run flow by version",
+ "operationId": "runFlowByVersion",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "version",
+ "description": "flow version ID",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "scheduled_for",
+ "description": "when to schedule this job (leave empty for immediate run)",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "date-time"
+ }
+ },
+ {
+ "name": "scheduled_in_secs",
+ "description": "schedule the script to execute in the number of seconds starting now",
+ "in": "query",
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/SkipPreprocessor"
+ },
+ {
+ "$ref": "#/components/parameters/ParentJob"
+ },
+ {
+ "$ref": "#/components/parameters/WorkerTag"
+ },
+ {
+ "$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "$ref": "#/components/parameters/IncludeHeader"
+ },
+ {
+ "name": "invisible_to_owner",
+ "description": "make the run invisible to the the flow owner (default false)",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
}
],
"requestBody": {
@@ -11080,7 +14070,7 @@
}
}
},
- "/w/{workspace}/jobs/restart/f/{id}/from/{step_id}/{branch_or_iteration_n}": {
+ "/w/{workspace}/jobs/restart/f/{id}": {
"post": {
"summary": "restart a completed flow at a given step",
"operationId": "restartFlowAtStep",
@@ -11094,24 +14084,6 @@
{
"$ref": "#/components/parameters/JobId"
},
- {
- "name": "step_id",
- "description": "step id to restart the flow from",
- "required": true,
- "in": "path",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "branch_or_iteration_n",
- "description": "for branchall or loop, the iteration at which the flow should restart",
- "required": true,
- "in": "path",
- "schema": {
- "type": "integer"
- }
- },
{
"name": "scheduled_for",
"description": "when to schedule this job (leave empty for immediate run)",
@@ -11151,12 +14123,29 @@
}
],
"requestBody": {
- "description": "flow args",
+ "description": "restart flow parameters",
"required": true,
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "type": "object",
+ "required": [
+ "step_id"
+ ],
+ "properties": {
+ "step_id": {
+ "type": "string",
+ "description": "step id to restart the flow from"
+ },
+ "branch_or_iteration_n": {
+ "type": "integer",
+ "description": "for branchall or loop, the iteration at which the flow should restart (optional)"
+ },
+ "flow_version": {
+ "type": "integer",
+ "description": "specific flow version to use for restart (optional, uses current version if not specified)"
+ }
+ }
}
}
}
@@ -11208,12 +14197,7 @@
}
},
{
- "name": "skip_preprocessor",
- "description": "skip the preprocessor",
- "in": "query",
- "schema": {
- "type": "boolean"
- }
+ "$ref": "#/components/parameters/SkipPreprocessor"
},
{
"$ref": "#/components/parameters/ParentJob"
@@ -11317,6 +14301,83 @@
}
}
},
+ "/w/{workspace}/jobs/run_inline/preview": {
+ "post": {
+ "summary": "run script preview without starting a new job",
+ "operationId": "runScriptPreviewInline",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "preview",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PreviewInline"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "script result",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/run_wait_result/preview": {
+ "post": {
+ "summary": "run script preview and wait for result",
+ "operationId": "runScriptPreviewAndWaitResult",
+ "x-mcp-tool": true,
+ "x-mcp-instructions": "Allows testing a script before deploying it. For typescript code, the language to send is either bun or deno. By default, send bun if no deno specific code is detected.",
+ "x-mcp-required-fields": [
+ "content",
+ "language",
+ "args"
+ ],
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "preview",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Preview"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "job result",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/jobs/workflow_as_code/{job_id}/{entrypoint}": {
"post": {
"summary": "run code-workflow task",
@@ -11455,6 +14516,15 @@
},
{
"$ref": "#/components/parameters/NewJobId"
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
}
],
"requestBody": {
@@ -11483,6 +14553,88 @@
}
}
},
+ "/w/{workspace}/jobs/run_wait_result/preview_flow": {
+ "post": {
+ "summary": "run flow preview and wait for result",
+ "operationId": "runFlowPreviewAndWaitResult",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "memory_id",
+ "description": "memory ID for chat-enabled flows",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "preview",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FlowPreview"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "job result",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/run/dynamic_select": {
+ "post": {
+ "summary": "run dynamic select helper function",
+ "operationId": "runDynamicSelect",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "dynamic select request",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DynamicInputData"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "dynamic select job created",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/jobs/queue/list": {
"get": {
"summary": "list all queued jobs",
@@ -11516,6 +14668,12 @@
{
"$ref": "#/components/parameters/SchedulePath"
},
+ {
+ "$ref": "#/components/parameters/TriggerPath"
+ },
+ {
+ "$ref": "#/components/parameters/JobTriggerKind"
+ },
{
"$ref": "#/components/parameters/ScriptExactHash"
},
@@ -11773,7 +14931,16 @@
"$ref": "#/components/parameters/CreatedAfter"
},
{
- "$ref": "#/components/parameters/CreatedOrStartedBefore"
+ "$ref": "#/components/parameters/CompletedBefore"
+ },
+ {
+ "$ref": "#/components/parameters/CompletedAfter"
+ },
+ {
+ "$ref": "#/components/parameters/CreatedBeforeQueue"
+ },
+ {
+ "$ref": "#/components/parameters/CreatedAfterQueue"
},
{
"$ref": "#/components/parameters/Running"
@@ -11781,12 +14948,6 @@
{
"$ref": "#/components/parameters/ScheduledForBeforeNow"
},
- {
- "$ref": "#/components/parameters/CreatedOrStartedAfter"
- },
- {
- "$ref": "#/components/parameters/CreatedOrStartedAfterCompletedJob"
- },
{
"$ref": "#/components/parameters/JobKinds"
},
@@ -11997,6 +15158,13 @@
"parameters": [
{
"$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "force_cancel",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
}
],
"requestBody": {
@@ -12030,6 +15198,172 @@
}
}
},
+ "/w/{workspace}/jobs/get_otel_traces/{id}": {
+ "get": {
+ "summary": "get OpenTelemetry traces for a job",
+ "operationId": "getJobOtelTraces",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/JobId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "list of OTEL Span objects (compatible with OpenTelemetry Span proto)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/trigger/{trigger_kind}/resume_suspended_trigger_jobs/{trigger_path}": {
+ "post": {
+ "summary": "resume all suspended jobs for a specific trigger",
+ "operationId": "resumeSuspendedTriggerJobs",
+ "tags": [
+ "trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "trigger_kind",
+ "description": "The kind of trigger",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/JobTriggerKind"
+ }
+ },
+ {
+ "name": "trigger_path",
+ "description": "The path of the trigger (can contain forward slashes)",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "style": "simple",
+ "explode": false
+ }
+ ],
+ "requestBody": {
+ "description": "Optional list of job IDs to reassign",
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "job_ids": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "description": "Optional list of specific job UUIDs to reassign. If not provided, all suspended jobs for the trigger will be reassigned."
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "confirmation message",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/trigger/{trigger_kind}/cancel_suspended_trigger_jobs/{trigger_path}": {
+ "post": {
+ "summary": "cancel all suspended jobs for a specific trigger",
+ "operationId": "cancelSuspendedTriggerJobs",
+ "tags": [
+ "trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "trigger_kind",
+ "description": "The kind of trigger",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/JobTriggerKind"
+ }
+ },
+ {
+ "name": "trigger_path",
+ "description": "The path of the trigger (can contain forward slashes)",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "style": "simple",
+ "explode": false
+ }
+ ],
+ "requestBody": {
+ "description": "Optional list of job IDs to cancel",
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "job_ids": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "description": "Optional list of specific job UUIDs to cancel. If not provided, all suspended jobs for the trigger will be canceled."
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "confirmation message",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/jobs/completed/list": {
"get": {
"summary": "list all completed jobs",
@@ -12148,6 +15482,196 @@
}
}
},
+ "/w/{workspace}/jobs/completed/export": {
+ "get": {
+ "summary": "export all completed jobs for backup/migration",
+ "operationId": "exportCompletedJobs",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Page"
+ },
+ {
+ "$ref": "#/components/parameters/PerPage"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "All completed jobs exported",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ExportableCompletedJob"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/completed/import": {
+ "post": {
+ "summary": "import completed jobs from backup/migration",
+ "operationId": "importCompletedJobs",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ExportableCompletedJob"
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successfully imported completed jobs",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/queue/export": {
+ "get": {
+ "summary": "export all queued jobs for backup/migration",
+ "operationId": "exportQueuedJobs",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Page"
+ },
+ {
+ "$ref": "#/components/parameters/PerPage"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "All queued jobs exported",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ExportableQueuedJob"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/queue/import": {
+ "post": {
+ "summary": "import queued jobs from backup/migration",
+ "operationId": "importQueuedJobs",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ExportableQueuedJob"
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successfully imported queued jobs",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/delete": {
+ "post": {
+ "summary": "delete jobs by IDs from all related tables",
+ "operationId": "deleteJobs",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "description": "Array of job IDs to delete"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successfully deleted jobs",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string",
+ "description": "Summary of deleted jobs and rows"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/jobs/list": {
"get": {
"summary": "list all jobs",
@@ -12197,7 +15721,16 @@
"$ref": "#/components/parameters/CreatedAfter"
},
{
- "$ref": "#/components/parameters/CreatedOrStartedBefore"
+ "$ref": "#/components/parameters/CompletedBefore"
+ },
+ {
+ "$ref": "#/components/parameters/CompletedAfter"
+ },
+ {
+ "$ref": "#/components/parameters/CreatedBeforeQueue"
+ },
+ {
+ "$ref": "#/components/parameters/CreatedAfterQueue"
},
{
"$ref": "#/components/parameters/Running"
@@ -12205,12 +15738,6 @@
{
"$ref": "#/components/parameters/ScheduledForBeforeNow"
},
- {
- "$ref": "#/components/parameters/CreatedOrStartedAfter"
- },
- {
- "$ref": "#/components/parameters/CreatedOrStartedAfterCompletedJob"
- },
{
"$ref": "#/components/parameters/JobKinds"
},
@@ -12230,10 +15757,10 @@
"$ref": "#/components/parameters/AllowWildcards"
},
{
- "$ref": "#/components/parameters/Page"
+ "$ref": "#/components/parameters/PerPage"
},
{
- "$ref": "#/components/parameters/PerPage"
+ "$ref": "#/components/parameters/JobTriggerKind"
},
{
"name": "is_skipped",
@@ -12463,6 +15990,13 @@
},
{
"$ref": "#/components/parameters/JobId"
+ },
+ {
+ "name": "remove_ansi_warnings",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
}
],
"responses": {
@@ -12479,6 +16013,35 @@
}
}
},
+ "/w/{workspace}/jobs_u/get_completed_logs_tail/{id}": {
+ "get": {
+ "summary": "get completed job logs tail",
+ "operationId": "getCompletedJobLogsTail",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/JobId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "completed job logs tail",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/jobs_u/get_args/{id}": {
"get": {
"summary": "get job args",
@@ -12506,6 +16069,50 @@
}
}
},
+ "/w/{workspace}/jobs_u/queue/get_started_at_by_ids": {
+ "post": {
+ "summary": "get started at by ids",
+ "operationId": "getStartedAtByIds",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "ids",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "started at by ids",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/jobs_u/getupdate/{id}": {
"get": {
"summary": "get job updates",
@@ -12866,6 +16473,51 @@
}
}
},
+ "/w/{workspace}/jobs_u/completed/get_timing/{id}": {
+ "get": {
+ "summary": "get completed job timing",
+ "operationId": "getCompletedJobTiming",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/JobId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "job timing details",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "started_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "duration_ms": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "created_at"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/jobs/completed/delete/{id}": {
"post": {
"summary": "delete completed job (erase content but keep run id)",
@@ -13030,6 +16682,76 @@
}
}
},
+ "/w/{workspace}/jobs/queue/position/{scheduled_for}": {
+ "get": {
+ "summary": "get queue position for a job",
+ "operationId": "getQueuePosition",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "scheduled_for",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "description": "The scheduled for timestamp in milliseconds"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "queue position information",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "position": {
+ "type": "integer",
+ "description": "The position in queue (1-based), null if not in queue or already running"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/jobs/queue/scheduled_for/{id}": {
+ "get": {
+ "summary": "get scheduled for timestamp for a job",
+ "operationId": "getScheduledFor",
+ "tags": [
+ "job"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/JobId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "scheduled for timestamp",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "integer"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/jobs/job_signature/{id}/{resume_id}": {
"get": {
"summary": "create an HMac signature given a job id and a resume id",
@@ -13102,6 +16824,14 @@
"schema": {
"type": "string"
}
+ },
+ {
+ "name": "flow_level",
+ "in": "query",
+ "description": "If true, generate resume URLs for the parent flow instead of the specific step. This allows pre-approvals that can be consumed by any later suspend step in the same flow.",
+ "schema": {
+ "type": "boolean"
+ }
}
],
"responses": {
@@ -14529,6 +18259,53 @@
}
}
},
+ "/w/{workspace}/http_triggers/setmode/{path}": {
+ "post": {
+ "summary": "enable/disable http trigger",
+ "operationId": "setHttpTriggerMode",
+ "tags": [
+ "http_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Path"
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
+ }
+ },
+ "required": [
+ "mode"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "http trigger enable/disable",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/websocket_triggers/create": {
"post": {
"summary": "create websocket trigger",
@@ -14751,10 +18528,10 @@
}
}
},
- "/w/{workspace}/websocket_triggers/setenabled/{path}": {
+ "/w/{workspace}/websocket_triggers/setmode/{path}": {
"post": {
"summary": "set enabled websocket trigger",
- "operationId": "setWebsocketTriggerEnabled",
+ "operationId": "setWebsocketTriggerMode",
"tags": [
"websocket_trigger"
],
@@ -14774,12 +18551,12 @@
"schema": {
"type": "object",
"properties": {
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
}
},
"required": [
- "enabled"
+ "mode"
]
}
}
@@ -15073,10 +18850,10 @@
}
}
},
- "/w/{workspace}/kafka_triggers/setenabled/{path}": {
+ "/w/{workspace}/kafka_triggers/setmode/{path}": {
"post": {
"summary": "set enabled kafka trigger",
- "operationId": "setKafkaTriggerEnabled",
+ "operationId": "setKafkaTriggerMode",
"tags": [
"kafka_trigger"
],
@@ -15096,12 +18873,12 @@
"schema": {
"type": "object",
"properties": {
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
}
},
"required": [
- "enabled"
+ "mode"
]
}
}
@@ -15388,10 +19165,10 @@
}
}
},
- "/w/{workspace}/nats_triggers/setenabled/{path}": {
+ "/w/{workspace}/nats_triggers/setmode/{path}": {
"post": {
"summary": "set enabled nats trigger",
- "operationId": "setNatsTriggerEnabled",
+ "operationId": "setNatsTriggerMode",
"tags": [
"nats_trigger"
],
@@ -15411,12 +19188,12 @@
"schema": {
"type": "object",
"properties": {
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
}
},
"required": [
- "enabled"
+ "mode"
]
}
}
@@ -15703,10 +19480,10 @@
}
}
},
- "/w/{workspace}/sqs_triggers/setenabled/{path}": {
+ "/w/{workspace}/sqs_triggers/setmode/{path}": {
"post": {
"summary": "set enabled sqs trigger",
- "operationId": "setSqsTriggerEnabled",
+ "operationId": "setSqsTriggerMode",
"tags": [
"sqs_trigger"
],
@@ -15726,12 +19503,12 @@
"schema": {
"type": "object",
"properties": {
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
}
},
"required": [
- "enabled"
+ "mode"
]
}
}
@@ -15796,6 +19573,674 @@
}
}
},
+ "/w/{workspace}/native_triggers/integrations/list": {
+ "get": {
+ "summary": "list available native trigger services",
+ "operationId": "listNativeTriggerServices",
+ "tags": [
+ "workspace_integration"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "native trigger services list",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/WorkspaceIntegrations"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/integrations/{service_name}/exists": {
+ "get": {
+ "summary": "check if integrations for a particular service exists",
+ "operationId": "checkIfNativeTriggersServiceExists",
+ "tags": [
+ "workspace_integration"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "integration exists",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/integrations/{service_name}/create": {
+ "post": {
+ "summary": "create native trigger service",
+ "operationId": "createNativeTriggerService",
+ "tags": [
+ "workspace_integration"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "new native trigger service",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/WorkspaceOAuthConfig"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "native trigger service created",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/integrations/{service_name}/generate_connect_url": {
+ "post": {
+ "summary": "generate connect url for native trigger service",
+ "operationId": "generateNativeTriggerServiceConnectUrl",
+ "tags": [
+ "workspace_integration"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "redirect_uri",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RedirectUri"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "native trigger service connect url",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/integrations/{service_name}/delete": {
+ "delete": {
+ "summary": "delete native trigger service",
+ "operationId": "deleteNativeTriggerService",
+ "tags": [
+ "workspace_integration"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "native trigger service deleted",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/integrations/{service_name}/callback/{code}/{state}": {
+ "post": {
+ "summary": "native trigger service oauth callback",
+ "operationId": "nativeTriggerServiceCallback",
+ "tags": [
+ "workspace_integration"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ },
+ {
+ "name": "code",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "state",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "redirect_uri",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RedirectUri"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "native trigger service oauth completed",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/{service_name}/create": {
+ "post": {
+ "summary": "create native trigger",
+ "description": "Creates a new native trigger for the specified service.\nRequires write access to the script or flow that the trigger will be associated with.\n",
+ "operationId": "createNativeTrigger",
+ "tags": [
+ "native_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "new native trigger configuration",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NativeTriggerData"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "native trigger created",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateTriggerResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/{service_name}/update/{external_id}": {
+ "post": {
+ "summary": "update native trigger",
+ "description": "Updates an existing native trigger.\nRequires write access to the script or flow that the trigger is associated with.\n",
+ "operationId": "updateNativeTrigger",
+ "tags": [
+ "native_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ },
+ {
+ "name": "external_id",
+ "in": "path",
+ "required": true,
+ "description": "The external ID of the trigger from the external service",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "updated native trigger configuration",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NativeTriggerData"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "native trigger updated",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/{service_name}/get/{external_id}": {
+ "get": {
+ "summary": "get native trigger",
+ "description": "Retrieves a native trigger by its external ID.\nRequires write access to the script or flow that the trigger is associated with.\n",
+ "operationId": "getNativeTrigger",
+ "tags": [
+ "native_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ },
+ {
+ "name": "external_id",
+ "in": "path",
+ "required": true,
+ "description": "The external ID of the trigger from the external service",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "native trigger with external configuration",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NativeTriggerWithExternal"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/{service_name}/delete/{external_id}": {
+ "delete": {
+ "summary": "delete native trigger",
+ "description": "Deletes a native trigger by its external ID.\nRequires write access to the script or flow that the trigger is associated with.\n",
+ "operationId": "deleteNativeTrigger",
+ "tags": [
+ "native_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ },
+ {
+ "name": "external_id",
+ "in": "path",
+ "required": true,
+ "description": "The external ID of the trigger from the external service",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "native trigger deleted",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/{service_name}/list": {
+ "get": {
+ "summary": "list native triggers",
+ "description": "Lists all native triggers for the specified service in the workspace.",
+ "operationId": "listNativeTriggers",
+ "tags": [
+ "native_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/Page"
+ },
+ {
+ "$ref": "#/components/parameters/PerPage"
+ },
+ {
+ "name": "path",
+ "description": "filter by script path",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "is_flow",
+ "description": "filter by is_flow",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "native triggers list",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/NativeTrigger"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/{service_name}/exists/{external_id}": {
+ "get": {
+ "summary": "check if native trigger exists",
+ "description": "Checks if a native trigger with the given external ID exists.",
+ "operationId": "existsNativeTrigger",
+ "tags": [
+ "native_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ },
+ {
+ "name": "external_id",
+ "in": "path",
+ "required": true,
+ "description": "The external ID of the trigger from the external service",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "whether the native trigger exists",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/{service_name}/sync": {
+ "post": {
+ "summary": "sync native triggers with external service",
+ "operationId": "syncNativeTriggers",
+ "tags": [
+ "native_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "sync completed successfully"
+ }
+ }
+ }
+ },
+ "/w/{workspace}/native_triggers/nextcloud/events": {
+ "get": {
+ "summary": "list available NextCloud events",
+ "operationId": "listNextCloudEvents",
+ "tags": [
+ "native_trigger"
+ ],
+ "parameters": [
+ {
+ "name": "workspace",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "list of available NextCloud events",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/NextCloudEventType"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/native_triggers/{service_name}/w/{workspace_id}/webhook/{internal_id}": {
+ "post": {
+ "summary": "receive webhook from external native trigger service",
+ "operationId": "nativeTriggerWebhook",
+ "tags": [
+ "native_trigger"
+ ],
+ "parameters": [
+ {
+ "name": "service_name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ }
+ },
+ {
+ "name": "workspace_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "internal_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "description": "The internal database ID of the trigger"
+ }
+ ],
+ "requestBody": {
+ "description": "webhook payload from external service",
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": true
+ }
+ },
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "webhook received successfully",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/mqtt_triggers/create": {
"post": {
"summary": "create mqtt trigger",
@@ -16018,10 +20463,10 @@
}
}
},
- "/w/{workspace}/mqtt_triggers/setenabled/{path}": {
+ "/w/{workspace}/mqtt_triggers/setmode/{path}": {
"post": {
"summary": "set enabled mqtt trigger",
- "operationId": "setMqttTriggerEnabled",
+ "operationId": "setMqttTriggerMode",
"tags": [
"mqtt_trigger"
],
@@ -16041,12 +20486,12 @@
"schema": {
"type": "object",
"properties": {
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
}
},
"required": [
- "enabled"
+ "mode"
]
}
}
@@ -16333,10 +20778,10 @@
}
}
},
- "/w/{workspace}/gcp_triggers/setenabled/{path}": {
+ "/w/{workspace}/gcp_triggers/setmode/{path}": {
"post": {
"summary": "set enabled gcp trigger",
- "operationId": "setGcpTriggerEnabled",
+ "operationId": "setGcpTriggerMode",
"tags": [
"gcp_trigger"
],
@@ -16356,12 +20801,12 @@
"schema": {
"type": "object",
"properties": {
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
}
},
"required": [
- "enabled"
+ "mode"
]
}
}
@@ -17181,10 +21626,10 @@
}
}
},
- "/w/{workspace}/postgres_triggers/setenabled/{path}": {
+ "/w/{workspace}/postgres_triggers/setmode/{path}": {
"post": {
"summary": "set enabled postgres trigger",
- "operationId": "setPostgresTriggerEnabled",
+ "operationId": "setPostgresTriggerMode",
"tags": [
"postgres_trigger"
],
@@ -17204,12 +21649,12 @@
"schema": {
"type": "object",
"properties": {
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
}
},
"required": [
- "enabled"
+ "mode"
]
}
}
@@ -17274,6 +21719,326 @@
}
}
},
+ "/w/{workspace}/email_triggers/create": {
+ "post": {
+ "summary": "create email trigger",
+ "operationId": "createEmailTrigger",
+ "tags": [
+ "email_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "new email trigger",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NewEmailTrigger"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "email trigger created",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/email_triggers/update/{path}": {
+ "post": {
+ "summary": "update email trigger",
+ "operationId": "updateEmailTrigger",
+ "tags": [
+ "email_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Path"
+ }
+ ],
+ "requestBody": {
+ "description": "updated trigger",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/EditEmailTrigger"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "email trigger updated",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/email_triggers/delete/{path}": {
+ "delete": {
+ "summary": "delete email trigger",
+ "operationId": "deleteEmailTrigger",
+ "tags": [
+ "email_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "email trigger deleted",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/email_triggers/get/{path}": {
+ "get": {
+ "summary": "get email trigger",
+ "operationId": "getEmailTrigger",
+ "tags": [
+ "email_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "email trigger retrieved",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/EmailTrigger"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/email_triggers/list": {
+ "get": {
+ "summary": "list email triggers",
+ "operationId": "listEmailTriggers",
+ "tags": [
+ "email_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId",
+ "required": true
+ },
+ {
+ "$ref": "#/components/parameters/Page"
+ },
+ {
+ "$ref": "#/components/parameters/PerPage"
+ },
+ {
+ "name": "path",
+ "description": "filter by path",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "is_flow",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ {
+ "name": "path_start",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "email trigger list",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/EmailTrigger"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/email_triggers/exists/{path}": {
+ "get": {
+ "summary": "does email trigger exists",
+ "operationId": "existsEmailTrigger",
+ "tags": [
+ "email_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "email trigger exists",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/email_triggers/local_part_exists": {
+ "post": {
+ "summary": "does email local part exists",
+ "operationId": "existsEmailLocalPart",
+ "tags": [
+ "email_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "requestBody": {
+ "description": "email local part exists request",
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "local_part": {
+ "type": "string"
+ },
+ "workspaced_local_part": {
+ "type": "boolean"
+ },
+ "trigger_path": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "local_part"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "email local part exists",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/email_triggers/setmode/{path}": {
+ "post": {
+ "summary": "enable/disable email trigger",
+ "operationId": "setEmailTriggerMode",
+ "tags": [
+ "email_trigger"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Path"
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
+ }
+ },
+ "required": [
+ "mode"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "email trigger enable/disable",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/groups/list": {
"get": {
"summary": "list instance groups",
@@ -17298,6 +22063,30 @@
}
}
},
+ "/groups/list_with_workspaces": {
+ "get": {
+ "summary": "list instance groups with workspace information",
+ "operationId": "listInstanceGroupsWithWorkspaces",
+ "tags": [
+ "group"
+ ],
+ "responses": {
+ "200": {
+ "description": "instance group list with workspaces",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/InstanceGroupWithWorkspaces"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/groups/get/{name}": {
"get": {
"summary": "get instance group",
@@ -17900,6 +22689,63 @@
}
}
},
+ "/w/{workspace}/groups_history/get/{name}": {
+ "get": {
+ "summary": "get group permission history",
+ "operationId": "getGroupPermissionHistory",
+ "tags": [
+ "group"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Name"
+ },
+ {
+ "$ref": "#/components/parameters/Page"
+ },
+ {
+ "$ref": "#/components/parameters/PerPage"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "group permission history",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "changed_by": {
+ "type": "string"
+ },
+ "changed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "change_type": {
+ "type": "string"
+ },
+ "member_affected": {
+ "type": "string",
+ "nullable": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/folders/list": {
"get": {
"summary": "list folders",
@@ -18330,6 +23176,63 @@
}
}
},
+ "/w/{workspace}/folders_history/get/{name}": {
+ "get": {
+ "summary": "get folder permission history",
+ "operationId": "getFolderPermissionHistory",
+ "tags": [
+ "folder"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "$ref": "#/components/parameters/Name"
+ },
+ {
+ "$ref": "#/components/parameters/Page"
+ },
+ {
+ "$ref": "#/components/parameters/PerPage"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "folder permission history",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "changed_by": {
+ "type": "string"
+ },
+ "changed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "change_type": {
+ "type": "string"
+ },
+ "affected": {
+ "type": "string",
+ "nullable": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/workers/list": {
"get": {
"summary": "list workers",
@@ -18372,18 +23275,28 @@
}
}
},
- "/workers/exists_worker_with_tag": {
+ "/workers/exists_workers_with_tags": {
"get": {
- "summary": "exists worker with tag",
- "operationId": "existsWorkerWithTag",
+ "summary": "exists workers with tags",
+ "operationId": "existsWorkersWithTags",
"tags": [
"worker"
],
"parameters": [
{
- "name": "tag",
+ "name": "tags",
"in": "query",
"required": true,
+ "description": "comma separated list of tags",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "description": "workspace to filter tags visibility (required when TAGS_ARE_SENSITIVE is enabled for non-superadmins)",
"schema": {
"type": "string"
}
@@ -18391,11 +23304,14 @@
],
"responses": {
"200": {
- "description": "whether a worker with the tag exists",
+ "description": "map of tags to whether at least one worker with the tag exists",
"content": {
"application/json": {
"schema": {
- "type": "boolean"
+ "type": "object",
+ "additionalProperties": {
+ "type": "boolean"
+ }
}
}
}
@@ -18478,6 +23394,30 @@
}
}
},
+ "/workers/queue_running_counts": {
+ "get": {
+ "summary": "get counts of currently running jobs per tag",
+ "operationId": "getCountsOfRunningJobsPerTag",
+ "tags": [
+ "worker"
+ ],
+ "responses": {
+ "200": {
+ "description": "queue running counts",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "integer"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/configs/list_worker_groups": {
"get": {
"summary": "list worker groups",
@@ -18636,6 +23576,12 @@
"schema": {
"type": "string"
}
+ },
+ {
+ "$ref": "#/components/parameters/Page"
+ },
+ {
+ "$ref": "#/components/parameters/PerPage"
}
],
"responses": {
@@ -18655,6 +23601,30 @@
}
}
},
+ "/configs/native_kubernetes_autoscaling_healthcheck": {
+ "get": {
+ "summary": "Check Kubernetes autoscaling health for a worker group",
+ "operationId": "nativeKubernetesAutoscalingHealthcheck",
+ "tags": [
+ "config"
+ ],
+ "responses": {
+ "200": {
+ "description": "Kubernetes autoscaling is healthy"
+ },
+ "400": {
+ "description": "Error",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/configs/list_available_python_versions": {
"get": {
"summary": "Get currently available python versions provided by UV.",
@@ -18864,6 +23834,28 @@
}
}
},
+ "/agent_workers/get_min_version": {
+ "get": {
+ "summary": "get minimum worker version across all workers",
+ "operationId": "getMinVersion",
+ "tags": [
+ "agent_workers"
+ ],
+ "responses": {
+ "200": {
+ "description": "minimum worker version",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string",
+ "description": "Minimum semantic version across all workers (e.g. \"1.583.0\")"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/acls/get/{kind}/{path}": {
"get": {
"summary": "get granular acls",
@@ -18901,7 +23893,8 @@
"postgres_trigger",
"mqtt_trigger",
"gcp_trigger",
- "sqs_trigger"
+ "sqs_trigger",
+ "email_trigger"
]
}
}
@@ -18960,7 +23953,8 @@
"postgres_trigger",
"mqtt_trigger",
"gcp_trigger",
- "sqs_trigger"
+ "sqs_trigger",
+ "email_trigger"
]
}
}
@@ -19038,7 +24032,8 @@
"postgres_trigger",
"mqtt_trigger",
"gcp_trigger",
- "sqs_trigger"
+ "sqs_trigger",
+ "email_trigger"
]
}
}
@@ -19382,7 +24377,8 @@
"flow",
"app",
"script",
- "raw_app"
+ "raw_app",
+ "asset"
]
}
}
@@ -19424,7 +24420,8 @@
"flow",
"app",
"script",
- "raw_app"
+ "raw_app",
+ "asset"
]
}
}
@@ -20228,6 +25225,255 @@
}
}
},
+ "/w/{workspace}/job_helpers/list_git_repo_files": {
+ "get": {
+ "summary": "List the file keys available in instance object storage with resource-based access control",
+ "operationId": "listGitRepoFiles",
+ "tags": [
+ "helpers"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "max_keys",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "name": "marker",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "prefix",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string",
+ "description": "Must follow format gitrepos/{workspace_id}/{resource_path}/..."
+ }
+ },
+ {
+ "name": "storage",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "List of file keys",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "next_marker": {
+ "type": "string"
+ },
+ "windmill_large_files": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/WindmillLargeFile"
+ }
+ },
+ "restricted_access": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "windmill_large_files"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/job_helpers/load_git_repo_file_preview": {
+ "get": {
+ "summary": "Load a preview of a file from instance storage with resource-based access control",
+ "operationId": "loadGitRepoFilePreview",
+ "tags": [
+ "helpers"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "file_key",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "description": "Must follow format gitrepos/{workspace_id}/{resource_path}/..."
+ }
+ },
+ {
+ "name": "file_size_in_bytes",
+ "in": "query",
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "name": "file_mime_type",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "csv_separator",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "csv_has_header",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ {
+ "name": "read_bytes_from",
+ "in": "query",
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "name": "read_bytes_length",
+ "in": "query",
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "name": "storage",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "FilePreview",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/WindmillFilePreview"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/job_helpers/load_git_repo_file_metadata": {
+ "get": {
+ "summary": "Load file metadata from instance storage with resource-based access control",
+ "operationId": "loadGitRepoFileMetadata",
+ "tags": [
+ "helpers"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "file_key",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "description": "Must follow format gitrepos/{workspace_id}/{resource_path}/..."
+ }
+ },
+ {
+ "name": "storage",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "FileMetadata",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/WindmillFileMetadata"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/w/{workspace}/job_helpers/check_s3_folder_exists": {
+ "get": {
+ "summary": "Check if S3 path exists and is a folder",
+ "operationId": "checkS3FolderExists",
+ "tags": [
+ "helpers"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "file_key",
+ "description": "S3 file key to check (e.g., gitrepos/{workspace_id}/u/user/resource/{commit_hash})",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "S3 folder existence check result",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "exists": {
+ "type": "boolean",
+ "description": "Whether the path exists"
+ },
+ "is_folder": {
+ "type": "boolean",
+ "description": "Whether the path is a folder (true) or file (false)"
+ }
+ },
+ "required": [
+ "exists",
+ "is_folder"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/job_helpers/load_parquet_preview/{path}": {
"get": {
"summary": "Load a preview of a parquet file",
@@ -20623,6 +25869,105 @@
}
}
},
+ "/w/{workspace}/job_helpers/upload_git_repo_file_to_instance_storage": {
+ "post": {
+ "summary": "Upload a file to the instance storage gitrepos section for viewing",
+ "operationId": "gitRepoViewerFileUpload",
+ "tags": [
+ "helpers"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "file_key",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "file_extension",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "s3_resource_path",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "resource_type",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "storage",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "content_type",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "content_disposition",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "File content",
+ "required": true,
+ "content": {
+ "application/octet-stream": {
+ "schema": {
+ "type": "string",
+ "format": "binary"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "File upload status",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "file_key": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "file_key"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/w/{workspace}/job_helpers/download_s3_file": {
"get": {
"summary": "Download file from S3 bucket",
@@ -21112,9 +26457,6 @@
{
"$ref": "#/components/parameters/StartedAfter"
},
- {
- "$ref": "#/components/parameters/CreatedOrStartedBefore"
- },
{
"$ref": "#/components/parameters/Running"
},
@@ -21122,10 +26464,16 @@
"$ref": "#/components/parameters/ScheduledForBeforeNow"
},
{
- "$ref": "#/components/parameters/CreatedOrStartedAfter"
+ "$ref": "#/components/parameters/CompletedBefore"
},
{
- "$ref": "#/components/parameters/CreatedOrStartedAfterCompletedJob"
+ "$ref": "#/components/parameters/CompletedAfter"
+ },
+ {
+ "$ref": "#/components/parameters/CreatedBeforeQueue"
+ },
+ {
+ "$ref": "#/components/parameters/CreatedAfterQueue"
},
{
"$ref": "#/components/parameters/JobKinds"
@@ -21148,6 +26496,9 @@
{
"$ref": "#/components/parameters/PerPage"
},
+ {
+ "$ref": "#/components/parameters/JobTriggerKind"
+ },
{
"name": "is_skipped",
"description": "is the job skipped",
@@ -21476,7 +26827,7 @@
},
"/w/{workspace}/assets/list": {
"get": {
- "summary": "List all assets in the workspace",
+ "summary": "List all assets in the workspace with cursor pagination",
"operationId": "listAssets",
"tags": [
"asset"
@@ -21484,56 +26835,160 @@
"parameters": [
{
"$ref": "#/components/parameters/WorkspaceId"
+ },
+ {
+ "name": "per_page",
+ "in": "query",
+ "description": "Number of items per page (max 1000, default 50)",
+ "schema": {
+ "type": "integer",
+ "default": 50,
+ "minimum": 1,
+ "maximum": 1000
+ }
+ },
+ {
+ "name": "cursor_created_at",
+ "in": "query",
+ "description": "Cursor timestamp for pagination (created_at of last item from previous page)",
+ "schema": {
+ "type": "string",
+ "format": "date-time"
+ }
+ },
+ {
+ "name": "cursor_id",
+ "in": "query",
+ "description": "Cursor ID for pagination (id of last item from previous page)",
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "asset_path",
+ "in": "query",
+ "description": "Filter by asset path (case-insensitive partial match)",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "usage_path",
+ "in": "query",
+ "description": "Filter by usage path (case-insensitive partial match)",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "asset_kinds",
+ "in": "query",
+ "description": "Filter by asset kinds (multiple values allowed)",
+ "schema": {
+ "type": "string"
+ }
}
],
"responses": {
"200": {
- "description": "all assets in the workspace",
+ "description": "paginated assets in the workspace",
"content": {
"application/json": {
"schema": {
- "type": "array",
- "items": {
- "type": "object",
- "required": [
- "path",
- "kind",
- "usages"
- ],
- "properties": {
- "path": {
- "type": "string"
- },
- "kind": {
- "$ref": "#/components/schemas/AssetKind"
- },
- "usages": {
- "type": "array",
- "items": {
- "type": "object",
- "required": [
- "path",
- "kind"
- ],
- "properties": {
- "path": {
- "type": "string"
- },
- "kind": {
- "$ref": "#/components/schemas/AssetUsageKind"
- },
- "access_type": {
- "$ref": "#/components/schemas/AssetUsageAccessType"
+ "type": "object",
+ "required": [
+ "assets"
+ ],
+ "properties": {
+ "assets": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "path",
+ "kind",
+ "usages"
+ ],
+ "properties": {
+ "path": {
+ "type": "string"
+ },
+ "kind": {
+ "$ref": "#/components/schemas/AssetKind"
+ },
+ "usages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "path",
+ "kind"
+ ],
+ "properties": {
+ "path": {
+ "type": "string"
+ },
+ "kind": {
+ "$ref": "#/components/schemas/AssetUsageKind"
+ },
+ "access_type": {
+ "$ref": "#/components/schemas/AssetUsageAccessType"
+ },
+ "columns": {
+ "type": "object",
+ "description": "The columns used (for tables)",
+ "additionalProperties": {
+ "$ref": "#/components/schemas/AssetUsageAccessType"
+ }
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the asset was detected"
+ },
+ "metadata": {
+ "type": "object",
+ "properties": {
+ "runnable_path": {
+ "type": "string",
+ "description": "The path of the script/flow that was run (only present when kind is 'job')"
+ },
+ "job_kind": {
+ "type": "string",
+ "description": "The kind of job (script, flow, preview, etc.) (only present when kind is 'job')"
+ }
+ }
+ }
+ }
+ }
+ },
+ "metadata": {
+ "type": "object",
+ "properties": {
+ "resource_type": {
+ "type": "string",
+ "description": "The type of the resource (only present when kind is 'resource')"
+ }
}
}
}
- },
- "metadata": {
- "type": "object",
- "properties": {
- "resource_type": {
- "type": "string"
- }
+ }
+ },
+ "next_cursor": {
+ "type": "object",
+ "description": "Cursor for the next page (null if no more pages)",
+ "nullable": true,
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Timestamp to use for next page"
+ },
+ "id": {
+ "type": "integer",
+ "format": "int64",
+ "description": "ID to use for next page"
}
}
}
@@ -21626,6 +27081,44 @@
}
}
},
+ "/w/{workspace}/assets/list_favorites": {
+ "get": {
+ "summary": "List all favorite assets for the authenticated user",
+ "operationId": "listFavoriteAssets",
+ "tags": [
+ "asset"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/WorkspaceId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "list of favorite assets",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "path"
+ ],
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "The asset path"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/mcp/w/{workspace}/list_tools": {
"get": {
"summary": "list available MCP tools",
@@ -21654,6 +27147,144 @@
}
}
}
+ },
+ "/mcp/oauth/discover": {
+ "post": {
+ "summary": "discover MCP server OAuth metadata",
+ "operationId": "discoverMcpOAuth",
+ "tags": [
+ "mcp_oauth"
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "mcp_server_url"
+ ],
+ "properties": {
+ "mcp_server_url": {
+ "type": "string",
+ "description": "URL of the MCP server to discover OAuth metadata from"
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "OAuth metadata from MCP server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "scopes_supported": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "authorization_endpoint": {
+ "type": "string"
+ },
+ "token_endpoint": {
+ "type": "string"
+ },
+ "registration_endpoint": {
+ "type": "string"
+ },
+ "supports_dynamic_registration": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/mcp/oauth/start": {
+ "get": {
+ "summary": "start MCP OAuth popup flow",
+ "description": "Opens in a popup, discovers OAuth metadata, registers client, and redirects to OAuth provider",
+ "operationId": "startMcpOAuthPopup",
+ "tags": [
+ "mcp_oauth"
+ ],
+ "parameters": [
+ {
+ "name": "mcp_server_url",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "description": "URL of the MCP server to connect to"
+ },
+ {
+ "name": "scopes",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ },
+ "description": "Comma-separated list of OAuth scopes to request"
+ }
+ ],
+ "responses": {
+ "302": {
+ "description": "Redirect to OAuth provider authorization URL"
+ }
+ }
+ }
+ },
+ "/mcp/oauth/callback": {
+ "get": {
+ "security": [],
+ "summary": "MCP OAuth callback",
+ "description": "Handles OAuth callback, exchanges code for tokens, returns HTML that posts message to opener",
+ "operationId": "mcpOAuthCallback",
+ "tags": [
+ "mcp_oauth"
+ ],
+ "parameters": [
+ {
+ "name": "code",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "description": "OAuth authorization code"
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "description": "CSRF state token"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "HTML page with JavaScript that posts tokens to opener window and closes",
+ "content": {
+ "text/html": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
}
},
"components": {
@@ -21815,6 +27446,14 @@
"type": "integer"
}
},
+ "JobTriggerKind": {
+ "name": "trigger_kind",
+ "description": "trigger kind (schedule, http, websocket...)",
+ "in": "query",
+ "schema": {
+ "$ref": "#/components/schemas/JobTriggerKind"
+ }
+ },
"OrderDesc": {
"name": "order_desc",
"description": "order by desc order (default true)",
@@ -21897,6 +27536,14 @@
"type": "string"
}
},
+ "SkipPreprocessor": {
+ "name": "skip_preprocessor",
+ "description": "skip the preprocessor",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
+ },
"Payload": {
"name": "payload",
"description": "The base64 encoded payload that has been encoded as a JSON. e.g how to encode such payload encodeURIComponent\n`encodeURIComponent(btoa(JSON.stringify({a: 2})))`\n",
@@ -21921,6 +27568,14 @@
"type": "string"
}
},
+ "TriggerPath": {
+ "name": "trigger_path",
+ "description": "mask to filter by trigger path",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
"ScriptExactPath": {
"name": "script_path_exact",
"description": "mask to filter exact matching path",
@@ -21982,27 +27637,36 @@
"format": "date-time"
}
},
- "CreatedOrStartedAfter": {
- "name": "created_or_started_after",
- "description": "filter on created_at for non non started job and started_at otherwise after (exclusive) timestamp",
+ "CompletedBefore": {
+ "name": "completed_before",
+ "description": "filter on started before (inclusive) timestamp",
"in": "query",
"schema": {
"type": "string",
"format": "date-time"
}
},
- "CreatedOrStartedAfterCompletedJob": {
- "name": "created_or_started_after_completed_jobs",
- "description": "filter on created_at for non non started job and started_at otherwise after (exclusive) timestamp but only for the completed jobs",
+ "CompletedAfter": {
+ "name": "completed_after",
+ "description": "filter on started after (exclusive) timestamp",
"in": "query",
"schema": {
"type": "string",
"format": "date-time"
}
},
- "CreatedOrStartedBefore": {
- "name": "created_or_started_before",
- "description": "filter on created_at for non non started job and started_at otherwise before (inclusive) timestamp",
+ "CreatedAfterQueue": {
+ "name": "created_after_queue",
+ "description": "filter on jobs created after X for jobs in the queue only",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "date-time"
+ }
+ },
+ "CreatedBeforeQueue": {
+ "name": "created_before_queue",
+ "description": "filter on jobs created before X for jobs in the queue only",
"in": "query",
"schema": {
"type": "string",
@@ -22181,18 +27845,26 @@
"schemas": {
"OpenFlow": {
"type": "object",
+ "description": "Top-level flow definition containing metadata, configuration, and the flow structure",
"properties": {
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short description of what this flow does"
},
"description": {
- "type": "string"
+ "type": "string",
+ "description": "Detailed documentation for this flow"
},
"value": {
"$ref": "#/components/schemas/schemas-FlowValue"
},
"schema": {
- "type": "object"
+ "type": "object",
+ "description": "JSON Schema for flow inputs. Use this to define input parameters, their types, defaults, and validation. For resource inputs, set type to 'object' and format to 'resource-' (e.g., 'resource-stripe')"
+ },
+ "on_behalf_of_email": {
+ "type": "string",
+ "description": "The flow will be run with the permissions of the user with this email."
}
},
"required": [
@@ -22202,42 +27874,98 @@
},
"FlowValue": {
"type": "object",
+ "description": "The flow structure containing modules and optional preprocessor/failure handlers",
"properties": {
"modules": {
"type": "array",
+ "description": "Array of steps that execute in sequence. Each step can be a script, subflow, loop, or branch",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
},
"failure_module": {
+ "description": "Special module that executes when the flow fails. Receives error object with message, name, stack, and step_id. Must have id 'failure'. Only supports script/rawscript types",
"$ref": "#/components/schemas/schemas-FlowModule"
},
"preprocessor_module": {
+ "description": "Special module that runs before the first step on external triggers. Must have id 'preprocessor'. Only supports script/rawscript types. Cannot reference other step results",
"$ref": "#/components/schemas/schemas-FlowModule"
},
"same_worker": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, all steps run on the same worker for better performance"
},
"concurrent_limit": {
- "type": "number"
+ "type": "number",
+ "description": "Maximum number of concurrent executions of this flow"
},
"concurrency_key": {
- "type": "string"
+ "type": "string",
+ "description": "Expression to group concurrent executions (e.g., by user ID)"
},
"concurrency_time_window_s": {
- "type": "number"
+ "type": "number",
+ "description": "Time window in seconds for concurrent_limit"
+ },
+ "debounce_delay_s": {
+ "type": "number",
+ "description": "Delay in seconds to debounce flow executions"
+ },
+ "debounce_key": {
+ "type": "string",
+ "description": "Expression to group debounced executions"
+ },
+ "debounce_args_to_accumulate": {
+ "type": "array",
+ "description": "Arguments to accumulate across debounced executions",
+ "items": {
+ "type": "string"
+ }
+ },
+ "max_total_debouncing_time": {
+ "type": "number",
+ "description": "Maximum total time in seconds that a job can be debounced"
+ },
+ "max_total_debounces_amount": {
+ "type": "number",
+ "description": "Maximum number of times a job can be debounced"
},
"skip_expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression to conditionally skip the entire flow"
},
"cache_ttl": {
- "type": "number"
+ "type": "number",
+ "description": "Cache duration in seconds for flow results"
+ },
+ "cache_ignore_s3_path": {
+ "type": "boolean"
+ },
+ "flow_env": {
+ "type": "object",
+ "description": "Environment variables available to all steps",
+ "additionalProperties": {
+ "type": "string"
+ }
},
"priority": {
- "type": "number"
+ "type": "number",
+ "description": "Execution priority (higher numbers run first)"
},
"early_return": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression to return early from the flow"
+ },
+ "chat_input_enabled": {
+ "type": "boolean",
+ "description": "Whether this flow accepts chat-style input"
+ },
+ "notes": {
+ "type": "array",
+ "description": "Sticky notes attached to the flow",
+ "items": {
+ "$ref": "#/components/schemas/schemas-FlowNote"
+ }
}
},
"required": [
@@ -22246,50 +27974,67 @@
},
"Retry": {
"type": "object",
+ "description": "Retry configuration for failed module executions",
"properties": {
"constant": {
"type": "object",
+ "description": "Retry with constant delay between attempts",
"properties": {
"attempts": {
- "type": "integer"
+ "type": "integer",
+ "description": "Number of retry attempts"
},
"seconds": {
- "type": "integer"
+ "type": "integer",
+ "description": "Seconds to wait between retries"
}
}
},
"exponential": {
"type": "object",
+ "description": "Retry with exponential backoff (delay doubles each time)",
"properties": {
"attempts": {
- "type": "integer"
+ "type": "integer",
+ "description": "Number of retry attempts"
},
"multiplier": {
- "type": "integer"
+ "type": "integer",
+ "description": "Multiplier for exponential backoff"
},
"seconds": {
- "type": "integer"
+ "type": "integer",
+ "minimum": 1,
+ "description": "Initial delay in seconds"
},
"random_factor": {
"type": "integer",
"minimum": 0,
- "maximum": 100
+ "maximum": 100,
+ "description": "Random jitter percentage (0-100) to avoid thundering herd"
}
}
+ },
+ "retry_if": {
+ "$ref": "#/components/schemas/RetryIf"
}
}
},
"StopAfterIf": {
"type": "object",
+ "description": "Early termination condition for a module",
"properties": {
"skip_if_stopped": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, following steps are skipped when this condition triggers"
},
"expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression evaluated after the module runs. Can use 'result' (step's result) or 'flow_input'. Return true to stop"
},
"error_message": {
- "type": "string"
+ "type": "string",
+ "description": "Custom error message shown when stopping"
}
},
"required": [
@@ -22298,24 +28043,30 @@
},
"FlowModule": {
"type": "object",
+ "description": "A single step in a flow. Can be a script, subflow, loop, or branch",
"properties": {
"id": {
- "type": "string"
+ "type": "string",
+ "description": "Unique identifier for this step. Used to reference results via 'results.step_id'. Must be a valid identifier (alphanumeric, underscore, hyphen)"
},
"value": {
"$ref": "#/components/schemas/schemas-FlowModuleValue"
},
"stop_after_if": {
+ "description": "Early termination condition evaluated after this step completes",
"$ref": "#/components/schemas/schemas-StopAfterIf"
},
"stop_after_all_iters_if": {
+ "description": "For loops only - early termination condition evaluated after all iterations complete",
"$ref": "#/components/schemas/schemas-StopAfterIf"
},
"skip_if": {
"type": "object",
+ "description": "Conditionally skip this step based on previous results or flow inputs",
"properties": {
"expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression that returns true to skip. Can use 'flow_input' or 'results.'"
}
},
"required": [
@@ -22323,70 +28074,95 @@
]
},
"sleep": {
+ "description": "Delay before executing this step (in seconds or as expression)",
"$ref": "#/components/schemas/schemas-InputTransform"
},
"cache_ttl": {
- "type": "number"
+ "type": "number",
+ "description": "Cache duration in seconds for this step's results"
},
- "timeout": {
- "type": "number"
- },
- "delete_after_use": {
+ "cache_ignore_s3_path": {
"type": "boolean"
},
+ "timeout": {
+ "description": "Maximum execution time in seconds (static value or expression)",
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ },
+ "delete_after_use": {
+ "type": "boolean",
+ "description": "If true, this step's result is deleted after use to save memory"
+ },
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short description of what this step does"
},
"mock": {
"type": "object",
+ "description": "Mock configuration for testing without executing the actual step",
"properties": {
"enabled": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, return mock value instead of executing"
},
- "return_value": {}
+ "return_value": {
+ "description": "Value to return when mocked"
+ }
}
},
"suspend": {
"type": "object",
+ "description": "Configuration for approval/resume steps that wait for user input",
"properties": {
"required_events": {
- "type": "integer"
+ "type": "integer",
+ "description": "Number of approvals required before continuing"
},
"timeout": {
- "type": "integer"
+ "type": "integer",
+ "description": "Timeout in seconds before auto-continuing or canceling"
},
"resume_form": {
"type": "object",
+ "description": "Form schema for collecting input when resuming",
"properties": {
"schema": {
- "type": "object"
+ "type": "object",
+ "description": "JSON Schema for the resume form"
}
}
},
"user_auth_required": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, only authenticated users can approve"
},
"user_groups_required": {
+ "description": "Expression or list of groups that can approve",
"$ref": "#/components/schemas/schemas-InputTransform"
},
"self_approval_disabled": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, the user who started the flow cannot approve"
},
"hide_cancel": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, hide the cancel button on the approval form"
},
"continue_on_disapprove_timeout": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, continue flow on timeout instead of canceling"
}
}
},
"priority": {
- "type": "number"
+ "type": "number",
+ "description": "Execution priority for this step (higher numbers run first)"
},
"continue_on_error": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, flow continues even if this step fails"
},
"retry": {
+ "description": "Retry configuration if this step fails",
"$ref": "#/components/schemas/schemas-Retry"
}
},
@@ -22396,26 +28172,34 @@
]
},
"InputTransform": {
+ "description": "Maps input parameters for a step. Can be a static value or a JavaScript expression that references previous results or flow inputs",
"oneOf": [
{
"$ref": "#/components/schemas/schemas-StaticTransform"
},
{
"$ref": "#/components/schemas/schemas-JavascriptTransform"
+ },
+ {
+ "$ref": "#/components/schemas/schemas-AiTransform"
}
],
"discriminator": {
"propertyName": "type",
"mapping": {
"static": "#/components/schemas/schemas-StaticTransform",
- "javascript": "#/components/schemas/schemas-JavascriptTransform"
+ "javascript": "#/components/schemas/schemas-JavascriptTransform",
+ "ai": "#/components/schemas/schemas-AiTransform"
}
}
},
"StaticTransform": {
"type": "object",
+ "description": "Static value passed directly to the step. Use for hardcoded values or resource references like '$res:path/to/resource'",
"properties": {
- "value": {},
+ "value": {
+ "description": "The static value. For resources, use format '$res:path/to/resource'"
+ },
"type": {
"type": "string",
"enum": [
@@ -22424,15 +28208,16 @@
}
},
"required": [
- "value",
"type"
]
},
"JavascriptTransform": {
"type": "object",
+ "description": "JavaScript expression evaluated at runtime. Can reference previous step results via 'results.step_id' or flow inputs via 'flow_input.property'. Inside loops, use 'flow_input.iter.value' for the current iteration value",
"properties": {
"expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression returning the value. Available variables - results (object with all previous step results), flow_input (flow inputs), flow_input.iter (in loops)"
},
"type": {
"type": "string",
@@ -22446,7 +28231,67 @@
"type"
]
},
+ "AiTransform": {
+ "type": "object",
+ "description": "Value resolved by the AI runtime for this input. The AI engine decides how to satisfy the parameter.",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "ai"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "ProviderConfig": {
+ "type": "object",
+ "description": "Complete AI provider configuration with resource reference and model selection",
+ "properties": {
+ "kind": {
+ "$ref": "#/components/schemas/AIProviderKind"
+ },
+ "resource": {
+ "type": "string",
+ "description": "Resource reference in format '$res:{resource_path}' pointing to provider credentials"
+ },
+ "model": {
+ "type": "string",
+ "description": "Model identifier (e.g., 'gpt-4', 'claude-3-opus-20240229', 'gemini-pro')"
+ }
+ },
+ "required": [
+ "kind",
+ "resource",
+ "model"
+ ]
+ },
+ "MemoryConfig": {
+ "description": "Conversation memory configuration",
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/MemoryOff"
+ },
+ {
+ "$ref": "#/components/schemas/MemoryAuto"
+ },
+ {
+ "$ref": "#/components/schemas/MemoryManual"
+ }
+ ],
+ "discriminator": {
+ "propertyName": "kind",
+ "mapping": {
+ "off": "#/components/schemas/MemoryOff",
+ "auto": "#/components/schemas/MemoryAuto",
+ "manual": "#/components/schemas/MemoryManual"
+ }
+ }
+ },
"FlowModuleValue": {
+ "description": "The actual implementation of a flow step. Can be a script (inline or referenced), subflow, loop, branch, or special module type",
"oneOf": [
{
"$ref": "#/components/schemas/schemas-RawScript"
@@ -22471,6 +28316,9 @@
},
{
"$ref": "#/components/schemas/schemas-Identity"
+ },
+ {
+ "$ref": "#/components/schemas/schemas-AiAgent"
}
],
"discriminator": {
@@ -22483,24 +28331,29 @@
"whileloopflow": "#/components/schemas/schemas-WhileloopFlow",
"branchone": "#/components/schemas/schemas-BranchOne",
"branchall": "#/components/schemas/schemas-BranchAll",
- "identity": "#/components/schemas/schemas-Identity"
+ "identity": "#/components/schemas/schemas-Identity",
+ "aiagent": "#/components/schemas/schemas-AiAgent"
}
}
},
"RawScript": {
"type": "object",
+ "description": "Inline script with code defined directly in the flow. Use 'bun' as default language if unspecified. The script receives arguments from input_transforms",
"properties": {
"input_transforms": {
"type": "object",
+ "description": "Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments",
"additionalProperties": {
"$ref": "#/components/schemas/schemas-InputTransform"
}
},
"content": {
- "type": "string"
+ "type": "string",
+ "description": "The script source code. Should export a 'main' function"
},
"language": {
"type": "string",
+ "description": "Programming language for this script",
"enum": [
"deno",
"bun",
@@ -22516,14 +28369,23 @@
"oracledb",
"graphql",
"nativets",
- "php"
+ "php",
+ "rust",
+ "ansible",
+ "csharp",
+ "nu",
+ "java",
+ "ruby",
+ "duckdb"
]
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "Optional path for saving this script"
},
"lock": {
- "type": "string"
+ "type": "string",
+ "description": "Lock file content for dependencies"
},
"type": {
"type": "string",
@@ -22532,22 +28394,28 @@
]
},
"tag": {
- "type": "string"
+ "type": "string",
+ "description": "Worker group tag for execution routing"
},
"concurrent_limit": {
- "type": "number"
+ "type": "number",
+ "description": "Maximum concurrent executions of this script"
},
"concurrency_time_window_s": {
- "type": "number"
+ "type": "number",
+ "description": "Time window for concurrent_limit"
},
"custom_concurrency_key": {
- "type": "string"
+ "type": "string",
+ "description": "Custom key for grouping concurrent executions"
},
"is_trigger": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, this script is a trigger that can start the flow"
},
"assets": {
"type": "array",
+ "description": "External resources this script accesses (S3 objects, resources, etc.)",
"items": {
"type": "object",
"required": [
@@ -22556,18 +28424,23 @@
],
"properties": {
"path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the asset"
},
"kind": {
"type": "string",
+ "description": "Type of asset",
"enum": [
"s3object",
"resource",
- "ducklake"
+ "ducklake",
+ "datatable"
]
},
"access_type": {
"type": "string",
+ "nullable": true,
+ "description": "Access level for this asset",
"enum": [
"r",
"w",
@@ -22576,6 +28449,8 @@
},
"alt_access_type": {
"type": "string",
+ "nullable": true,
+ "description": "Alternative access level",
"enum": [
"r",
"w",
@@ -22595,18 +28470,22 @@
},
"PathScript": {
"type": "object",
+ "description": "Reference to an existing script by path. Use this when calling a previously saved script instead of writing inline code",
"properties": {
"input_transforms": {
"type": "object",
+ "description": "Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments",
"additionalProperties": {
"$ref": "#/components/schemas/schemas-InputTransform"
}
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script in the workspace (e.g., 'f/scripts/send_email')"
},
"hash": {
- "type": "string"
+ "type": "string",
+ "description": "Optional specific version hash of the script to use"
},
"type": {
"type": "string",
@@ -22615,10 +28494,12 @@
]
},
"tag_override": {
- "type": "string"
+ "type": "string",
+ "description": "Override the script's default worker group tag"
},
"is_trigger": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, this script is a trigger that can start the flow"
}
},
"required": [
@@ -22629,15 +28510,18 @@
},
"PathFlow": {
"type": "object",
+ "description": "Reference to an existing flow by path. Use this to call another flow as a subflow",
"properties": {
"input_transforms": {
"type": "object",
+ "description": "Map of parameter names to their values (static or JavaScript expressions). These become the subflow's input arguments",
"additionalProperties": {
"$ref": "#/components/schemas/schemas-InputTransform"
}
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the flow in the workspace (e.g., 'f/flows/process_user')"
},
"type": {
"type": "string",
@@ -22654,18 +28538,22 @@
},
"ForloopFlow": {
"type": "object",
+ "description": "Executes nested modules in a loop over an iterator. Inside the loop, use 'flow_input.iter.value' to access the current iteration value, and 'flow_input.iter.index' for the index. Supports parallel execution for better performance on I/O-bound operations",
"properties": {
"modules": {
"type": "array",
+ "description": "Steps to execute for each iteration. These can reference the iteration value via 'flow_input.iter.value'",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
},
"iterator": {
+ "description": "JavaScript expression that returns an array to iterate over. Can reference 'results.step_id' or 'flow_input'",
"$ref": "#/components/schemas/schemas-InputTransform"
},
"skip_failures": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, iteration failures don't stop the loop. Failed iterations return null"
},
"type": {
"type": "string",
@@ -22674,10 +28562,15 @@
]
},
"parallel": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, iterations run concurrently (faster for I/O-bound operations). Use with parallelism to control concurrency"
},
"parallelism": {
- "type": "integer"
+ "description": "Maximum number of concurrent iterations when parallel=true. Limits resource usage. Can be static number or expression",
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ },
+ "squash": {
+ "type": "boolean"
}
},
"required": [
@@ -22689,15 +28582,18 @@
},
"WhileloopFlow": {
"type": "object",
+ "description": "Executes nested modules repeatedly while a condition is true. The loop checks the condition after each iteration. Use stop_after_if on modules to control loop termination",
"properties": {
"modules": {
"type": "array",
+ "description": "Steps to execute in each iteration. Use stop_after_if to control when the loop ends",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
},
"skip_failures": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, iteration failures don't stop the loop. Failed iterations return null"
},
"type": {
"type": "string",
@@ -22706,10 +28602,15 @@
]
},
"parallel": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, iterations run concurrently (use with caution in while loops)"
},
"parallelism": {
- "type": "integer"
+ "description": "Maximum number of concurrent iterations when parallel=true",
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ },
+ "squash": {
+ "type": "boolean"
}
},
"required": [
@@ -22720,20 +28621,25 @@
},
"BranchOne": {
"type": "object",
+ "description": "Conditional branching where only the first matching branch executes. Branches are evaluated in order, and the first one with a true expression runs. If no branches match, the default branch executes",
"properties": {
"branches": {
"type": "array",
+ "description": "Array of branches to evaluate in order. The first branch with expr evaluating to true executes",
"items": {
"type": "object",
"properties": {
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short description of this branch condition"
},
"expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression that returns boolean. Can use 'results.step_id' or 'flow_input'. First true expr wins"
},
"modules": {
"type": "array",
+ "description": "Steps to execute if this branch's expr is true",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
@@ -22747,12 +28653,10 @@
},
"default": {
"type": "array",
+ "description": "Steps to execute if no branch expressions match",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
- },
- "required": [
- "modules"
- ]
+ }
},
"type": {
"type": "string",
@@ -22769,20 +28673,25 @@
},
"BranchAll": {
"type": "object",
+ "description": "Parallel branching where all branches execute simultaneously. Unlike BranchOne, all branches run regardless of conditions. Useful for executing independent tasks concurrently",
"properties": {
"branches": {
"type": "array",
+ "description": "Array of branches that all execute (either in parallel or sequentially)",
"items": {
"type": "object",
"properties": {
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short description of this branch's purpose"
},
"skip_failure": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, failure in this branch doesn't fail the entire flow"
},
"modules": {
"type": "array",
+ "description": "Steps to execute in this branch",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
@@ -22800,7 +28709,8 @@
]
},
"parallel": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, all branches execute concurrently. If false, they execute sequentially"
}
},
"required": [
@@ -22808,8 +28718,118 @@
"type"
]
},
+ "AiAgent": {
+ "type": "object",
+ "description": "AI agent step that can use tools to accomplish tasks. The agent receives inputs and can call any of its configured tools to complete the task",
+ "properties": {
+ "input_transforms": {
+ "type": "object",
+ "description": "Input parameters for the AI agent mapped to their values",
+ "properties": {
+ "provider": {
+ "$ref": "#/components/schemas/ProviderTransform"
+ },
+ "output_type": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Output format type.\nValid values: 'text' (default) - plain text response, 'image' - image generation\n"
+ },
+ "user_message": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "The user's prompt/message to the AI agent. Supports variable interpolation with flow.input syntax."
+ },
+ "system_prompt": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "System instructions that guide the AI's behavior, persona, and response style. Optional."
+ },
+ "streaming": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Boolean. If true, stream the AI response incrementally.\nStreaming events include: token_delta, tool_call, tool_call_arguments, tool_execution, tool_result\n"
+ },
+ "memory": {
+ "$ref": "#/components/schemas/MemoryTransform"
+ },
+ "output_schema": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "JSON Schema object defining structured output format. Used when you need the AI to return data in a specific shape.\nSupports standard JSON Schema properties: type, properties, required, items, enum, pattern, minLength, maxLength, minimum, maximum, etc.\nExample: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'integer' } }, required: ['name'] }\n"
+ },
+ "user_images": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Array of image references for vision-capable models.\nFormat: Array<{ bucket: string, key: string }> - S3 object references\nExample: [{ bucket: 'my-bucket', key: 'images/photo.jpg' }]\n"
+ },
+ "max_completion_tokens": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Integer. Maximum number of tokens the AI will generate in its response.\nRange: 1 to 4,294,967,295. Typical values: 256-4096 for most use cases.\n"
+ },
+ "temperature": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Float. Controls randomness/creativity of responses.\nRange: 0.0 to 2.0 (provider-dependent)\n- 0.0 = deterministic, focused responses\n- 0.7 = balanced (common default)\n- 1.0+ = more creative/random\n"
+ }
+ },
+ "required": [
+ "provider",
+ "user_message",
+ "output_type"
+ ]
+ },
+ "tools": {
+ "type": "array",
+ "description": "Array of tools the agent can use. The agent decides which tools to call based on the task",
+ "items": {
+ "$ref": "#/components/schemas/AgentTool"
+ }
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "aiagent"
+ ]
+ },
+ "parallel": {
+ "type": "boolean",
+ "description": "If true, the agent can execute multiple tool calls in parallel"
+ }
+ },
+ "required": [
+ "tools",
+ "type",
+ "input_transforms"
+ ]
+ },
"Identity": {
"type": "object",
+ "description": "Pass-through module that returns its input unchanged. Useful for flow structure or as a placeholder",
"properties": {
"type": {
"type": "string",
@@ -22818,7 +28838,8 @@
]
},
"flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, marks this as a flow identity (special handling)"
}
},
"required": [
@@ -22921,6 +28942,9 @@
"type": "array",
"items": {}
},
+ "itered_len": {
+ "type": "integer"
+ },
"args": {}
}
},
@@ -22936,6 +28960,23 @@
"type": "boolean"
}
},
+ "flow_jobs_duration": {
+ "type": "object",
+ "properties": {
+ "started_at": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "duration_ms": {
+ "type": "array",
+ "items": {
+ "type": "integer"
+ }
+ }
+ }
+ },
"branch_chosen": {
"type": "object",
"properties": {
@@ -22996,12 +29037,763 @@
},
"skipped": {
"type": "boolean"
+ },
+ "agent_actions": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "job_id": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "function_name": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "tool_call"
+ ]
+ },
+ "module_id": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "job_id",
+ "function_name",
+ "type",
+ "module_id"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "call_id": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "function_name": {
+ "type": "string"
+ },
+ "resource_path": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "mcp_tool_call"
+ ]
+ },
+ "arguments": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "call_id",
+ "function_name",
+ "resource_path",
+ "type"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "web_search"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "message"
+ ]
+ }
+ },
+ "required": [
+ "content",
+ "type"
+ ]
+ }
+ ]
+ }
+ },
+ "agent_actions_success": {
+ "type": "array",
+ "items": {
+ "type": "boolean"
+ }
}
},
"required": [
"type"
]
},
+ "FlowNote": {
+ "type": "object",
+ "description": "A sticky note attached to a flow for documentation and annotation",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique identifier for the note"
+ },
+ "text": {
+ "type": "string",
+ "description": "Content of the note"
+ },
+ "position": {
+ "type": "object",
+ "description": "Position of the note in the flow editor",
+ "properties": {
+ "x": {
+ "type": "number",
+ "description": "X coordinate"
+ },
+ "y": {
+ "type": "number",
+ "description": "Y coordinate"
+ }
+ },
+ "required": [
+ "x",
+ "y"
+ ]
+ },
+ "size": {
+ "type": "object",
+ "description": "Size of the note in the flow editor",
+ "properties": {
+ "width": {
+ "type": "number",
+ "description": "Width in pixels"
+ },
+ "height": {
+ "type": "number",
+ "description": "Height in pixels"
+ }
+ },
+ "required": [
+ "width",
+ "height"
+ ]
+ },
+ "color": {
+ "type": "string",
+ "description": "Color of the note (e.g., \"yellow\", \"#ffff00\")"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "free",
+ "group"
+ ],
+ "description": "Type of note - 'free' for standalone notes, 'group' for notes that group other nodes"
+ },
+ "locked": {
+ "type": "boolean",
+ "default": false,
+ "description": "Whether the note is locked and cannot be edited or moved"
+ },
+ "contained_node_ids": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "For group notes, the IDs of nodes contained within this group"
+ }
+ },
+ "required": [
+ "id",
+ "text",
+ "color",
+ "type"
+ ]
+ },
+ "HealthStatusResponse": {
+ "type": "object",
+ "description": "Health status response (cached with 5s TTL)",
+ "required": [
+ "status",
+ "checked_at",
+ "database_healthy",
+ "workers_alive"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "healthy",
+ "degraded",
+ "unhealthy"
+ ],
+ "description": "Overall health status"
+ },
+ "checked_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Timestamp when the health check was actually performed (not cache return time)"
+ },
+ "database_healthy": {
+ "type": "boolean",
+ "description": "Whether the database is reachable"
+ },
+ "workers_alive": {
+ "type": "integer",
+ "format": "int64",
+ "description": "Number of workers that pinged within last 5 minutes"
+ }
+ }
+ },
+ "DetailedHealthResponse": {
+ "type": "object",
+ "description": "Detailed health status response (always fresh, no caching)",
+ "required": [
+ "status",
+ "checked_at",
+ "version",
+ "checks"
+ ],
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": [
+ "healthy",
+ "degraded",
+ "unhealthy"
+ ],
+ "description": "Overall health status"
+ },
+ "checked_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Timestamp when the health check was performed"
+ },
+ "version": {
+ "type": "string",
+ "description": "Server version (e.g., \"EE 1.615.3\")"
+ },
+ "checks": {
+ "$ref": "#/components/schemas/HealthChecks"
+ }
+ }
+ },
+ "HealthChecks": {
+ "type": "object",
+ "description": "Detailed health checks",
+ "required": [
+ "database",
+ "readiness"
+ ],
+ "properties": {
+ "database": {
+ "$ref": "#/components/schemas/DatabaseHealth"
+ },
+ "workers": {
+ "$ref": "#/components/schemas/WorkersHealth",
+ "description": "Worker status (null if database is unreachable)",
+ "nullable": true
+ },
+ "queue": {
+ "$ref": "#/components/schemas/QueueHealth",
+ "description": "Queue status (null if database is unreachable)",
+ "nullable": true
+ },
+ "readiness": {
+ "$ref": "#/components/schemas/ReadinessHealth"
+ }
+ }
+ },
+ "DatabaseHealth": {
+ "type": "object",
+ "description": "Database health status",
+ "required": [
+ "healthy",
+ "latency_ms",
+ "pool"
+ ],
+ "properties": {
+ "healthy": {
+ "type": "boolean",
+ "description": "Whether the database is reachable"
+ },
+ "latency_ms": {
+ "type": "integer",
+ "format": "int64",
+ "description": "Database query latency in milliseconds"
+ },
+ "pool": {
+ "$ref": "#/components/schemas/PoolStats"
+ }
+ }
+ },
+ "PoolStats": {
+ "type": "object",
+ "description": "Database connection pool statistics",
+ "required": [
+ "size",
+ "idle",
+ "max_connections"
+ ],
+ "properties": {
+ "size": {
+ "type": "integer",
+ "description": "Current number of connections in the pool"
+ },
+ "idle": {
+ "type": "integer",
+ "description": "Number of idle connections"
+ },
+ "max_connections": {
+ "type": "integer",
+ "description": "Maximum number of connections allowed"
+ }
+ }
+ },
+ "WorkersHealth": {
+ "type": "object",
+ "description": "Workers health status",
+ "required": [
+ "healthy",
+ "active_count",
+ "worker_groups",
+ "min_version",
+ "versions"
+ ],
+ "properties": {
+ "healthy": {
+ "type": "boolean",
+ "description": "Whether any workers are active"
+ },
+ "active_count": {
+ "type": "integer",
+ "format": "int64",
+ "description": "Number of active workers (pinged in last 5 minutes)"
+ },
+ "worker_groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of active worker groups"
+ },
+ "min_version": {
+ "type": "string",
+ "description": "Minimum required worker version"
+ },
+ "versions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of active worker versions"
+ }
+ }
+ },
+ "QueueHealth": {
+ "type": "object",
+ "description": "Job queue status",
+ "required": [
+ "pending_jobs",
+ "running_jobs"
+ ],
+ "properties": {
+ "pending_jobs": {
+ "type": "integer",
+ "format": "int64",
+ "description": "Number of pending jobs in the queue"
+ },
+ "running_jobs": {
+ "type": "integer",
+ "format": "int64",
+ "description": "Number of currently running jobs"
+ }
+ }
+ },
+ "ReadinessHealth": {
+ "type": "object",
+ "description": "Server readiness status",
+ "required": [
+ "healthy"
+ ],
+ "properties": {
+ "healthy": {
+ "type": "boolean",
+ "description": "Whether the server is ready to accept requests"
+ }
+ }
+ },
+ "AutoInviteConfig": {
+ "type": "object",
+ "description": "Configuration for auto-inviting users to the workspace",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false
+ },
+ "domain": {
+ "type": "string"
+ },
+ "operator": {
+ "type": "boolean",
+ "default": false,
+ "description": "If true, auto-invited users are added as operators. If false, they are added as developers."
+ },
+ "mode": {
+ "type": "string",
+ "enum": [
+ "invite",
+ "add"
+ ],
+ "default": "invite"
+ },
+ "instance_groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "instance_groups_roles": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "ErrorHandlerConfig": {
+ "type": "object",
+ "description": "Configuration for the workspace error handler",
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to the error handler script or flow"
+ },
+ "extra_args": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ },
+ "muted_on_cancel": {
+ "type": "boolean",
+ "default": false
+ },
+ "muted_on_user_path": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "SuccessHandlerConfig": {
+ "type": "object",
+ "description": "Configuration for the workspace success handler",
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to the success handler script or flow"
+ },
+ "extra_args": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ }
+ }
+ },
+ "EditErrorHandler": {
+ "description": "Request body for editing the workspace error handler. Accepts both new grouped format and legacy flat format for backward compatibility.",
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/EditErrorHandlerNew"
+ },
+ {
+ "$ref": "#/components/schemas/EditErrorHandlerLegacy"
+ }
+ ]
+ },
+ "EditErrorHandlerNew": {
+ "type": "object",
+ "description": "New grouped format for editing error handler",
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to the error handler script or flow"
+ },
+ "extra_args": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ },
+ "muted_on_cancel": {
+ "type": "boolean",
+ "default": false
+ },
+ "muted_on_user_path": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "EditErrorHandlerLegacy": {
+ "type": "object",
+ "description": "Legacy flat format for editing error handler (deprecated, use new format)",
+ "properties": {
+ "error_handler": {
+ "type": "string",
+ "description": "Path to the error handler script or flow"
+ },
+ "error_handler_extra_args": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ },
+ "error_handler_muted_on_cancel": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "EditSuccessHandler": {
+ "description": "Request body for editing the workspace success handler. Accepts both new grouped format and legacy flat format for backward compatibility.",
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/EditSuccessHandlerNew"
+ },
+ {
+ "$ref": "#/components/schemas/EditSuccessHandlerLegacy"
+ }
+ ]
+ },
+ "EditSuccessHandlerNew": {
+ "type": "object",
+ "description": "New grouped format for editing success handler",
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to the success handler script or flow"
+ },
+ "extra_args": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ }
+ }
+ },
+ "EditSuccessHandlerLegacy": {
+ "type": "object",
+ "description": "Legacy flat format for editing success handler (deprecated, use new format)",
+ "properties": {
+ "success_handler": {
+ "type": "string",
+ "description": "Path to the success handler script or flow"
+ },
+ "success_handler_extra_args": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ }
+ }
+ },
+ "VaultSettings": {
+ "type": "object",
+ "required": [
+ "address",
+ "mount_path"
+ ],
+ "properties": {
+ "address": {
+ "type": "string",
+ "description": "HashiCorp Vault server address (e.g., https://vault.company.com:8200)"
+ },
+ "mount_path": {
+ "type": "string",
+ "description": "KV v2 secrets engine mount path (e.g., windmill)"
+ },
+ "jwt_role": {
+ "type": "string",
+ "description": "Vault JWT auth role name for Windmill (optional, if not provided token auth is used)"
+ },
+ "namespace": {
+ "type": "string",
+ "description": "Vault Enterprise namespace (optional)"
+ },
+ "token": {
+ "type": "string",
+ "description": "Static Vault token for testing/development (optional, if provided this is used instead of JWT authentication)"
+ }
+ }
+ },
+ "SecretMigrationFailure": {
+ "type": "object",
+ "required": [
+ "workspace_id",
+ "path",
+ "error"
+ ],
+ "properties": {
+ "workspace_id": {
+ "type": "string",
+ "description": "Workspace ID where the secret is located"
+ },
+ "path": {
+ "type": "string",
+ "description": "Path of the secret that failed to migrate"
+ },
+ "error": {
+ "type": "string",
+ "description": "Error message"
+ }
+ }
+ },
+ "SecretMigrationReport": {
+ "type": "object",
+ "required": [
+ "total_secrets",
+ "migrated_count",
+ "failed_count",
+ "failures"
+ ],
+ "properties": {
+ "total_secrets": {
+ "type": "integer",
+ "format": "int64",
+ "description": "Total number of secrets found"
+ },
+ "migrated_count": {
+ "type": "integer",
+ "format": "int64",
+ "description": "Number of secrets successfully migrated"
+ },
+ "failed_count": {
+ "type": "integer",
+ "format": "int64",
+ "description": "Number of secrets that failed to migrate"
+ },
+ "failures": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/SecretMigrationFailure"
+ },
+ "description": "Details of any failures encountered during migration"
+ }
+ }
+ },
+ "JwksResponse": {
+ "type": "object",
+ "required": [
+ "keys"
+ ],
+ "properties": {
+ "keys": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": true
+ },
+ "description": "Array of JSON Web Keys for JWT verification"
+ }
+ }
+ },
+ "FlowConversation": {
+ "type": "object",
+ "required": [
+ "id",
+ "workspace_id",
+ "flow_path",
+ "created_at",
+ "updated_at",
+ "created_by"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Unique identifier for the conversation"
+ },
+ "workspace_id": {
+ "type": "string",
+ "description": "The workspace ID where the conversation belongs"
+ },
+ "flow_path": {
+ "type": "string",
+ "description": "Path of the flow this conversation is for"
+ },
+ "title": {
+ "type": "string",
+ "description": "Optional title for the conversation",
+ "nullable": true
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the conversation was created"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the conversation was last updated"
+ },
+ "created_by": {
+ "type": "string",
+ "description": "Username who created the conversation"
+ }
+ }
+ },
+ "FlowConversationMessage": {
+ "type": "object",
+ "required": [
+ "id",
+ "conversation_id",
+ "message_type",
+ "content",
+ "created_at"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Unique identifier for the message"
+ },
+ "conversation_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "The conversation this message belongs to"
+ },
+ "message_type": {
+ "type": "string",
+ "enum": [
+ "user",
+ "assistant",
+ "system",
+ "tool"
+ ],
+ "description": "Type of the message"
+ },
+ "content": {
+ "type": "string",
+ "description": "The message content"
+ },
+ "job_id": {
+ "type": "string",
+ "format": "uuid",
+ "nullable": true,
+ "description": "Associated job ID if this message came from a flow run"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the message was created"
+ },
+ "step_name": {
+ "type": "string",
+ "description": "The step name that produced that message"
+ },
+ "success": {
+ "type": "boolean",
+ "description": "Whether the message is a success"
+ }
+ }
+ },
"EndpointTool": {
"type": "object",
"required": [
@@ -23061,6 +29853,7 @@
"groq",
"openrouter",
"togetherai",
+ "aws_bedrock",
"customai"
]
},
@@ -23130,6 +29923,20 @@
},
"code_completion_model": {
"$ref": "#/components/schemas/AIProviderModel"
+ },
+ "custom_prompts": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "max_tokens_per_model": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 2000000
+ }
}
}
},
@@ -23175,6 +29982,69 @@
}
}
},
+ "WorkspaceDependencies": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "archived": {
+ "type": "boolean"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "content": {
+ "type": "string"
+ },
+ "language": {
+ "$ref": "#/components/schemas/ScriptLang"
+ },
+ "workspace_id": {
+ "type": "string"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "workspace_id",
+ "language",
+ "created_at",
+ "content",
+ "id",
+ "archived"
+ ]
+ },
+ "NewWorkspaceDependencies": {
+ "type": "object",
+ "properties": {
+ "workspace_id": {
+ "type": "string"
+ },
+ "language": {
+ "$ref": "#/components/schemas/ScriptLang"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "content": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "workspace_id",
+ "language",
+ "content"
+ ]
+ },
"Script": {
"type": "object",
"properties": {
@@ -23275,6 +30145,24 @@
"concurrency_key": {
"type": "string"
},
+ "debounce_key": {
+ "type": "string"
+ },
+ "debounce_delay_s": {
+ "type": "integer"
+ },
+ "debounce_args_to_accumulate": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "max_total_debouncing_time": {
+ "type": "integer"
+ },
+ "max_total_debounces_amount": {
+ "type": "integer"
+ },
"cache_ttl": {
"type": "number"
},
@@ -23393,6 +30281,9 @@
"cache_ttl": {
"type": "number"
},
+ "cache_ignore_s3_path": {
+ "type": "boolean"
+ },
"dedicated_worker": {
"type": "boolean"
},
@@ -23417,6 +30308,24 @@
"concurrency_key": {
"type": "string"
},
+ "debounce_key": {
+ "type": "string"
+ },
+ "debounce_delay_s": {
+ "type": "integer"
+ },
+ "debounce_args_to_accumulate": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "max_total_debouncing_time": {
+ "type": "integer"
+ },
+ "max_total_debounces_amount": {
+ "type": "integer"
+ },
"visible_to_runner_only": {
"type": "boolean"
},
@@ -23513,7 +30422,7 @@
"ScriptArgs": {
"type": "object",
"description": "The arguments to pass to the script or flow",
- "additionalProperties": {}
+ "additionalProperties": true
},
"Input": {
"type": "object",
@@ -23663,10 +30572,14 @@
"script_hub",
"identity",
"deploymentcallback",
- "singlescriptflow",
+ "singlestepflow",
"flowscript",
"flownode",
- "appscript"
+ "appscript",
+ "aiagent",
+ "unassigned_script",
+ "unassigned_flow",
+ "unassigned_singlestepflow"
]
},
"schedule_path": {
@@ -23759,6 +30672,10 @@
"type": "string",
"format": "date-time"
},
+ "completed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
"duration_ms": {
"type": "integer"
},
@@ -23806,10 +30723,14 @@
"script_hub",
"identity",
"deploymentcallback",
- "singlescriptflow",
+ "singlestepflow",
"flowscript",
"flownode",
- "appscript"
+ "appscript",
+ "aiagent",
+ "unassigned_script",
+ "unassigned_flow",
+ "unassigned_singlestepflow"
]
},
"schedule_path": {
@@ -23888,6 +30809,394 @@
"tag"
]
},
+ "ExportableCompletedJob": {
+ "type": "object",
+ "description": "Completed job with full data for export/import operations",
+ "properties": {
+ "id": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "parent_job": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "created_by": {
+ "type": "string"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "started_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "completed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "duration_ms": {
+ "type": "integer"
+ },
+ "script_path": {
+ "type": "string"
+ },
+ "script_hash": {
+ "type": "string"
+ },
+ "args": {
+ "type": "object",
+ "description": "Full job arguments without size restrictions"
+ },
+ "result": {
+ "type": "object",
+ "description": "Full job result without size restrictions"
+ },
+ "logs": {
+ "type": "string",
+ "description": "Complete job logs from v2_job table"
+ },
+ "raw_code": {
+ "type": "string"
+ },
+ "raw_lock": {
+ "type": "string"
+ },
+ "canceled_by": {
+ "type": "string"
+ },
+ "canceled_reason": {
+ "type": "string"
+ },
+ "job_kind": {
+ "type": "string",
+ "enum": [
+ "script",
+ "preview",
+ "dependencies",
+ "flow",
+ "flowdependencies",
+ "appdependencies",
+ "flowpreview",
+ "script_hub",
+ "identity",
+ "deploymentcallback",
+ "singlestepflow",
+ "flowscript",
+ "flownode",
+ "appscript",
+ "aiagent",
+ "unassigned_script",
+ "unassigned_flow",
+ "unassigned_singlestepflow"
+ ]
+ },
+ "trigger": {
+ "type": "string",
+ "description": "Trigger path for the job (replaces schedule_path)"
+ },
+ "trigger_kind": {
+ "type": "string",
+ "enum": [
+ "webhook",
+ "http",
+ "websocket",
+ "kafka",
+ "email",
+ "nats",
+ "schedule",
+ "app",
+ "ui",
+ "postgres",
+ "sqs",
+ "gcp"
+ ]
+ },
+ "permissioned_as": {
+ "type": "string"
+ },
+ "permissioned_as_email": {
+ "type": "string"
+ },
+ "flow_status": {
+ "type": "object",
+ "description": "Flow status from v2_job_status table"
+ },
+ "workflow_as_code_status": {
+ "type": "object"
+ },
+ "raw_flow": {
+ "type": "object"
+ },
+ "is_flow_step": {
+ "type": "boolean"
+ },
+ "language": {
+ "$ref": "#/components/schemas/ScriptLang"
+ },
+ "is_skipped": {
+ "type": "boolean"
+ },
+ "email": {
+ "type": "string"
+ },
+ "visible_to_owner": {
+ "type": "boolean"
+ },
+ "mem_peak": {
+ "type": "integer"
+ },
+ "tag": {
+ "type": "string"
+ },
+ "priority": {
+ "type": "integer"
+ },
+ "labels": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "same_worker": {
+ "type": "boolean"
+ },
+ "flow_step_id": {
+ "type": "string"
+ },
+ "flow_innermost_root_job": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "concurrent_limit": {
+ "type": "integer"
+ },
+ "concurrency_time_window_s": {
+ "type": "integer"
+ },
+ "timeout": {
+ "type": "integer"
+ },
+ "cache_ttl": {
+ "type": "integer"
+ },
+ "self_wait_time_ms": {
+ "type": "integer"
+ },
+ "aggregate_wait_time_ms": {
+ "type": "integer"
+ },
+ "preprocessed": {
+ "type": "boolean"
+ },
+ "worker": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string",
+ "description": "Actual job status from database"
+ }
+ },
+ "required": [
+ "id",
+ "created_by",
+ "created_at",
+ "job_kind",
+ "permissioned_as",
+ "email",
+ "visible_to_owner"
+ ]
+ },
+ "ExportableQueuedJob": {
+ "type": "object",
+ "description": "Queued job with full data for export/import operations",
+ "properties": {
+ "id": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "parent_job": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "created_by": {
+ "type": "string"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "started_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "scheduled_for": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "script_path": {
+ "type": "string"
+ },
+ "script_hash": {
+ "type": "string"
+ },
+ "args": {
+ "type": "object",
+ "description": "Full job arguments without size restrictions"
+ },
+ "logs": {
+ "type": "string",
+ "description": "Complete job logs from v2_job table"
+ },
+ "raw_code": {
+ "type": "string"
+ },
+ "raw_lock": {
+ "type": "string"
+ },
+ "canceled_by": {
+ "type": "string"
+ },
+ "canceled_reason": {
+ "type": "string"
+ },
+ "job_kind": {
+ "type": "string",
+ "enum": [
+ "script",
+ "preview",
+ "dependencies",
+ "flowdependencies",
+ "appdependencies",
+ "flow",
+ "flowpreview",
+ "script_hub",
+ "identity",
+ "deploymentcallback",
+ "singlestepflow",
+ "flowscript",
+ "flownode",
+ "appscript",
+ "aiagent",
+ "unassigned_script",
+ "unassigned_flow",
+ "unassigned_singlestepflow"
+ ]
+ },
+ "trigger": {
+ "type": "string",
+ "description": "Trigger path for the job (replaces schedule_path)"
+ },
+ "trigger_kind": {
+ "type": "string",
+ "enum": [
+ "webhook",
+ "http",
+ "websocket",
+ "kafka",
+ "email",
+ "nats",
+ "schedule",
+ "app",
+ "ui",
+ "postgres",
+ "sqs",
+ "gcp"
+ ]
+ },
+ "permissioned_as": {
+ "type": "string"
+ },
+ "permissioned_as_email": {
+ "type": "string"
+ },
+ "flow_status": {
+ "type": "object",
+ "description": "Flow status from v2_job_status table"
+ },
+ "workflow_as_code_status": {
+ "type": "object"
+ },
+ "raw_flow": {
+ "type": "object"
+ },
+ "is_flow_step": {
+ "type": "boolean"
+ },
+ "language": {
+ "$ref": "#/components/schemas/ScriptLang"
+ },
+ "email": {
+ "type": "string"
+ },
+ "visible_to_owner": {
+ "type": "boolean"
+ },
+ "mem_peak": {
+ "type": "integer"
+ },
+ "tag": {
+ "type": "string"
+ },
+ "priority": {
+ "type": "integer"
+ },
+ "labels": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "same_worker": {
+ "type": "boolean"
+ },
+ "flow_step_id": {
+ "type": "string"
+ },
+ "flow_innermost_root_job": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "concurrent_limit": {
+ "type": "integer"
+ },
+ "concurrency_time_window_s": {
+ "type": "integer"
+ },
+ "timeout": {
+ "type": "integer"
+ },
+ "cache_ttl": {
+ "type": "integer"
+ },
+ "self_wait_time_ms": {
+ "type": "integer"
+ },
+ "aggregate_wait_time_ms": {
+ "type": "integer"
+ },
+ "preprocessed": {
+ "type": "boolean"
+ },
+ "suspend": {
+ "type": "integer"
+ },
+ "suspend_until": {
+ "type": "string",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "id",
+ "created_by",
+ "created_at",
+ "job_kind",
+ "permissioned_as",
+ "email",
+ "visible_to_owner"
+ ]
+ },
"ObscuredJob": {
"type": "object",
"properties": {
@@ -23991,6 +31300,14 @@
"items": {
"type": "string"
}
+ },
+ "added_via": {
+ "nullable": true,
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/UserSource"
+ }
+ ]
}
},
"required": [
@@ -24005,6 +31322,31 @@
"folders_owners"
]
},
+ "UserSource": {
+ "type": "object",
+ "properties": {
+ "source": {
+ "type": "string",
+ "enum": [
+ "domain",
+ "instance_group",
+ "manual"
+ ],
+ "description": "How the user was added to the workspace"
+ },
+ "domain": {
+ "type": "string",
+ "description": "The domain used for auto-invite (when source is 'domain')"
+ },
+ "group": {
+ "type": "string",
+ "description": "The instance group name (when source is 'instance_group')"
+ }
+ },
+ "required": [
+ "source"
+ ]
+ },
"UserUsage": {
"type": "object",
"properties": {
@@ -24031,6 +31373,17 @@
"password"
]
},
+ "PasswordResetResponse": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "message"
+ ]
+ },
"EditWorkspaceUser": {
"type": "object",
"properties": {
@@ -24265,6 +31618,9 @@
"AuditLog": {
"type": "object",
"properties": {
+ "workspace_id": {
+ "type": "string"
+ },
"id": {
"type": "integer"
},
@@ -24385,6 +31741,7 @@
}
},
"required": [
+ "workspace_id",
"id",
"timestamp",
"username",
@@ -24611,20 +31968,25 @@
"csharp",
"nu",
"java",
- "duckdb"
+ "ruby",
+ "duckdb",
+ "bunnative"
]
},
"Preview": {
"type": "object",
"properties": {
"content": {
- "type": "string"
+ "type": "string",
+ "description": "The code to run"
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The path to the script"
},
"script_hash": {
- "type": "string"
+ "type": "string",
+ "description": "The hash of the script"
},
"args": {
"$ref": "#/components/schemas/ScriptArgs"
@@ -24654,6 +32016,26 @@
"args"
]
},
+ "PreviewInline": {
+ "type": "object",
+ "properties": {
+ "content": {
+ "type": "string",
+ "description": "The code to run"
+ },
+ "args": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ },
+ "language": {
+ "$ref": "#/components/schemas/ScriptLang"
+ }
+ },
+ "required": [
+ "content",
+ "args",
+ "language"
+ ]
+ },
"WorkflowTask": {
"type": "object",
"properties": {
@@ -24867,29 +32249,37 @@
"type": "object",
"properties": {
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this schedule"
},
"edited_by": {
- "type": "string"
+ "type": "string",
+ "description": "Username of the last person who edited this schedule"
},
"edited_at": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "Timestamp of the last edit"
},
"schedule": {
- "type": "string"
+ "type": "string",
+ "description": "Cron expression with 6 fields (seconds, minutes, hours, day of month, month, day of week). Example '0 0 12 * * *' for daily at noon"
},
"timezone": {
- "type": "string"
+ "type": "string",
+ "description": "IANA timezone for the schedule (e.g., 'UTC', 'Europe/Paris', 'America/New_York')"
},
"enabled": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Whether the schedule is currently active and will trigger jobs"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when triggered"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
"args": {
"$ref": "#/components/schemas/ScriptArgs"
@@ -24898,65 +32288,85 @@
"type": "object",
"additionalProperties": {
"type": "boolean"
- }
+ },
+ "description": "Additional permissions for this schedule"
},
"email": {
- "type": "string"
+ "type": "string",
+ "description": "Email of the user who owns this schedule, used for permissioned_as"
},
"error": {
- "type": "string"
+ "type": "string",
+ "description": "Last error message if the schedule failed to trigger"
},
"on_failure": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the scheduled job fails"
},
"on_failure_times": {
- "type": "number"
+ "type": "number",
+ "description": "Number of consecutive failures before the on_failure handler is triggered (default 1)"
},
"on_failure_exact": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, trigger on_failure handler only on exactly N failures, not on every failure after N"
},
"on_failure_extra_args": {
"$ref": "#/components/schemas/ScriptArgs"
},
"on_recovery": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the schedule recovers after failures"
},
"on_recovery_times": {
- "type": "number"
+ "type": "number",
+ "description": "Number of consecutive successes before the on_recovery handler is triggered (default 1)"
},
"on_recovery_extra_args": {
"$ref": "#/components/schemas/ScriptArgs"
},
"on_success": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run after each successful execution"
},
"on_success_extra_args": {
"$ref": "#/components/schemas/ScriptArgs"
},
"ws_error_handler_muted": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, the workspace-level error handler will not be triggered for this schedule's failures"
},
"retry": {
"$ref": "#/components/schemas/Retry"
},
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short summary describing the purpose of this schedule"
},
"description": {
- "type": "string"
+ "type": "string",
+ "description": "Detailed description of what this schedule does"
},
"no_flow_overlap": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, skip this schedule's execution if the previous run is still in progress (prevents concurrent runs)"
},
"tag": {
- "type": "string"
+ "type": "string",
+ "description": "Worker tag to route jobs to specific worker groups"
},
"paused_until": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "ISO 8601 datetime until which the schedule is paused. Schedule resumes automatically after this time"
},
"cron_version": {
- "type": "string"
+ "type": "string",
+ "description": "Cron parser version. Use 'v2' for extended syntax with additional features"
+ },
+ "dynamic_skip": {
+ "type": "string",
+ "description": "Path to a script that validates scheduled datetimes. Receives scheduled_for datetime and returns boolean to skip (true) or run (false)"
}
},
"required": [
@@ -25020,100 +32430,99 @@
"properties": {
"path": {
"type": "string",
- "description": "The path where the schedule will be created"
+ "description": "The unique path identifier for this schedule"
},
"schedule": {
"type": "string",
- "description": "The cron schedule to trigger the script or flow. Should include seconds."
+ "description": "Cron expression with 6 fields (seconds, minutes, hours, day of month, month, day of week). Example '0 0 12 * * *' for daily at noon"
},
"timezone": {
"type": "string",
- "description": "The timezone to use for the cron schedule"
+ "description": "IANA timezone for the schedule (e.g., 'UTC', 'Europe/Paris', 'America/New_York')"
},
"script_path": {
"type": "string",
- "description": "The path to the script or flow to trigger"
+ "description": "Path to the script or flow to execute when triggered"
},
"is_flow": {
"type": "boolean",
- "description": "Whether the schedule is for a flow"
+ "description": "True if script_path points to a flow, false if it points to a script"
},
"args": {
- "$ref": "#/components/schemas/ScriptArgs",
- "description": "The arguments to pass to the script or flow"
+ "$ref": "#/components/schemas/ScriptArgs"
},
"enabled": {
"type": "boolean",
- "description": "Whether the schedule is enabled"
+ "description": "Whether the schedule is currently active and will trigger jobs"
},
"on_failure": {
"type": "string",
- "description": "The path to the script or flow to trigger on failure"
+ "description": "Path to a script or flow to run when the scheduled job fails"
},
"on_failure_times": {
"type": "number",
- "description": "The number of times to retry on failure"
+ "description": "Number of consecutive failures before the on_failure handler is triggered (default 1)"
},
"on_failure_exact": {
"type": "boolean",
- "description": "Whether the schedule should only run on the exact time"
+ "description": "If true, trigger on_failure handler only on exactly N failures, not on every failure after N"
},
"on_failure_extra_args": {
- "$ref": "#/components/schemas/ScriptArgs",
- "description": "The arguments to pass to the script or flow on failure"
+ "$ref": "#/components/schemas/ScriptArgs"
},
"on_recovery": {
"type": "string",
- "description": "The path to the script or flow to trigger on recovery"
+ "description": "Path to a script or flow to run when the schedule recovers after failures"
},
"on_recovery_times": {
"type": "number",
- "description": "The number of times to retry on recovery"
+ "description": "Number of consecutive successes before the on_recovery handler is triggered (default 1)"
},
"on_recovery_extra_args": {
- "$ref": "#/components/schemas/ScriptArgs",
- "description": "The arguments to pass to the script or flow on recovery"
+ "$ref": "#/components/schemas/ScriptArgs"
},
"on_success": {
"type": "string",
- "description": "The path to the script or flow to trigger on success"
+ "description": "Path to a script or flow to run after each successful execution"
},
"on_success_extra_args": {
- "$ref": "#/components/schemas/ScriptArgs",
- "description": "The arguments to pass to the script or flow on success"
+ "$ref": "#/components/schemas/ScriptArgs"
},
"ws_error_handler_muted": {
"type": "boolean",
- "description": "Whether the WebSocket error handler is muted"
+ "description": "If true, the workspace-level error handler will not be triggered for this schedule's failures"
},
"retry": {
- "$ref": "#/components/schemas/Retry",
- "description": "The retry configuration for the schedule"
+ "$ref": "#/components/schemas/Retry"
},
"no_flow_overlap": {
"type": "boolean",
- "description": "Whether the schedule should not run if a flow is already running"
+ "description": "If true, skip this schedule's execution if the previous run is still in progress (prevents concurrent runs)"
},
"summary": {
"type": "string",
- "description": "The summary of the schedule"
+ "description": "Short summary describing the purpose of this schedule"
},
"description": {
"type": "string",
- "description": "The description of the schedule"
+ "description": "Detailed description of what this schedule does"
},
"tag": {
"type": "string",
- "description": "The tag of the schedule"
+ "description": "Worker tag to route jobs to specific worker groups"
},
"paused_until": {
"type": "string",
- "description": "The date and time the schedule will be paused until",
- "format": "date-time"
+ "format": "date-time",
+ "description": "ISO 8601 datetime until which the schedule is paused. Schedule resumes automatically after this time"
},
"cron_version": {
"type": "string",
- "description": "The version of the cron schedule to use (last is v2)"
+ "description": "Cron parser version. Use 'v2' for extended syntax with additional features"
+ },
+ "dynamic_skip": {
+ "type": "string",
+ "description": "Path to a script that validates scheduled datetimes. Receives scheduled_for datetime and returns boolean to skip (true) or run (false)"
}
},
"required": [
@@ -25130,84 +32539,83 @@
"properties": {
"schedule": {
"type": "string",
- "description": "The cron schedule to trigger the script or flow. Should include seconds."
+ "description": "Cron expression with 6 fields (seconds, minutes, hours, day of month, month, day of week). Example '0 0 12 * * *' for daily at noon"
},
"timezone": {
"type": "string",
- "description": "The timezone to use for the cron schedule"
+ "description": "IANA timezone for the schedule (e.g., 'UTC', 'Europe/Paris', 'America/New_York')"
},
"args": {
- "$ref": "#/components/schemas/ScriptArgs",
- "description": "The arguments to pass to the script or flow"
+ "$ref": "#/components/schemas/ScriptArgs"
},
"on_failure": {
"type": "string",
- "description": "The path to the script or flow to trigger on failure"
+ "description": "Path to a script or flow to run when the scheduled job fails"
},
"on_failure_times": {
"type": "number",
- "description": "The number of times to retry on failure"
+ "description": "Number of consecutive failures before the on_failure handler is triggered (default 1)"
},
"on_failure_exact": {
"type": "boolean",
- "description": "Whether the schedule should only run on the exact time"
+ "description": "If true, trigger on_failure handler only on exactly N failures, not on every failure after N"
},
"on_failure_extra_args": {
- "$ref": "#/components/schemas/ScriptArgs",
- "description": "The arguments to pass to the script or flow on failure"
+ "$ref": "#/components/schemas/ScriptArgs"
},
"on_recovery": {
"type": "string",
- "description": "The path to the script or flow to trigger on recovery"
+ "description": "Path to a script or flow to run when the schedule recovers after failures"
},
"on_recovery_times": {
"type": "number",
- "description": "The number of times to retry on recovery"
+ "description": "Number of consecutive successes before the on_recovery handler is triggered (default 1)"
},
"on_recovery_extra_args": {
- "$ref": "#/components/schemas/ScriptArgs",
- "description": "The arguments to pass to the script or flow on recovery"
+ "$ref": "#/components/schemas/ScriptArgs"
},
"on_success": {
"type": "string",
- "description": "The path to the script or flow to trigger on success"
+ "description": "Path to a script or flow to run after each successful execution"
},
"on_success_extra_args": {
- "$ref": "#/components/schemas/ScriptArgs",
- "description": "The arguments to pass to the script or flow on success"
+ "$ref": "#/components/schemas/ScriptArgs"
},
"ws_error_handler_muted": {
"type": "boolean",
- "description": "Whether the WebSocket error handler is muted"
+ "description": "If true, the workspace-level error handler will not be triggered for this schedule's failures"
},
"retry": {
- "$ref": "#/components/schemas/Retry",
- "description": "The retry configuration for the schedule"
+ "$ref": "#/components/schemas/Retry"
},
"no_flow_overlap": {
"type": "boolean",
- "description": "Whether the schedule should not run if a flow is already running"
+ "description": "If true, skip this schedule's execution if the previous run is still in progress (prevents concurrent runs)"
},
"summary": {
"type": "string",
- "description": "The summary of the schedule"
+ "description": "Short summary describing the purpose of this schedule"
},
"description": {
"type": "string",
- "description": "The description of the schedule"
+ "description": "Detailed description of what this schedule does"
},
"tag": {
"type": "string",
- "description": "The tag of the schedule"
+ "description": "Worker tag to route jobs to specific worker groups"
},
"paused_until": {
"type": "string",
- "description": "The date and time the schedule will be paused until",
- "format": "date-time"
+ "format": "date-time",
+ "description": "ISO 8601 datetime until which the schedule is paused. Schedule resumes automatically after this time"
},
"cron_version": {
"type": "string",
- "description": "The version of the cron schedule to use (last is v2)"
+ "description": "Cron parser version. Use 'v2' for extended syntax with additional features"
+ },
+ "dynamic_skip": {
+ "type": "string",
+ "description": "Path to a script that validates scheduled datetimes. Receives scheduled_for datetime and returns boolean to skip (true) or run (false)"
}
},
"required": [
@@ -25216,36 +32624,75 @@
"args"
]
},
+ "JobTriggerKind": {
+ "description": "job trigger kind (schedule, http, websocket...)",
+ "type": "string",
+ "enum": [
+ "webhook",
+ "default_email",
+ "email",
+ "schedule",
+ "http",
+ "websocket",
+ "postgres",
+ "kafka",
+ "nats",
+ "mqtt",
+ "sqs",
+ "gcp"
+ ]
+ },
+ "TriggerMode": {
+ "description": "job trigger mode",
+ "type": "string",
+ "enum": [
+ "enabled",
+ "disabled",
+ "suspended"
+ ]
+ },
"TriggerExtraProperty": {
"type": "object",
"properties": {
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when triggered"
},
"email": {
- "type": "string"
+ "type": "string",
+ "description": "Email of the user who owns this trigger, used for permissioned_as"
},
"extra_perms": {
"type": "object",
+ "description": "Additional permissions for this trigger",
"additionalProperties": {
"type": "boolean"
}
},
"workspace_id": {
- "type": "string"
+ "type": "string",
+ "description": "The workspace this trigger belongs to"
},
"edited_by": {
- "type": "string"
+ "type": "string",
+ "description": "Username of the last person who edited this trigger"
},
"edited_at": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "Timestamp of the last edit"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
+ },
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode",
+ "description": "Trigger mode (enabled/disabled)"
}
},
"required": [
@@ -25256,7 +32703,8 @@
"workspace_id",
"edited_by",
"edited_at",
- "is_flow"
+ "is_flow",
+ "mode"
]
},
"AuthenticationMethod": {
@@ -25419,6 +32867,14 @@
"patch"
]
},
+ "HttpRequestType": {
+ "type": "string",
+ "enum": [
+ "sync",
+ "async",
+ "sync_sse"
+ ]
+ },
"HttpTrigger": {
"allOf": [
{
@@ -25428,19 +32884,24 @@
"type": "object",
"properties": {
"route_path": {
- "type": "string"
+ "type": "string",
+ "description": "The URL route path that will trigger this endpoint (e.g., 'api/myendpoint'). Must NOT start with a /."
},
"static_asset_config": {
"type": "object",
+ "description": "Configuration for serving static assets (s3 bucket, storage path, filename)",
"properties": {
"s3": {
- "type": "string"
+ "type": "string",
+ "description": "S3 bucket path for static assets"
},
"storage": {
- "type": "string"
+ "type": "string",
+ "description": "Storage path for static assets"
},
"filename": {
- "type": "string"
+ "type": "string",
+ "description": "Filename for the static asset"
}
},
"required": [
@@ -25448,48 +32909,61 @@
]
},
"http_method": {
- "$ref": "#/components/schemas/HttpMethod"
+ "$ref": "#/components/schemas/HttpMethod",
+ "description": "HTTP method (get, post, put, delete, patch) that triggers this endpoint"
},
"authentication_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the resource containing authentication configuration (for api_key, basic_http, custom_script, signature methods)"
},
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short summary describing the purpose of this trigger"
},
"description": {
- "type": "string"
+ "type": "string",
+ "description": "Detailed description of what this trigger does"
},
- "is_async": {
- "type": "boolean"
+ "request_type": {
+ "$ref": "#/components/schemas/HttpRequestType",
+ "description": "How the request is handled - 'sync' waits for result, 'async' returns job ID immediately, 'sync_sse' streams results via Server-Sent Events"
},
"authentication_method": {
- "$ref": "#/components/schemas/AuthenticationMethod"
+ "$ref": "#/components/schemas/AuthenticationMethod",
+ "description": "How requests are authenticated - 'none' (public), 'windmill' (Windmill token), 'api_key', 'basic_http', 'custom_script', 'signature'"
},
"is_static_website": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, serves static files from S3/storage instead of running a script"
},
"workspaced_route": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, the route includes the workspace ID in the path"
},
"wrap_body": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, wraps the request body in a 'body' parameter"
},
"raw_string": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, passes the request body as a raw string instead of parsing as JSON"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
"route_path",
- "is_async",
+ "request_type",
"authentication_method",
"http_method",
"is_static_website",
@@ -25502,34 +32976,44 @@
"type": "object",
"properties": {
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when triggered"
},
"route_path": {
- "type": "string"
+ "type": "string",
+ "description": "The URL route path that will trigger this endpoint (e.g., 'api/myendpoint'). Must NOT start with a /."
},
"workspaced_route": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, the route includes the workspace ID in the path"
},
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short summary describing the purpose of this trigger"
},
"description": {
- "type": "string"
+ "type": "string",
+ "description": "Detailed description of what this trigger does"
},
"static_asset_config": {
"type": "object",
+ "description": "Configuration for serving static assets (s3 bucket, storage path, filename)",
"properties": {
"s3": {
- "type": "string"
+ "type": "string",
+ "description": "S3 bucket path for static assets"
},
"storage": {
- "type": "string"
+ "type": "string",
+ "description": "Storage path for static assets"
},
"filename": {
- "type": "string"
+ "type": "string",
+ "description": "Filename for the static asset"
}
},
"required": [
@@ -25537,37 +33021,55 @@
]
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
"http_method": {
- "$ref": "#/components/schemas/HttpMethod"
+ "$ref": "#/components/schemas/HttpMethod",
+ "description": "HTTP method (get, post, put, delete, patch) that triggers this endpoint"
},
"authentication_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the resource containing authentication configuration (for api_key, basic_http, custom_script, signature methods)"
},
"is_async": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Deprecated, use request_type instead"
+ },
+ "request_type": {
+ "$ref": "#/components/schemas/HttpRequestType",
+ "description": "How the request is handled - 'sync' waits for result, 'async' returns job ID immediately, 'sync_sse' streams results via Server-Sent Events"
},
"authentication_method": {
- "$ref": "#/components/schemas/AuthenticationMethod"
+ "$ref": "#/components/schemas/AuthenticationMethod",
+ "description": "How requests are authenticated - 'none' (public), 'windmill' (Windmill token), 'api_key', 'basic_http', 'custom_script', 'signature'"
},
"is_static_website": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, serves static files from S3/storage instead of running a script"
},
"wrap_body": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, wraps the request body in a 'body' parameter"
+ },
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"raw_string": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, passes the request body as a raw string instead of parsing as JSON"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -25575,7 +33077,6 @@
"script_path",
"route_path",
"is_flow",
- "is_async",
"authentication_method",
"http_method",
"is_static_website"
@@ -25585,34 +33086,44 @@
"type": "object",
"properties": {
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when triggered"
},
"route_path": {
- "type": "string"
+ "type": "string",
+ "description": "The URL route path that will trigger this endpoint (e.g., 'api/myendpoint'). Must NOT start with a /."
},
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short summary describing the purpose of this trigger"
},
"description": {
- "type": "string"
+ "type": "string",
+ "description": "Detailed description of what this trigger does"
},
"workspaced_route": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, the route includes the workspace ID in the path"
},
"static_asset_config": {
"type": "object",
+ "description": "Configuration for serving static assets (s3 bucket, storage path, filename)",
"properties": {
"s3": {
- "type": "string"
+ "type": "string",
+ "description": "S3 bucket path for static assets"
},
"storage": {
- "type": "string"
+ "type": "string",
+ "description": "Storage path for static assets"
},
"filename": {
- "type": "string"
+ "type": "string",
+ "description": "Filename for the static asset"
}
},
"required": [
@@ -25620,37 +33131,52 @@
]
},
"authentication_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the resource containing authentication configuration (for api_key, basic_http, custom_script, signature methods)"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
"http_method": {
- "$ref": "#/components/schemas/HttpMethod"
+ "$ref": "#/components/schemas/HttpMethod",
+ "description": "HTTP method (get, post, put, delete, patch) that triggers this endpoint"
},
"is_async": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Deprecated, use request_type instead"
+ },
+ "request_type": {
+ "$ref": "#/components/schemas/HttpRequestType",
+ "description": "How the request is handled - 'sync' waits for result, 'async' returns job ID immediately, 'sync_sse' streams results via Server-Sent Events"
},
"authentication_method": {
- "$ref": "#/components/schemas/AuthenticationMethod"
+ "$ref": "#/components/schemas/AuthenticationMethod",
+ "description": "How requests are authenticated - 'none' (public), 'windmill' (Windmill token), 'api_key', 'basic_http', 'custom_script', 'signature'"
},
"is_static_website": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, serves static files from S3/storage instead of running a script"
},
"wrap_body": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, wraps the request body in a 'body' parameter"
},
"raw_string": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, passes the request body as a raw string instead of parsing as JSON"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -25658,7 +33184,6 @@
"script_path",
"is_flow",
"kind",
- "is_async",
"authentication_method",
"http_method",
"is_static_website"
@@ -25687,6 +33212,9 @@
"email_count": {
"type": "number"
},
+ "default_email_count": {
+ "type": "number"
+ },
"websocket_count": {
"type": "number"
},
@@ -25707,6 +33235,9 @@
},
"sqs_count": {
"type": "number"
+ },
+ "nextcloud_count": {
+ "type": "number"
}
}
},
@@ -25719,23 +33250,25 @@
"type": "object",
"properties": {
"url": {
- "type": "string"
+ "type": "string",
+ "description": "The WebSocket URL to connect to (can be a static URL or computed by a runnable)"
},
"server_id": {
- "type": "string"
+ "type": "string",
+ "description": "ID of the server currently handling this trigger (internal)"
},
"last_server_ping": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "Timestamp of last server heartbeat (internal)"
},
"error": {
- "type": "string"
- },
- "enabled": {
- "type": "boolean"
+ "type": "string",
+ "description": "Last error message if the trigger failed"
},
"filters": {
"type": "array",
+ "description": "Array of key-value filters to match incoming messages (only matching messages trigger the script)",
"items": {
"type": "object",
"properties": {
@@ -25752,53 +33285,68 @@
},
"initial_messages": {
"type": "array",
+ "description": "Messages to send immediately after connecting (can be raw strings or computed by runnables)",
"items": {
"$ref": "#/components/schemas/WebsocketTriggerInitialMessage"
}
},
"url_runnable_args": {
+ "description": "Arguments to pass to the script/flow that computes the WebSocket URL",
"$ref": "#/components/schemas/ScriptArgs"
},
"can_return_message": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, the script can return a message to send back through the WebSocket"
+ },
+ "can_return_error_result": {
+ "type": "boolean",
+ "description": "If true, error results are sent back through the WebSocket"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
+ "description": "Arguments to pass to the error handler",
"$ref": "#/components/schemas/ScriptArgs"
},
"retry": {
+ "description": "Retry configuration for failed executions",
"$ref": "#/components/schemas/Retry"
}
},
"required": [
"url",
- "enabled",
"filters",
- "can_return_message"
+ "can_return_message",
+ "can_return_error_result"
]
},
"NewWebsocketTrigger": {
"type": "object",
"properties": {
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
"url": {
- "type": "string"
+ "type": "string",
+ "description": "The WebSocket URL to connect to (can be a static URL or computed by a runnable)"
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"filters": {
"type": "array",
+ "description": "Array of key-value filters to match incoming messages (only matching messages trigger the script)",
"items": {
"type": "object",
"properties": {
@@ -25815,23 +33363,33 @@
},
"initial_messages": {
"type": "array",
+ "description": "Messages to send immediately after connecting (can be raw strings or computed by runnables)",
"items": {
"$ref": "#/components/schemas/WebsocketTriggerInitialMessage"
}
},
"url_runnable_args": {
+ "description": "Arguments to pass to the script/flow that computes the WebSocket URL",
"$ref": "#/components/schemas/ScriptArgs"
},
"can_return_message": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, the script can return a message to send back through the WebSocket"
+ },
+ "can_return_error_result": {
+ "type": "boolean",
+ "description": "If true, error results are sent back through the WebSocket"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
+ "description": "Arguments to pass to the error handler",
"$ref": "#/components/schemas/ScriptArgs"
},
"retry": {
+ "description": "Retry configuration for failed executions",
"$ref": "#/components/schemas/Retry"
}
},
@@ -25841,26 +33399,32 @@
"url",
"is_flow",
"filters",
- "can_return_message"
+ "can_return_message",
+ "can_return_error_result"
]
},
"EditWebsocketTrigger": {
"type": "object",
"properties": {
"url": {
- "type": "string"
+ "type": "string",
+ "description": "The WebSocket URL to connect to (can be a static URL or computed by a runnable)"
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
"filters": {
"type": "array",
+ "description": "Array of key-value filters to match incoming messages (only matching messages trigger the script)",
"items": {
"type": "object",
"properties": {
@@ -25877,23 +33441,33 @@
},
"initial_messages": {
"type": "array",
+ "description": "Messages to send immediately after connecting (can be raw strings or computed by runnables)",
"items": {
"$ref": "#/components/schemas/WebsocketTriggerInitialMessage"
}
},
"url_runnable_args": {
+ "description": "Arguments to pass to the script/flow that computes the WebSocket URL",
"$ref": "#/components/schemas/ScriptArgs"
},
"can_return_message": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, the script can return a message to send back through the WebSocket"
+ },
+ "can_return_error_result": {
+ "type": "boolean",
+ "description": "If true, error results are sent back through the WebSocket"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
+ "description": "Arguments to pass to the error handler",
"$ref": "#/components/schemas/ScriptArgs"
},
"retry": {
+ "description": "Retry configuration for failed executions",
"$ref": "#/components/schemas/Retry"
}
},
@@ -25903,7 +33477,8 @@
"url",
"is_flow",
"filters",
- "can_return_message"
+ "can_return_message",
+ "can_return_error_result"
]
},
"WebsocketTriggerInitialMessage": {
@@ -26009,51 +33584,59 @@
"type": "object",
"properties": {
"mqtt_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the MQTT resource containing broker connection configuration"
},
"subscribe_topics": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MqttSubscribeTopic"
- }
+ },
+ "description": "Array of MQTT topics to subscribe to, each with topic name and QoS level"
},
"v3_config": {
- "$ref": "#/components/schemas/MqttV3Config"
+ "$ref": "#/components/schemas/MqttV3Config",
+ "description": "MQTT v3 specific configuration (clean_session)"
},
"v5_config": {
- "$ref": "#/components/schemas/MqttV5Config"
+ "$ref": "#/components/schemas/MqttV5Config",
+ "description": "MQTT v5 specific configuration (clean_start, topic_alias_maximum, session_expiry_interval)"
},
"client_id": {
- "type": "string"
+ "type": "string",
+ "description": "MQTT client ID for this connection"
},
"client_version": {
- "$ref": "#/components/schemas/MqttClientVersion"
+ "$ref": "#/components/schemas/MqttClientVersion",
+ "description": "MQTT protocol version ('v3' or 'v5')"
},
"server_id": {
- "type": "string"
+ "type": "string",
+ "description": "ID of the server currently handling this trigger (internal)"
},
"last_server_ping": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "Timestamp of last server heartbeat (internal)"
},
"error": {
- "type": "string"
- },
- "enabled": {
- "type": "boolean"
+ "type": "string",
+ "description": "Last error message if the trigger failed"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
- "enabled",
"subscribe_topics",
"mqtt_resource_path"
]
@@ -26062,46 +33645,58 @@
"type": "object",
"properties": {
"mqtt_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the MQTT resource containing broker connection configuration"
},
"subscribe_topics": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MqttSubscribeTopic"
- }
+ },
+ "description": "Array of MQTT topics to subscribe to, each with topic name and QoS level"
},
"client_id": {
- "type": "string"
+ "type": "string",
+ "description": "MQTT client ID for this connection"
},
"v3_config": {
- "$ref": "#/components/schemas/MqttV3Config"
+ "$ref": "#/components/schemas/MqttV3Config",
+ "description": "MQTT v3 specific configuration (clean_session)"
},
"v5_config": {
- "$ref": "#/components/schemas/MqttV5Config"
+ "$ref": "#/components/schemas/MqttV5Config",
+ "description": "MQTT v5 specific configuration (clean_start, topic_alias_maximum, session_expiry_interval)"
},
"client_version": {
- "$ref": "#/components/schemas/MqttClientVersion"
+ "$ref": "#/components/schemas/MqttClientVersion",
+ "description": "MQTT protocol version ('v3' or 'v5')"
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -26116,46 +33711,58 @@
"type": "object",
"properties": {
"mqtt_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the MQTT resource containing broker connection configuration"
},
"subscribe_topics": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MqttSubscribeTopic"
- }
+ },
+ "description": "Array of MQTT topics to subscribe to, each with topic name and QoS level"
},
"client_id": {
- "type": "string"
+ "type": "string",
+ "description": "MQTT client ID for this connection"
},
"v3_config": {
- "$ref": "#/components/schemas/MqttV3Config"
+ "$ref": "#/components/schemas/MqttV3Config",
+ "description": "MQTT v3 specific configuration (clean_session)"
},
"v5_config": {
- "$ref": "#/components/schemas/MqttV5Config"
+ "$ref": "#/components/schemas/MqttV5Config",
+ "description": "MQTT v5 specific configuration (clean_start, topic_alias_maximum, session_expiry_interval)"
},
"client_version": {
- "$ref": "#/components/schemas/MqttClientVersion"
+ "$ref": "#/components/schemas/MqttClientVersion",
+ "description": "MQTT protocol version ('v3' or 'v5')"
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -26172,16 +33779,20 @@
"enum": [
"push",
"pull"
- ]
+ ],
+ "description": "Delivery mode for messages. 'push' for HTTP push delivery where messages are sent to a webhook endpoint, 'pull' for polling where the trigger actively fetches messages."
},
"PushConfig": {
"type": "object",
+ "description": "Configuration for push delivery mode.",
"properties": {
"audience": {
- "type": "string"
+ "type": "string",
+ "description": "The audience claim for OIDC tokens used in push authentication."
},
"authenticate": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, push messages will include OIDC authentication tokens."
}
},
"required": [
@@ -26196,18 +33807,23 @@
}
],
"type": "object",
+ "description": "A Google Cloud Pub/Sub trigger that executes a script or flow when messages are received.",
"properties": {
"gcp_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the GCP resource containing service account credentials for authentication."
},
"topic_id": {
- "type": "string"
+ "type": "string",
+ "description": "Google Cloud Pub/Sub topic ID to subscribe to."
},
"subscription_id": {
- "type": "string"
+ "type": "string",
+ "description": "Google Cloud Pub/Sub subscription ID."
},
"server_id": {
- "type": "string"
+ "type": "string",
+ "description": "ID of the server currently handling this trigger (internal use)."
},
"delivery_type": {
"$ref": "#/components/schemas/DeliveryType"
@@ -26220,29 +33836,30 @@
},
"last_server_ping": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "Timestamp of last server heartbeat (internal use)."
},
"error": {
- "type": "string"
- },
- "enabled": {
- "type": "boolean"
+ "type": "string",
+ "description": "Last error message if the trigger failed."
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails."
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler."
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions."
}
},
"required": [
"gcp_resource_path",
"topic_id",
"subscription_id",
- "enabled",
"delivery_type",
"subscription_mode"
]
@@ -26257,21 +33874,26 @@
},
"GcpTriggerData": {
"type": "object",
+ "description": "Data for creating or updating a Google Cloud Pub/Sub trigger.",
"properties": {
"gcp_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the GCP resource containing service account credentials for authentication."
},
"subscription_mode": {
"$ref": "#/components/schemas/SubscriptionMode"
},
"topic_id": {
- "type": "string"
+ "type": "string",
+ "description": "Google Cloud Pub/Sub topic ID to subscribe to."
},
"subscription_id": {
- "type": "string"
+ "type": "string",
+ "description": "Google Cloud Pub/Sub subscription ID."
},
"base_endpoint": {
- "type": "string"
+ "type": "string",
+ "description": "Base URL for push delivery endpoint."
},
"delivery_type": {
"$ref": "#/components/schemas/DeliveryType"
@@ -26280,28 +33902,42 @@
"$ref": "#/components/schemas/PushConfig"
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger."
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received."
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script."
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"auto_acknowledge_msg": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, automatically acknowledge messages after processing."
+ },
+ "ack_deadline": {
+ "type": "integer",
+ "format": "int32",
+ "minimum": 10,
+ "maximum": 600,
+ "description": "Time in seconds within which the message must be acknowledged. If not provided, defaults to the subscription's acknowledgment deadline (600 seconds)."
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails."
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler."
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions."
}
},
"required": [
@@ -26351,88 +33987,168 @@
"type": "object",
"properties": {
"queue_url": {
- "type": "string"
+ "type": "string",
+ "description": "The full URL of the AWS SQS queue to poll for messages"
},
"aws_auth_resource_type": {
- "$ref": "#/components/schemas/AwsAuthResourceType"
+ "$ref": "#/components/schemas/AwsAuthResourceType",
+ "description": "Authentication type - 'credentials' for access key/secret, 'oidc' for OpenID Connect"
},
"aws_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the AWS resource containing credentials or OIDC configuration"
},
"message_attributes": {
"type": "array",
"items": {
"type": "string"
- }
+ },
+ "description": "Array of SQS message attribute names to include with each message"
},
"server_id": {
- "type": "string"
+ "type": "string",
+ "description": "ID of the server currently handling this trigger (internal)"
},
"last_server_ping": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "Timestamp of last server heartbeat (internal)"
},
"error": {
- "type": "string"
- },
- "enabled": {
- "type": "boolean"
+ "type": "string",
+ "description": "Last error message if the trigger failed"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
"queue_url",
"aws_resource_path",
- "enabled",
"aws_auth_resource_type"
]
},
+ "LoggedWizardStatus": {
+ "type": "string",
+ "enum": [
+ "OK",
+ "SKIP",
+ "FAIL"
+ ]
+ },
+ "CustomInstanceDbLogs": {
+ "type": "object",
+ "properties": {
+ "super_admin": {
+ "$ref": "#/components/schemas/LoggedWizardStatus"
+ },
+ "database_credentials": {
+ "$ref": "#/components/schemas/LoggedWizardStatus"
+ },
+ "valid_dbname": {
+ "$ref": "#/components/schemas/LoggedWizardStatus"
+ },
+ "created_database": {
+ "$ref": "#/components/schemas/LoggedWizardStatus"
+ },
+ "db_connect": {
+ "$ref": "#/components/schemas/LoggedWizardStatus"
+ },
+ "grant_permissions": {
+ "$ref": "#/components/schemas/LoggedWizardStatus"
+ }
+ }
+ },
+ "CustomInstanceDbTag": {
+ "type": "string",
+ "enum": [
+ "ducklake",
+ "datatable"
+ ]
+ },
+ "CustomInstanceDb": {
+ "type": "object",
+ "required": [
+ "logs",
+ "success"
+ ],
+ "properties": {
+ "logs": {
+ "$ref": "#/components/schemas/CustomInstanceDbLogs"
+ },
+ "success": {
+ "type": "boolean",
+ "description": "Whether the operation completed successfully",
+ "example": true
+ },
+ "error": {
+ "type": "string",
+ "nullable": true,
+ "description": "Error message if the operation failed",
+ "example": "Connection timeout"
+ },
+ "tag": {
+ "$ref": "#/components/schemas/CustomInstanceDbTag"
+ }
+ }
+ },
"NewSqsTrigger": {
"type": "object",
"properties": {
"queue_url": {
- "type": "string"
+ "type": "string",
+ "description": "The full URL of the AWS SQS queue to poll for messages"
},
"aws_auth_resource_type": {
- "$ref": "#/components/schemas/AwsAuthResourceType"
+ "$ref": "#/components/schemas/AwsAuthResourceType",
+ "description": "Authentication type - 'credentials' for access key/secret, 'oidc' for OpenID Connect"
},
"aws_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the AWS resource containing credentials or OIDC configuration"
},
"message_attributes": {
"type": "array",
"items": {
"type": "string"
- }
+ },
+ "description": "Array of SQS message attribute names to include with each message"
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -26448,40 +34164,50 @@
"type": "object",
"properties": {
"queue_url": {
- "type": "string"
+ "type": "string",
+ "description": "The full URL of the AWS SQS queue to poll for messages"
},
"aws_auth_resource_type": {
- "$ref": "#/components/schemas/AwsAuthResourceType"
+ "$ref": "#/components/schemas/AwsAuthResourceType",
+ "description": "Authentication type - 'credentials' for access key/secret, 'oidc' for OpenID Connect"
},
"aws_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the AWS resource containing credentials or OIDC configuration"
},
"message_attributes": {
"type": "array",
"items": {
"type": "string"
- }
+ },
+ "description": "Array of SQS message attribute names to include with each message"
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -26607,40 +34333,45 @@
],
"type": "object",
"properties": {
- "enabled": {
- "type": "boolean"
- },
"postgres_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the PostgreSQL resource containing connection configuration"
},
"publication_name": {
- "type": "string"
+ "type": "string",
+ "description": "Name of the PostgreSQL publication to subscribe to for change data capture"
},
"server_id": {
- "type": "string"
+ "type": "string",
+ "description": "ID of the server currently handling this trigger (internal)"
},
"replication_slot_name": {
- "type": "string"
+ "type": "string",
+ "description": "Name of the PostgreSQL logical replication slot to use"
},
"error": {
- "type": "string"
+ "type": "string",
+ "description": "Last error message if the trigger failed"
},
"last_server_ping": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "Timestamp of last server heartbeat (internal)"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
- "enabled",
"postgres_resource_path",
"replication_slot_name",
"publication_name"
@@ -26650,37 +34381,47 @@
"type": "object",
"properties": {
"replication_slot_name": {
- "type": "string"
+ "type": "string",
+ "description": "Name of the PostgreSQL logical replication slot to use"
},
"publication_name": {
- "type": "string"
+ "type": "string",
+ "description": "Name of the PostgreSQL publication to subscribe to for change data capture"
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when database changes are detected"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"postgres_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the PostgreSQL resource containing connection configuration"
},
"publication": {
- "$ref": "#/components/schemas/PublicationData"
+ "$ref": "#/components/schemas/PublicationData",
+ "description": "Configuration for creating/managing the publication (tables, operations)"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -26695,37 +34436,47 @@
"type": "object",
"properties": {
"replication_slot_name": {
- "type": "string"
+ "type": "string",
+ "description": "Name of the PostgreSQL logical replication slot to use"
},
"publication_name": {
- "type": "string"
+ "type": "string",
+ "description": "Name of the PostgreSQL publication to subscribe to for change data capture"
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when database changes are detected"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"postgres_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the PostgreSQL resource containing connection configuration"
},
"publication": {
- "$ref": "#/components/schemas/PublicationData"
+ "$ref": "#/components/schemas/PublicationData",
+ "description": "Configuration for creating/managing the publication (tables, operations)"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -26747,82 +34498,129 @@
"type": "object",
"properties": {
"kafka_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the Kafka resource containing connection configuration"
},
"group_id": {
- "type": "string"
+ "type": "string",
+ "description": "Kafka consumer group ID for this trigger"
},
"topics": {
"type": "array",
"items": {
"type": "string"
+ },
+ "description": "Array of Kafka topic names to subscribe to"
+ },
+ "filters": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "value": {}
+ },
+ "required": [
+ "key",
+ "value"
+ ]
}
},
"server_id": {
- "type": "string"
+ "type": "string",
+ "description": "ID of the server currently handling this trigger (internal)"
},
"last_server_ping": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "Timestamp of last server heartbeat (internal)"
},
"error": {
- "type": "string"
- },
- "enabled": {
- "type": "boolean"
+ "type": "string",
+ "description": "Last error message if the trigger failed"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
"kafka_resource_path",
"group_id",
"topics",
- "enabled"
+ "filters"
]
},
"NewKafkaTrigger": {
"type": "object",
"properties": {
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
"kafka_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the Kafka resource containing connection configuration"
},
"group_id": {
- "type": "string"
+ "type": "string",
+ "description": "Kafka consumer group ID for this trigger"
},
"topics": {
"type": "array",
"items": {
"type": "string"
+ },
+ "description": "Array of Kafka topic names to subscribe to"
+ },
+ "filters": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "value": {}
+ },
+ "required": [
+ "key",
+ "value"
+ ]
}
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -26831,41 +34629,67 @@
"is_flow",
"kafka_resource_path",
"group_id",
- "topics"
+ "topics",
+ "filters"
]
},
"EditKafkaTrigger": {
"type": "object",
"properties": {
"kafka_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the Kafka resource containing connection configuration"
},
"group_id": {
- "type": "string"
+ "type": "string",
+ "description": "Kafka consumer group ID for this trigger"
},
"topics": {
"type": "array",
"items": {
"type": "string"
+ },
+ "description": "Array of Kafka topic names to subscribe to"
+ },
+ "filters": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "value": {}
+ },
+ "required": [
+ "key",
+ "value"
+ ]
}
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -26874,6 +34698,7 @@
"kafka_resource_path",
"group_id",
"topics",
+ "filters",
"is_flow"
]
},
@@ -26886,94 +34711,112 @@
"type": "object",
"properties": {
"nats_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the NATS resource containing connection configuration"
},
"use_jetstream": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, uses NATS JetStream for durable message delivery"
},
"stream_name": {
- "type": "string"
+ "type": "string",
+ "description": "JetStream stream name (required when use_jetstream is true)"
},
"consumer_name": {
- "type": "string"
+ "type": "string",
+ "description": "JetStream consumer name (required when use_jetstream is true)"
},
"subjects": {
"type": "array",
"items": {
"type": "string"
- }
+ },
+ "description": "Array of NATS subjects to subscribe to"
},
"server_id": {
- "type": "string"
+ "type": "string",
+ "description": "ID of the server currently handling this trigger (internal)"
},
"last_server_ping": {
"type": "string",
- "format": "date-time"
+ "format": "date-time",
+ "description": "Timestamp of last server heartbeat (internal)"
},
"error": {
- "type": "string"
- },
- "enabled": {
- "type": "boolean"
+ "type": "string",
+ "description": "Last error message if the trigger failed"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
"nats_resource_path",
"use_jetstream",
- "subjects",
- "enabled"
+ "subjects"
]
},
"NewNatsTrigger": {
"type": "object",
"properties": {
"path": {
- "type": "string"
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
},
"script_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
},
"is_flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
},
"nats_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the NATS resource containing connection configuration"
},
"use_jetstream": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, uses NATS JetStream for durable message delivery"
},
"stream_name": {
- "type": "string"
+ "type": "string",
+ "description": "JetStream stream name (required when use_jetstream is true)"
},
"consumer_name": {
- "type": "string"
+ "type": "string",
+ "description": "JetStream consumer name (required when use_jetstream is true)"
},
"subjects": {
"type": "array",
"items": {
"type": "string"
- }
+ },
+ "description": "Array of NATS subjects to subscribe to"
},
- "enabled": {
- "type": "boolean"
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
},
"error_handler_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
},
"error_handler_args": {
- "$ref": "#/components/schemas/ScriptArgs"
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
},
"retry": {
- "$ref": "#/components/schemas/Retry"
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
}
},
"required": [
@@ -26989,29 +34832,143 @@
"type": "object",
"properties": {
"nats_resource_path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the NATS resource containing connection configuration"
},
"use_jetstream": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, uses NATS JetStream for durable message delivery"
},
"stream_name": {
- "type": "string"
+ "type": "string",
+ "description": "JetStream stream name (required when use_jetstream is true)"
},
"consumer_name": {
- "type": "string"
+ "type": "string",
+ "description": "JetStream consumer name (required when use_jetstream is true)"
},
"subjects": {
"type": "array",
"items": {
"type": "string"
- }
+ },
+ "description": "Array of NATS subjects to subscribe to"
},
+ "path": {
+ "type": "string",
+ "description": "The unique path identifier for this trigger"
+ },
+ "script_path": {
+ "type": "string",
+ "description": "Path to the script or flow to execute when a message is received"
+ },
+ "is_flow": {
+ "type": "boolean",
+ "description": "True if script_path points to a flow, false if it points to a script"
+ },
+ "error_handler_path": {
+ "type": "string",
+ "description": "Path to a script or flow to run when the triggered job fails"
+ },
+ "error_handler_args": {
+ "$ref": "#/components/schemas/ScriptArgs",
+ "description": "Arguments to pass to the error handler"
+ },
+ "retry": {
+ "$ref": "#/components/schemas/Retry",
+ "description": "Retry configuration for failed executions"
+ }
+ },
+ "required": [
+ "path",
+ "script_path",
+ "nats_resource_path",
+ "use_jetstream",
+ "subjects",
+ "is_flow"
+ ]
+ },
+ "EmailTrigger": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/TriggerExtraProperty"
+ }
+ ],
+ "type": "object",
+ "properties": {
+ "local_part": {
+ "type": "string"
+ },
+ "workspaced_local_part": {
+ "type": "boolean"
+ },
+ "error_handler_path": {
+ "type": "string"
+ },
+ "error_handler_args": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ },
+ "retry": {
+ "$ref": "#/components/schemas/Retry"
+ }
+ },
+ "required": [
+ "local_part"
+ ]
+ },
+ "NewEmailTrigger": {
+ "type": "object",
+ "properties": {
"path": {
"type": "string"
},
"script_path": {
"type": "string"
},
+ "local_part": {
+ "type": "string"
+ },
+ "workspaced_local_part": {
+ "type": "boolean"
+ },
+ "is_flow": {
+ "type": "boolean"
+ },
+ "error_handler_path": {
+ "type": "string"
+ },
+ "error_handler_args": {
+ "$ref": "#/components/schemas/ScriptArgs"
+ },
+ "retry": {
+ "$ref": "#/components/schemas/Retry"
+ },
+ "mode": {
+ "$ref": "#/components/schemas/TriggerMode"
+ }
+ },
+ "required": [
+ "path",
+ "script_path",
+ "local_part",
+ "is_flow"
+ ]
+ },
+ "EditEmailTrigger": {
+ "type": "object",
+ "properties": {
+ "path": {
+ "type": "string"
+ },
+ "script_path": {
+ "type": "string"
+ },
+ "local_part": {
+ "type": "string"
+ },
+ "workspaced_local_part": {
+ "type": "boolean"
+ },
"is_flow": {
"type": "boolean"
},
@@ -27028,9 +34985,6 @@
"required": [
"path",
"script_path",
- "nats_resource_path",
- "use_jetstream",
- "subjects",
"is_flow"
]
},
@@ -27062,6 +35016,9 @@
},
"InstanceGroup": {
"type": "object",
+ "required": [
+ "name"
+ ],
"properties": {
"name": {
"type": "string"
@@ -27075,6 +35032,46 @@
"type": "string"
}
}
+ }
+ },
+ "InstanceGroupWithWorkspaces": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "summary": {
+ "type": "string"
+ },
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "workspaces": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/WorkspaceInfo"
+ }
+ }
+ }
+ },
+ "WorkspaceInfo": {
+ "type": "object",
+ "properties": {
+ "workspace_id": {
+ "type": "string"
+ },
+ "workspace_name": {
+ "type": "string"
+ },
+ "role": {
+ "type": "string"
+ }
},
"required": [
"name"
@@ -27178,6 +35175,9 @@
},
"wm_memory_usage": {
"type": "number"
+ },
+ "job_isolation": {
+ "type": "string"
}
},
"required": [
@@ -27216,13 +35216,25 @@
},
"operator_settings": {
"$ref": "#/components/schemas/OperatorSettings"
+ },
+ "parent_workspace_id": {
+ "type": "string",
+ "nullable": true
+ },
+ "created_by": {
+ "type": "string",
+ "nullable": true
+ },
+ "disabled": {
+ "type": "boolean"
}
},
"required": [
"id",
"name",
"username",
- "color"
+ "color",
+ "disabled"
]
}
}
@@ -27253,6 +35265,25 @@
"name"
]
},
+ "CreateWorkspaceFork": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "color": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "name",
+ "parent_workspace_id"
+ ]
+ },
"Workspace": {
"type": "object",
"properties": {
@@ -27270,12 +35301,85 @@
},
"color": {
"type": "string"
+ },
+ "parent_workspace_id": {
+ "type": "string",
+ "nullable": true
}
},
"required": [
"id",
"name",
- "owner"
+ "owner",
+ "created_at"
+ ]
+ },
+ "DependencyMap": {
+ "type": "object",
+ "properties": {
+ "workspace_id": {
+ "type": "string",
+ "nullable": true
+ },
+ "importer_path": {
+ "type": "string",
+ "nullable": true
+ },
+ "importer_kind": {
+ "type": "string",
+ "nullable": true
+ },
+ "imported_path": {
+ "type": "string",
+ "nullable": true
+ },
+ "importer_node_id": {
+ "type": "string",
+ "nullable": true
+ }
+ }
+ },
+ "DependencyDependent": {
+ "type": "object",
+ "properties": {
+ "importer_path": {
+ "type": "string"
+ },
+ "importer_kind": {
+ "type": "string",
+ "enum": [
+ "script",
+ "flow",
+ "app"
+ ]
+ },
+ "importer_node_ids": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "nullable": true
+ }
+ },
+ "required": [
+ "importer_path",
+ "importer_kind"
+ ]
+ },
+ "DependentsAmount": {
+ "type": "object",
+ "properties": {
+ "imported_path": {
+ "type": "string"
+ },
+ "count": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ "required": [
+ "imported_path",
+ "count"
]
},
"WorkspaceInvite": {
@@ -27292,6 +35396,10 @@
},
"operator": {
"type": "boolean"
+ },
+ "parent_workspace_id": {
+ "type": "string",
+ "nullable": true
}
},
"required": [
@@ -27334,13 +35442,17 @@
},
"operator_only": {
"type": "boolean"
+ },
+ "first_time_user": {
+ "type": "boolean"
}
},
"required": [
"email",
"login_type",
"super_admin",
- "verified"
+ "verified",
+ "first_time_user"
]
},
"Flow": {
@@ -27356,6 +35468,9 @@
"properties": {
"lock_error_logs": {
"type": "string"
+ },
+ "version_id": {
+ "type": "number"
}
}
}
@@ -27501,6 +35616,9 @@
},
"branch_or_iteration_n": {
"type": "integer"
+ },
+ "flow_version": {
+ "type": "integer"
}
}
},
@@ -27720,9 +35838,7 @@
"type": "string",
"format": "date-time"
},
- "value": {
- "type": "object"
- },
+ "value": {},
"policy": {
"$ref": "#/components/schemas/Policy"
},
@@ -27742,6 +35858,12 @@
},
"custom_path": {
"type": "string"
+ },
+ "raw_app": {
+ "type": "boolean"
+ },
+ "bundle_secret": {
+ "type": "string"
}
},
"required": [
@@ -27755,7 +35877,8 @@
"value",
"policy",
"execution_mode",
- "extra_perms"
+ "extra_perms",
+ "raw_app"
]
},
"AppWithLastVersionWDraft": {
@@ -27906,6 +36029,12 @@
"public_resource": {
"type": "boolean"
},
+ "advanced_permissions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/S3PermissionRule"
+ }
+ },
"secondary_storage": {
"type": "object",
"additionalProperties": {
@@ -27985,12 +36114,150 @@
"required": [
"path"
]
+ },
+ "extra_args": {
+ "type": "string"
}
}
}
}
}
},
+ "DataTableSettings": {
+ "type": "object",
+ "required": [
+ "datatables"
+ ],
+ "properties": {
+ "datatables": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "required": [
+ "database"
+ ],
+ "properties": {
+ "database": {
+ "type": "object",
+ "properties": {
+ "resource_type": {
+ "type": "string",
+ "enum": [
+ "postgresql",
+ "instance"
+ ]
+ },
+ "resource_path": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "resource_type"
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "DataTableSchema": {
+ "type": "object",
+ "required": [
+ "datatable_name",
+ "schemas"
+ ],
+ "properties": {
+ "datatable_name": {
+ "type": "string"
+ },
+ "schemas": {
+ "type": "object",
+ "description": "Hierarchical schema: schema_name -> table_name -> column_name -> compact_type (e.g. 'int4', 'text?', 'int4?=0')",
+ "additionalProperties": {
+ "type": "object",
+ "description": "Tables in this schema",
+ "additionalProperties": {
+ "type": "object",
+ "description": "Columns in this table",
+ "additionalProperties": {
+ "type": "string",
+ "description": "Compact type: 'type[?][=default]' where ? means nullable"
+ }
+ }
+ }
+ },
+ "error": {
+ "type": "string"
+ }
+ }
+ },
+ "DynamicInputData": {
+ "type": "object",
+ "properties": {
+ "entrypoint_function": {
+ "type": "string",
+ "description": "Name of the function to execute for dynamic select"
+ },
+ "args": {
+ "type": "object",
+ "description": "Arguments to pass to the function"
+ },
+ "runnable_ref": {
+ "type": "object",
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "source": {
+ "type": "string",
+ "enum": [
+ "deployed"
+ ]
+ },
+ "path": {
+ "type": "string",
+ "description": "Path to the deployed script or flow"
+ },
+ "runnable_kind": {
+ "$ref": "#/components/schemas/RunnableKind"
+ }
+ },
+ "required": [
+ "source",
+ "path",
+ "runnable_kind"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "source": {
+ "type": "string",
+ "enum": [
+ "inline"
+ ]
+ },
+ "code": {
+ "type": "string",
+ "description": "Code content for inline execution"
+ },
+ "language": {
+ "$ref": "#/components/schemas/ScriptLang"
+ }
+ },
+ "required": [
+ "source",
+ "code"
+ ]
+ }
+ ]
+ }
+ },
+ "required": [
+ "entrypoint_function",
+ "runnable_ref"
+ ]
+ },
"WindmillLargeFile": {
"type": "object",
"properties": {
@@ -28130,6 +36397,21 @@
}
}
},
+ "S3PermissionRule": {
+ "type": "object",
+ "properties": {
+ "pattern": {
+ "type": "string"
+ },
+ "allow": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "pattern",
+ "allow"
+ ]
+ },
"GitRepositorySettings": {
"type": "object",
"properties": {
@@ -28189,21 +36471,6 @@
"git_repo_resource_path"
]
},
- "UploadFilePart": {
- "type": "object",
- "properties": {
- "part_number": {
- "type": "integer"
- },
- "tag": {
- "type": "string"
- }
- },
- "required": [
- "part_number",
- "tag"
- ]
- },
"MetricMetadata": {
"type": "object",
"properties": {
@@ -28367,9 +36634,7 @@
"name": {
"type": "string"
},
- "value": {
- "type": "object"
- }
+ "value": {}
},
"required": [
"name",
@@ -28499,12 +36764,13 @@
"http",
"websocket",
"kafka",
- "email",
+ "default_email",
"nats",
"postgres",
"sqs",
"mqtt",
- "gcp"
+ "gcp",
+ "email"
]
},
"Capture": {
@@ -28608,6 +36874,153 @@
}
}
},
+ "WorkspaceComparison": {
+ "type": "object",
+ "required": [
+ "all_ahead_items_visible",
+ "all_behind_items_visible",
+ "skipped_comparison",
+ "diffs",
+ "summary"
+ ],
+ "properties": {
+ "all_ahead_items_visible": {
+ "type": "boolean",
+ "description": "All items with changes ahead are visible by the user of the request."
+ },
+ "all_behind_items_visible": {
+ "type": "boolean",
+ "description": "All items with changes behind are visible by the user of the request."
+ },
+ "skipped_comparison": {
+ "type": "boolean",
+ "description": "Whether the comparison was skipped. This happens with old forks that where not being kept track of"
+ },
+ "diffs": {
+ "type": "array",
+ "description": "List of differences found between workspaces",
+ "items": {
+ "$ref": "#/components/schemas/WorkspaceItemDiff"
+ }
+ },
+ "summary": {
+ "$ref": "#/components/schemas/CompareSummary",
+ "description": "Summary statistics of the comparison"
+ }
+ }
+ },
+ "WorkspaceItemDiff": {
+ "type": "object",
+ "required": [
+ "kind",
+ "path",
+ "ahead",
+ "behind",
+ "has_changes",
+ "exists_in_source",
+ "exists_in_fork"
+ ],
+ "properties": {
+ "kind": {
+ "type": "string",
+ "enum": [
+ "script",
+ "flow",
+ "app",
+ "resource",
+ "variable",
+ "resource_type"
+ ],
+ "description": "Type of the item"
+ },
+ "path": {
+ "type": "string",
+ "description": "Path of the item in the workspace"
+ },
+ "ahead": {
+ "type": "integer",
+ "description": "Number of versions source is ahead of target"
+ },
+ "behind": {
+ "type": "integer",
+ "description": "Number of versions source is behind target"
+ },
+ "has_changes": {
+ "type": "boolean",
+ "description": "Whether the item has any differences"
+ },
+ "exists_in_source": {
+ "type": "boolean",
+ "description": "If the item exists in the source workspace"
+ },
+ "exists_in_fork": {
+ "type": "boolean",
+ "description": "If the item exists in the fork workspace"
+ }
+ }
+ },
+ "CompareSummary": {
+ "type": "object",
+ "required": [
+ "total_diffs",
+ "total_ahead",
+ "total_behind",
+ "scripts_changed",
+ "flows_changed",
+ "apps_changed",
+ "resources_changed",
+ "variables_changed",
+ "resource_types_changed",
+ "folders_changed",
+ "conflicts"
+ ],
+ "properties": {
+ "total_diffs": {
+ "type": "integer",
+ "description": "Total number of items with differences"
+ },
+ "total_ahead": {
+ "type": "integer",
+ "description": "Total number of ahead changes"
+ },
+ "total_behind": {
+ "type": "integer",
+ "description": "Total number of behind changes"
+ },
+ "scripts_changed": {
+ "type": "integer",
+ "description": "Number of scripts with differences"
+ },
+ "flows_changed": {
+ "type": "integer",
+ "description": "Number of flows with differences"
+ },
+ "apps_changed": {
+ "type": "integer",
+ "description": "Number of apps with differences"
+ },
+ "resources_changed": {
+ "type": "integer",
+ "description": "Number of resources with differences"
+ },
+ "variables_changed": {
+ "type": "integer",
+ "description": "Number of variables with differences"
+ },
+ "resource_types_changed": {
+ "type": "integer",
+ "description": "Number of resource types with differences"
+ },
+ "folders_changed": {
+ "type": "integer",
+ "description": "Number of folders with differences"
+ },
+ "conflicts": {
+ "type": "integer",
+ "description": "Number of items that are both ahead and behind (conflicts)"
+ }
+ }
+ },
"TeamInfo": {
"type": "object",
"required": [
@@ -28697,12 +37110,26 @@
"url"
]
}
+ },
+ "total_count": {
+ "type": "number",
+ "description": "Total number of repositories available for this installation"
+ },
+ "per_page": {
+ "type": "number",
+ "description": "Number of repositories loaded per page"
+ },
+ "error": {
+ "type": "string",
+ "description": "Error message if token retrieval failed"
}
},
"required": [
"installation_id",
"account_id",
- "repositories"
+ "repositories",
+ "total_count",
+ "per_page"
]
}
},
@@ -28776,7 +37203,8 @@
"type": "string",
"enum": [
"script",
- "flow"
+ "flow",
+ "job"
]
},
"AssetUsageAccessType": {
@@ -28785,14 +37213,16 @@
"r",
"w",
"rw"
- ]
+ ],
+ "nullable": true
},
"AssetKind": {
"type": "string",
"enum": [
"s3object",
"resource",
- "ducklake"
+ "ducklake",
+ "datatable"
]
},
"Asset": {
@@ -28810,10 +37240,341 @@
"kind"
]
},
- "schemas-StaticTransform": {
+ "ProtectionRuleset": {
+ "type": "object",
+ "description": "A workspace protection rule defining restrictions and bypass permissions",
+ "required": [
+ "name",
+ "rules",
+ "bypass_groups",
+ "bypass_users"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Unique name for the protection rule",
+ "example": "Production Protection"
+ },
+ "workspace_id": {
+ "type": "string"
+ },
+ "rules": {
+ "$ref": "#/components/schemas/ProtectionRules"
+ },
+ "bypass_groups": {
+ "$ref": "#/components/schemas/RuleBypasserGroups"
+ },
+ "bypass_users": {
+ "$ref": "#/components/schemas/RuleBypasserUsers"
+ }
+ }
+ },
+ "ProtectionRules": {
+ "type": "array",
+ "description": "Configuration of protection restrictions",
+ "items": {
+ "$ref": "#/components/schemas/ProtectionRuleKind"
+ }
+ },
+ "ProtectionRuleKind": {
+ "type": "string",
+ "enum": [
+ "DisableDirectDeployment",
+ "DisableWorkspaceForking"
+ ]
+ },
+ "RuleBypasserGroups": {
+ "type": "array",
+ "description": "Groups that can bypass this ruleset",
+ "items": {
+ "type": "string"
+ }
+ },
+ "RuleBypasserUsers": {
+ "type": "array",
+ "description": "Users that can bypass this ruleset",
+ "items": {
+ "type": "string"
+ }
+ },
+ "NativeServiceName": {
+ "type": "string",
+ "enum": [
+ "nextcloud"
+ ]
+ },
+ "NativeTrigger": {
+ "type": "object",
+ "description": "A native trigger stored in Windmill",
+ "properties": {
+ "external_id": {
+ "type": "string",
+ "description": "The unique identifier from the external service"
+ },
+ "workspace_id": {
+ "type": "string",
+ "description": "The workspace this trigger belongs to"
+ },
+ "service_name": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ },
+ "script_path": {
+ "type": "string",
+ "description": "The path to the script or flow that will be triggered"
+ },
+ "is_flow": {
+ "type": "boolean",
+ "description": "Whether the trigger targets a flow (true) or a script (false)"
+ },
+ "service_config": {
+ "type": "object",
+ "description": "Configuration for the trigger including event_type and service_config",
+ "additionalProperties": true
+ },
+ "error": {
+ "type": "string",
+ "nullable": true,
+ "description": "Error message if the trigger is in an error state"
+ }
+ },
+ "required": [
+ "external_id",
+ "workspace_id",
+ "service_name",
+ "script_path",
+ "is_flow",
+ "service_config"
+ ]
+ },
+ "NativeTriggerWithExternal": {
+ "type": "object",
+ "description": "Full trigger response containing both Windmill data and external service data",
+ "properties": {
+ "external_id": {
+ "type": "string",
+ "description": "The unique identifier from the external service"
+ },
+ "workspace_id": {
+ "type": "string",
+ "description": "The workspace this trigger belongs to"
+ },
+ "service_name": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ },
+ "script_path": {
+ "type": "string",
+ "description": "The path to the script or flow that will be triggered"
+ },
+ "is_flow": {
+ "type": "boolean",
+ "description": "Whether the trigger targets a flow (true) or a script (false)"
+ },
+ "service_config": {
+ "type": "object",
+ "description": "Configuration for the trigger including event_type and service_config",
+ "additionalProperties": true
+ },
+ "error": {
+ "type": "string",
+ "nullable": true,
+ "description": "Error message if the trigger is in an error state"
+ },
+ "external_data": {
+ "type": "object",
+ "description": "Configuration data from the external service",
+ "additionalProperties": true
+ }
+ },
+ "required": [
+ "external_id",
+ "workspace_id",
+ "service_name",
+ "script_path",
+ "is_flow",
+ "service_config",
+ "external_data"
+ ]
+ },
+ "WorkspaceIntegrations": {
"type": "object",
"properties": {
- "value": {},
+ "service_name": {
+ "$ref": "#/components/schemas/NativeServiceName"
+ },
+ "oauth_data": {
+ "nullable": true,
+ "$ref": "#/components/schemas/WorkspaceOAuthConfig"
+ }
+ },
+ "required": [
+ "service_name"
+ ]
+ },
+ "WorkspaceOAuthConfig": {
+ "type": "object",
+ "properties": {
+ "client_id": {
+ "type": "string",
+ "description": "The OAuth client ID for the workspace"
+ },
+ "client_secret": {
+ "type": "string",
+ "description": "The OAuth client secret for the workspace"
+ },
+ "base_url": {
+ "type": "string",
+ "format": "uri",
+ "description": "The base URL of the workspace"
+ },
+ "redirect_uri": {
+ "type": "string",
+ "format": "uri",
+ "description": "The OAuth redirect URI"
+ }
+ },
+ "required": [
+ "client_id",
+ "client_secret",
+ "base_url",
+ "redirect_uri"
+ ]
+ },
+ "WebhookEvent": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "webhook"
+ ]
+ },
+ "request_type": {
+ "$ref": "#/components/schemas/WebhookRequestType"
+ }
+ },
+ "required": [
+ "type",
+ "request_type"
+ ]
+ },
+ "WebhookRequestType": {
+ "type": "string",
+ "description": "The type of webhook request (define possible values here)",
+ "enum": [
+ "async",
+ "sync"
+ ]
+ },
+ "RedirectUri": {
+ "type": "object",
+ "properties": {
+ "redirect_uri": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "redirect_uri"
+ ]
+ },
+ "NativeTriggerData": {
+ "type": "object",
+ "description": "Data for creating or updating a native trigger",
+ "properties": {
+ "script_path": {
+ "type": "string",
+ "description": "The path to the script or flow that will be triggered"
+ },
+ "is_flow": {
+ "type": "boolean",
+ "description": "Whether the trigger targets a flow (true) or a script (false)"
+ },
+ "service_config": {
+ "type": "object",
+ "description": "Service-specific configuration (e.g., event types, filters)",
+ "additionalProperties": true
+ }
+ },
+ "required": [
+ "script_path",
+ "is_flow",
+ "service_config"
+ ]
+ },
+ "CreateTriggerResponse": {
+ "type": "object",
+ "description": "Response returned when a native trigger is created",
+ "properties": {
+ "external_id": {
+ "type": "string",
+ "description": "The external ID of the created trigger from the external service"
+ }
+ },
+ "required": [
+ "external_id"
+ ]
+ },
+ "SyncResult": {
+ "type": "object",
+ "properties": {
+ "already_in_sync": {
+ "type": "boolean"
+ },
+ "added_count": {
+ "type": "integer"
+ },
+ "added_triggers": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "total_external": {
+ "type": "integer"
+ },
+ "total_windmill": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "already_in_sync",
+ "added_count",
+ "added_triggers",
+ "total_external",
+ "total_windmill"
+ ]
+ },
+ "NextCloudEventType": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "category": {
+ "type": "string"
+ },
+ "path": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "name",
+ "path"
+ ]
+ },
+ "schemas-StaticTransform": {
+ "type": "object",
+ "description": "Static value passed directly to the step. Use for hardcoded values or resource references like '$res:path/to/resource'",
+ "properties": {
+ "value": {
+ "description": "The static value. For resources, use format '$res:path/to/resource'"
+ },
"type": {
"type": "string",
"enum": [
@@ -28822,15 +37583,16 @@
}
},
"required": [
- "value",
"type"
]
},
"schemas-JavascriptTransform": {
"type": "object",
+ "description": "JavaScript expression evaluated at runtime. Can reference previous step results via 'results.step_id' or flow inputs via 'flow_input.property'. Inside loops, use 'flow_input.iter.value' for the current iteration value",
"properties": {
"expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression returning the value. Available variables - results (object with all previous step results), flow_input (flow inputs), flow_input.iter (in loops)"
},
"type": {
"type": "string",
@@ -28844,37 +37606,61 @@
"type"
]
},
+ "schemas-AiTransform": {
+ "type": "object",
+ "description": "Value resolved by the AI runtime for this input. The AI engine decides how to satisfy the parameter.",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "ai"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
"schemas-InputTransform": {
+ "description": "Maps input parameters for a step. Can be a static value or a JavaScript expression that references previous results or flow inputs",
"oneOf": [
{
"$ref": "#/components/schemas/schemas-StaticTransform"
},
{
"$ref": "#/components/schemas/schemas-JavascriptTransform"
+ },
+ {
+ "$ref": "#/components/schemas/schemas-AiTransform"
}
],
"discriminator": {
"propertyName": "type",
"mapping": {
"static": "#/components/schemas/schemas-StaticTransform",
- "javascript": "#/components/schemas/schemas-JavascriptTransform"
+ "javascript": "#/components/schemas/schemas-JavascriptTransform",
+ "ai": "#/components/schemas/schemas-AiTransform"
}
}
},
"schemas-RawScript": {
"type": "object",
+ "description": "Inline script with code defined directly in the flow. Use 'bun' as default language if unspecified. The script receives arguments from input_transforms",
"properties": {
"input_transforms": {
"type": "object",
+ "description": "Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments",
"additionalProperties": {
"$ref": "#/components/schemas/schemas-InputTransform"
}
},
"content": {
- "type": "string"
+ "type": "string",
+ "description": "The script source code. Should export a 'main' function"
},
"language": {
"type": "string",
+ "description": "Programming language for this script",
"enum": [
"deno",
"bun",
@@ -28890,14 +37676,23 @@
"oracledb",
"graphql",
"nativets",
- "php"
+ "php",
+ "rust",
+ "ansible",
+ "csharp",
+ "nu",
+ "java",
+ "ruby",
+ "duckdb"
]
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "Optional path for saving this script"
},
"lock": {
- "type": "string"
+ "type": "string",
+ "description": "Lock file content for dependencies"
},
"type": {
"type": "string",
@@ -28906,22 +37701,28 @@
]
},
"tag": {
- "type": "string"
+ "type": "string",
+ "description": "Worker group tag for execution routing"
},
"concurrent_limit": {
- "type": "number"
+ "type": "number",
+ "description": "Maximum concurrent executions of this script"
},
"concurrency_time_window_s": {
- "type": "number"
+ "type": "number",
+ "description": "Time window for concurrent_limit"
},
"custom_concurrency_key": {
- "type": "string"
+ "type": "string",
+ "description": "Custom key for grouping concurrent executions"
},
"is_trigger": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, this script is a trigger that can start the flow"
},
"assets": {
"type": "array",
+ "description": "External resources this script accesses (S3 objects, resources, etc.)",
"items": {
"type": "object",
"required": [
@@ -28930,18 +37731,23 @@
],
"properties": {
"path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the asset"
},
"kind": {
"type": "string",
+ "description": "Type of asset",
"enum": [
"s3object",
"resource",
- "ducklake"
+ "ducklake",
+ "datatable"
]
},
"access_type": {
"type": "string",
+ "nullable": true,
+ "description": "Access level for this asset",
"enum": [
"r",
"w",
@@ -28950,6 +37756,8 @@
},
"alt_access_type": {
"type": "string",
+ "nullable": true,
+ "description": "Alternative access level",
"enum": [
"r",
"w",
@@ -28969,18 +37777,22 @@
},
"schemas-PathScript": {
"type": "object",
+ "description": "Reference to an existing script by path. Use this when calling a previously saved script instead of writing inline code",
"properties": {
"input_transforms": {
"type": "object",
+ "description": "Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments",
"additionalProperties": {
"$ref": "#/components/schemas/schemas-InputTransform"
}
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the script in the workspace (e.g., 'f/scripts/send_email')"
},
"hash": {
- "type": "string"
+ "type": "string",
+ "description": "Optional specific version hash of the script to use"
},
"type": {
"type": "string",
@@ -28989,10 +37801,12 @@
]
},
"tag_override": {
- "type": "string"
+ "type": "string",
+ "description": "Override the script's default worker group tag"
},
"is_trigger": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, this script is a trigger that can start the flow"
}
},
"required": [
@@ -29003,15 +37817,18 @@
},
"schemas-PathFlow": {
"type": "object",
+ "description": "Reference to an existing flow by path. Use this to call another flow as a subflow",
"properties": {
"input_transforms": {
"type": "object",
+ "description": "Map of parameter names to their values (static or JavaScript expressions). These become the subflow's input arguments",
"additionalProperties": {
"$ref": "#/components/schemas/schemas-InputTransform"
}
},
"path": {
- "type": "string"
+ "type": "string",
+ "description": "Path to the flow in the workspace (e.g., 'f/flows/process_user')"
},
"type": {
"type": "string",
@@ -29028,24 +37845,30 @@
},
"schemas-FlowModule": {
"type": "object",
+ "description": "A single step in a flow. Can be a script, subflow, loop, or branch",
"properties": {
"id": {
- "type": "string"
+ "type": "string",
+ "description": "Unique identifier for this step. Used to reference results via 'results.step_id'. Must be a valid identifier (alphanumeric, underscore, hyphen)"
},
"value": {
"$ref": "#/components/schemas/schemas-FlowModuleValue"
},
"stop_after_if": {
+ "description": "Early termination condition evaluated after this step completes",
"$ref": "#/components/schemas/schemas-StopAfterIf"
},
"stop_after_all_iters_if": {
+ "description": "For loops only - early termination condition evaluated after all iterations complete",
"$ref": "#/components/schemas/schemas-StopAfterIf"
},
"skip_if": {
"type": "object",
+ "description": "Conditionally skip this step based on previous results or flow inputs",
"properties": {
"expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression that returns true to skip. Can use 'flow_input' or 'results.'"
}
},
"required": [
@@ -29053,70 +37876,95 @@
]
},
"sleep": {
+ "description": "Delay before executing this step (in seconds or as expression)",
"$ref": "#/components/schemas/schemas-InputTransform"
},
"cache_ttl": {
- "type": "number"
+ "type": "number",
+ "description": "Cache duration in seconds for this step's results"
},
- "timeout": {
- "type": "number"
- },
- "delete_after_use": {
+ "cache_ignore_s3_path": {
"type": "boolean"
},
+ "timeout": {
+ "description": "Maximum execution time in seconds (static value or expression)",
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ },
+ "delete_after_use": {
+ "type": "boolean",
+ "description": "If true, this step's result is deleted after use to save memory"
+ },
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short description of what this step does"
},
"mock": {
"type": "object",
+ "description": "Mock configuration for testing without executing the actual step",
"properties": {
"enabled": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, return mock value instead of executing"
},
- "return_value": {}
+ "return_value": {
+ "description": "Value to return when mocked"
+ }
}
},
"suspend": {
"type": "object",
+ "description": "Configuration for approval/resume steps that wait for user input",
"properties": {
"required_events": {
- "type": "integer"
+ "type": "integer",
+ "description": "Number of approvals required before continuing"
},
"timeout": {
- "type": "integer"
+ "type": "integer",
+ "description": "Timeout in seconds before auto-continuing or canceling"
},
"resume_form": {
"type": "object",
+ "description": "Form schema for collecting input when resuming",
"properties": {
"schema": {
- "type": "object"
+ "type": "object",
+ "description": "JSON Schema for the resume form"
}
}
},
"user_auth_required": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, only authenticated users can approve"
},
"user_groups_required": {
+ "description": "Expression or list of groups that can approve",
"$ref": "#/components/schemas/schemas-InputTransform"
},
"self_approval_disabled": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, the user who started the flow cannot approve"
},
"hide_cancel": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, hide the cancel button on the approval form"
},
"continue_on_disapprove_timeout": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, continue flow on timeout instead of canceling"
}
}
},
"priority": {
- "type": "number"
+ "type": "number",
+ "description": "Execution priority for this step (higher numbers run first)"
},
"continue_on_error": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, flow continues even if this step fails"
},
"retry": {
+ "description": "Retry configuration if this step fails",
"$ref": "#/components/schemas/schemas-Retry"
}
},
@@ -29127,18 +37975,22 @@
},
"schemas-ForloopFlow": {
"type": "object",
+ "description": "Executes nested modules in a loop over an iterator. Inside the loop, use 'flow_input.iter.value' to access the current iteration value, and 'flow_input.iter.index' for the index. Supports parallel execution for better performance on I/O-bound operations",
"properties": {
"modules": {
"type": "array",
+ "description": "Steps to execute for each iteration. These can reference the iteration value via 'flow_input.iter.value'",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
},
"iterator": {
+ "description": "JavaScript expression that returns an array to iterate over. Can reference 'results.step_id' or 'flow_input'",
"$ref": "#/components/schemas/schemas-InputTransform"
},
"skip_failures": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, iteration failures don't stop the loop. Failed iterations return null"
},
"type": {
"type": "string",
@@ -29147,10 +37999,15 @@
]
},
"parallel": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, iterations run concurrently (faster for I/O-bound operations). Use with parallelism to control concurrency"
},
"parallelism": {
- "type": "integer"
+ "description": "Maximum number of concurrent iterations when parallel=true. Limits resource usage. Can be static number or expression",
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ },
+ "squash": {
+ "type": "boolean"
}
},
"required": [
@@ -29162,15 +38019,18 @@
},
"schemas-WhileloopFlow": {
"type": "object",
+ "description": "Executes nested modules repeatedly while a condition is true. The loop checks the condition after each iteration. Use stop_after_if on modules to control loop termination",
"properties": {
"modules": {
"type": "array",
+ "description": "Steps to execute in each iteration. Use stop_after_if to control when the loop ends",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
},
"skip_failures": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, iteration failures don't stop the loop. Failed iterations return null"
},
"type": {
"type": "string",
@@ -29179,10 +38039,15 @@
]
},
"parallel": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, iterations run concurrently (use with caution in while loops)"
},
"parallelism": {
- "type": "integer"
+ "description": "Maximum number of concurrent iterations when parallel=true",
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ },
+ "squash": {
+ "type": "boolean"
}
},
"required": [
@@ -29193,20 +38058,25 @@
},
"schemas-BranchOne": {
"type": "object",
+ "description": "Conditional branching where only the first matching branch executes. Branches are evaluated in order, and the first one with a true expression runs. If no branches match, the default branch executes",
"properties": {
"branches": {
"type": "array",
+ "description": "Array of branches to evaluate in order. The first branch with expr evaluating to true executes",
"items": {
"type": "object",
"properties": {
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short description of this branch condition"
},
"expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression that returns boolean. Can use 'results.step_id' or 'flow_input'. First true expr wins"
},
"modules": {
"type": "array",
+ "description": "Steps to execute if this branch's expr is true",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
@@ -29220,12 +38090,10 @@
},
"default": {
"type": "array",
+ "description": "Steps to execute if no branch expressions match",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
- },
- "required": [
- "modules"
- ]
+ }
},
"type": {
"type": "string",
@@ -29242,20 +38110,25 @@
},
"schemas-BranchAll": {
"type": "object",
+ "description": "Parallel branching where all branches execute simultaneously. Unlike BranchOne, all branches run regardless of conditions. Useful for executing independent tasks concurrently",
"properties": {
"branches": {
"type": "array",
+ "description": "Array of branches that all execute (either in parallel or sequentially)",
"items": {
"type": "object",
"properties": {
"summary": {
- "type": "string"
+ "type": "string",
+ "description": "Short description of this branch's purpose"
},
"skip_failure": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, failure in this branch doesn't fail the entire flow"
},
"modules": {
"type": "array",
+ "description": "Steps to execute in this branch",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
@@ -29273,7 +38146,8 @@
]
},
"parallel": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, all branches execute concurrently. If false, they execute sequentially"
}
},
"required": [
@@ -29283,6 +38157,7 @@
},
"schemas-Identity": {
"type": "object",
+ "description": "Pass-through module that returns its input unchanged. Useful for flow structure or as a placeholder",
"properties": {
"type": {
"type": "string",
@@ -29291,14 +38166,240 @@
]
},
"flow": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, marks this as a flow identity (special handling)"
}
},
"required": [
"type"
]
},
+ "AIProviderKind": {
+ "type": "string",
+ "description": "Supported AI provider types",
+ "enum": [
+ "openai",
+ "azure_openai",
+ "anthropic",
+ "mistral",
+ "deepseek",
+ "googleai",
+ "groq",
+ "openrouter",
+ "togetherai",
+ "customai",
+ "aws_bedrock"
+ ]
+ },
+ "schemas-ProviderConfig": {
+ "type": "object",
+ "description": "Complete AI provider configuration with resource reference and model selection",
+ "properties": {
+ "kind": {
+ "$ref": "#/components/schemas/AIProviderKind"
+ },
+ "resource": {
+ "type": "string",
+ "description": "Resource reference in format '$res:{resource_path}' pointing to provider credentials"
+ },
+ "model": {
+ "type": "string",
+ "description": "Model identifier (e.g., 'gpt-4', 'claude-3-opus-20240229', 'gemini-pro')"
+ }
+ },
+ "required": [
+ "kind",
+ "resource",
+ "model"
+ ]
+ },
+ "StaticProviderTransform": {
+ "type": "object",
+ "description": "Static provider configuration passed directly to the AI agent",
+ "properties": {
+ "value": {
+ "$ref": "#/components/schemas/schemas-ProviderConfig"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "static"
+ ]
+ }
+ },
+ "required": [
+ "type",
+ "value"
+ ]
+ },
+ "ProviderTransform": {
+ "description": "Provider configuration - can be static (ProviderConfig), JavaScript expression, or AI-determined",
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/StaticProviderTransform"
+ },
+ {
+ "$ref": "#/components/schemas/schemas-JavascriptTransform"
+ },
+ {
+ "$ref": "#/components/schemas/schemas-AiTransform"
+ }
+ ],
+ "discriminator": {
+ "propertyName": "type",
+ "mapping": {
+ "static": "#/components/schemas/StaticProviderTransform",
+ "javascript": "#/components/schemas/schemas-JavascriptTransform",
+ "ai": "#/components/schemas/schemas-AiTransform"
+ }
+ }
+ },
+ "MemoryOff": {
+ "type": "object",
+ "description": "No conversation memory/context",
+ "properties": {
+ "kind": {
+ "type": "string",
+ "enum": [
+ "off"
+ ]
+ }
+ },
+ "required": [
+ "kind"
+ ]
+ },
+ "MemoryAuto": {
+ "type": "object",
+ "description": "Automatic context management",
+ "properties": {
+ "kind": {
+ "type": "string",
+ "enum": [
+ "auto"
+ ]
+ },
+ "context_length": {
+ "type": "integer",
+ "description": "Maximum number of messages to retain in context"
+ },
+ "memory_id": {
+ "type": "string",
+ "description": "Identifier for persistent memory across agent invocations"
+ }
+ },
+ "required": [
+ "kind"
+ ]
+ },
+ "MemoryMessage": {
+ "type": "object",
+ "description": "A single message in conversation history",
+ "properties": {
+ "role": {
+ "type": "string",
+ "enum": [
+ "user",
+ "assistant",
+ "system"
+ ]
+ },
+ "content": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "role",
+ "content"
+ ]
+ },
+ "MemoryManual": {
+ "type": "object",
+ "description": "Explicit message history",
+ "properties": {
+ "kind": {
+ "type": "string",
+ "enum": [
+ "manual"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/MemoryMessage"
+ }
+ }
+ },
+ "required": [
+ "kind",
+ "messages"
+ ]
+ },
+ "schemas-MemoryConfig": {
+ "description": "Conversation memory configuration",
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/MemoryOff"
+ },
+ {
+ "$ref": "#/components/schemas/MemoryAuto"
+ },
+ {
+ "$ref": "#/components/schemas/MemoryManual"
+ }
+ ],
+ "discriminator": {
+ "propertyName": "kind",
+ "mapping": {
+ "off": "#/components/schemas/MemoryOff",
+ "auto": "#/components/schemas/MemoryAuto",
+ "manual": "#/components/schemas/MemoryManual"
+ }
+ }
+ },
+ "StaticMemoryTransform": {
+ "type": "object",
+ "description": "Static memory configuration passed directly to the AI agent",
+ "properties": {
+ "value": {
+ "$ref": "#/components/schemas/schemas-MemoryConfig"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "static"
+ ]
+ }
+ },
+ "required": [
+ "type",
+ "value"
+ ]
+ },
+ "MemoryTransform": {
+ "description": "Memory configuration - can be static (MemoryConfig), JavaScript expression, or AI-determined",
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/StaticMemoryTransform"
+ },
+ {
+ "$ref": "#/components/schemas/schemas-JavascriptTransform"
+ },
+ {
+ "$ref": "#/components/schemas/schemas-AiTransform"
+ }
+ ],
+ "discriminator": {
+ "propertyName": "type",
+ "mapping": {
+ "static": "#/components/schemas/StaticMemoryTransform",
+ "javascript": "#/components/schemas/schemas-JavascriptTransform",
+ "ai": "#/components/schemas/schemas-AiTransform"
+ }
+ }
+ },
"schemas-FlowModuleValue": {
+ "description": "The actual implementation of a flow step. Can be a script (inline or referenced), subflow, loop, branch, or special module type",
"oneOf": [
{
"$ref": "#/components/schemas/schemas-RawScript"
@@ -29323,6 +38424,9 @@
},
{
"$ref": "#/components/schemas/schemas-Identity"
+ },
+ {
+ "$ref": "#/components/schemas/schemas-AiAgent"
}
],
"discriminator": {
@@ -29335,21 +38439,262 @@
"whileloopflow": "#/components/schemas/schemas-WhileloopFlow",
"branchone": "#/components/schemas/schemas-BranchOne",
"branchall": "#/components/schemas/schemas-BranchAll",
- "identity": "#/components/schemas/schemas-Identity"
+ "identity": "#/components/schemas/schemas-Identity",
+ "aiagent": "#/components/schemas/schemas-AiAgent"
}
}
},
+ "FlowModuleTool": {
+ "description": "A tool implemented as a flow module (script, flow, etc.). The AI can call this like any other flow module",
+ "allOf": [
+ {
+ "type": "object",
+ "properties": {
+ "tool_type": {
+ "type": "string",
+ "enum": [
+ "flowmodule"
+ ]
+ }
+ },
+ "required": [
+ "tool_type"
+ ]
+ },
+ {
+ "$ref": "#/components/schemas/schemas-FlowModuleValue"
+ }
+ ]
+ },
+ "McpToolValue": {
+ "type": "object",
+ "description": "Reference to an external MCP (Model Context Protocol) tool. The AI can call tools from MCP servers",
+ "properties": {
+ "tool_type": {
+ "type": "string",
+ "enum": [
+ "mcp"
+ ]
+ },
+ "resource_path": {
+ "type": "string",
+ "description": "Path to the MCP resource/server configuration"
+ },
+ "include_tools": {
+ "type": "array",
+ "description": "Whitelist of specific tools to include from this MCP server",
+ "items": {
+ "type": "string"
+ }
+ },
+ "exclude_tools": {
+ "type": "array",
+ "description": "Blacklist of tools to exclude from this MCP server",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "tool_type",
+ "resource_path"
+ ]
+ },
+ "WebsearchToolValue": {
+ "type": "object",
+ "description": "A tool implemented as a websearch tool. The AI can call this like any other websearch tool",
+ "properties": {
+ "tool_type": {
+ "type": "string",
+ "enum": [
+ "websearch"
+ ]
+ }
+ },
+ "required": [
+ "tool_type"
+ ]
+ },
+ "ToolValue": {
+ "description": "The implementation of a tool. Can be a flow module (script/flow) or an MCP tool reference",
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/FlowModuleTool"
+ },
+ {
+ "$ref": "#/components/schemas/McpToolValue"
+ },
+ {
+ "$ref": "#/components/schemas/WebsearchToolValue"
+ }
+ ],
+ "discriminator": {
+ "propertyName": "tool_type",
+ "mapping": {
+ "flowmodule": "#/components/schemas/FlowModuleTool",
+ "mcp": "#/components/schemas/McpToolValue",
+ "websearch": "#/components/schemas/WebsearchToolValue"
+ }
+ }
+ },
+ "AgentTool": {
+ "type": "object",
+ "description": "A tool available to an AI agent. Can be a flow module or an external MCP (Model Context Protocol) tool",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique identifier for this tool. Cannot contain spaces - use underscores instead (e.g., 'get_user_data' not 'get user data')"
+ },
+ "summary": {
+ "type": "string",
+ "description": "Short description of what this tool does (shown to the AI)"
+ },
+ "value": {
+ "$ref": "#/components/schemas/ToolValue"
+ }
+ },
+ "required": [
+ "id",
+ "value"
+ ]
+ },
+ "schemas-AiAgent": {
+ "type": "object",
+ "description": "AI agent step that can use tools to accomplish tasks. The agent receives inputs and can call any of its configured tools to complete the task",
+ "properties": {
+ "input_transforms": {
+ "type": "object",
+ "description": "Input parameters for the AI agent mapped to their values",
+ "properties": {
+ "provider": {
+ "$ref": "#/components/schemas/ProviderTransform"
+ },
+ "output_type": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Output format type.\nValid values: 'text' (default) - plain text response, 'image' - image generation\n"
+ },
+ "user_message": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "The user's prompt/message to the AI agent. Supports variable interpolation with flow.input syntax."
+ },
+ "system_prompt": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "System instructions that guide the AI's behavior, persona, and response style. Optional."
+ },
+ "streaming": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Boolean. If true, stream the AI response incrementally.\nStreaming events include: token_delta, tool_call, tool_call_arguments, tool_execution, tool_result\n"
+ },
+ "memory": {
+ "$ref": "#/components/schemas/MemoryTransform"
+ },
+ "output_schema": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "JSON Schema object defining structured output format. Used when you need the AI to return data in a specific shape.\nSupports standard JSON Schema properties: type, properties, required, items, enum, pattern, minLength, maxLength, minimum, maximum, etc.\nExample: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'integer' } }, required: ['name'] }\n"
+ },
+ "user_images": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Array of image references for vision-capable models.\nFormat: Array<{ bucket: string, key: string }> - S3 object references\nExample: [{ bucket: 'my-bucket', key: 'images/photo.jpg' }]\n"
+ },
+ "max_completion_tokens": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Integer. Maximum number of tokens the AI will generate in its response.\nRange: 1 to 4,294,967,295. Typical values: 256-4096 for most use cases.\n"
+ },
+ "temperature": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/schemas-InputTransform"
+ }
+ ],
+ "description": "Float. Controls randomness/creativity of responses.\nRange: 0.0 to 2.0 (provider-dependent)\n- 0.0 = deterministic, focused responses\n- 0.7 = balanced (common default)\n- 1.0+ = more creative/random\n"
+ }
+ },
+ "required": [
+ "provider",
+ "user_message",
+ "output_type"
+ ]
+ },
+ "tools": {
+ "type": "array",
+ "description": "Array of tools the agent can use. The agent decides which tools to call based on the task",
+ "items": {
+ "$ref": "#/components/schemas/AgentTool"
+ }
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "aiagent"
+ ]
+ },
+ "parallel": {
+ "type": "boolean",
+ "description": "If true, the agent can execute multiple tool calls in parallel"
+ }
+ },
+ "required": [
+ "tools",
+ "type",
+ "input_transforms"
+ ]
+ },
"schemas-StopAfterIf": {
"type": "object",
+ "description": "Early termination condition for a module",
"properties": {
"skip_if_stopped": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, following steps are skipped when this condition triggers"
},
"expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression evaluated after the module runs. Can use 'result' (step's result) or 'flow_input'. Return true to stop"
},
"error_message": {
- "type": "string"
+ "type": "string",
+ "description": "Custom error message shown when stopping"
+ }
+ },
+ "required": [
+ "expr"
+ ]
+ },
+ "RetryIf": {
+ "type": "object",
+ "description": "Conditional retry based on error or result",
+ "properties": {
+ "expr": {
+ "type": "string",
+ "description": "JavaScript expression that returns true to retry. Has access to 'result' and 'error' variables"
}
},
"required": [
@@ -29358,77 +38703,226 @@
},
"schemas-Retry": {
"type": "object",
+ "description": "Retry configuration for failed module executions",
"properties": {
"constant": {
"type": "object",
+ "description": "Retry with constant delay between attempts",
"properties": {
"attempts": {
- "type": "integer"
+ "type": "integer",
+ "description": "Number of retry attempts"
},
"seconds": {
- "type": "integer"
+ "type": "integer",
+ "description": "Seconds to wait between retries"
}
}
},
"exponential": {
"type": "object",
+ "description": "Retry with exponential backoff (delay doubles each time)",
"properties": {
"attempts": {
- "type": "integer"
+ "type": "integer",
+ "description": "Number of retry attempts"
},
"multiplier": {
- "type": "integer"
+ "type": "integer",
+ "description": "Multiplier for exponential backoff"
},
"seconds": {
- "type": "integer"
+ "type": "integer",
+ "minimum": 1,
+ "description": "Initial delay in seconds"
},
"random_factor": {
"type": "integer",
"minimum": 0,
- "maximum": 100
+ "maximum": 100,
+ "description": "Random jitter percentage (0-100) to avoid thundering herd"
}
}
+ },
+ "retry_if": {
+ "$ref": "#/components/schemas/RetryIf"
}
}
},
+ "schemas-FlowNote": {
+ "type": "object",
+ "description": "A sticky note attached to a flow for documentation and annotation",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique identifier for the note"
+ },
+ "text": {
+ "type": "string",
+ "description": "Content of the note"
+ },
+ "position": {
+ "type": "object",
+ "description": "Position of the note in the flow editor",
+ "properties": {
+ "x": {
+ "type": "number",
+ "description": "X coordinate"
+ },
+ "y": {
+ "type": "number",
+ "description": "Y coordinate"
+ }
+ },
+ "required": [
+ "x",
+ "y"
+ ]
+ },
+ "size": {
+ "type": "object",
+ "description": "Size of the note in the flow editor",
+ "properties": {
+ "width": {
+ "type": "number",
+ "description": "Width in pixels"
+ },
+ "height": {
+ "type": "number",
+ "description": "Height in pixels"
+ }
+ },
+ "required": [
+ "width",
+ "height"
+ ]
+ },
+ "color": {
+ "type": "string",
+ "description": "Color of the note (e.g., \"yellow\", \"#ffff00\")"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "free",
+ "group"
+ ],
+ "description": "Type of note - 'free' for standalone notes, 'group' for notes that group other nodes"
+ },
+ "locked": {
+ "type": "boolean",
+ "default": false,
+ "description": "Whether the note is locked and cannot be edited or moved"
+ },
+ "contained_node_ids": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "For group notes, the IDs of nodes contained within this group"
+ }
+ },
+ "required": [
+ "id",
+ "text",
+ "color",
+ "type"
+ ]
+ },
"schemas-FlowValue": {
"type": "object",
+ "description": "The flow structure containing modules and optional preprocessor/failure handlers",
"properties": {
"modules": {
"type": "array",
+ "description": "Array of steps that execute in sequence. Each step can be a script, subflow, loop, or branch",
"items": {
"$ref": "#/components/schemas/schemas-FlowModule"
}
},
"failure_module": {
+ "description": "Special module that executes when the flow fails. Receives error object with message, name, stack, and step_id. Must have id 'failure'. Only supports script/rawscript types",
"$ref": "#/components/schemas/schemas-FlowModule"
},
"preprocessor_module": {
+ "description": "Special module that runs before the first step on external triggers. Must have id 'preprocessor'. Only supports script/rawscript types. Cannot reference other step results",
"$ref": "#/components/schemas/schemas-FlowModule"
},
"same_worker": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "If true, all steps run on the same worker for better performance"
},
"concurrent_limit": {
- "type": "number"
+ "type": "number",
+ "description": "Maximum number of concurrent executions of this flow"
},
"concurrency_key": {
- "type": "string"
+ "type": "string",
+ "description": "Expression to group concurrent executions (e.g., by user ID)"
},
"concurrency_time_window_s": {
- "type": "number"
+ "type": "number",
+ "description": "Time window in seconds for concurrent_limit"
+ },
+ "debounce_delay_s": {
+ "type": "number",
+ "description": "Delay in seconds to debounce flow executions"
+ },
+ "debounce_key": {
+ "type": "string",
+ "description": "Expression to group debounced executions"
+ },
+ "debounce_args_to_accumulate": {
+ "type": "array",
+ "description": "Arguments to accumulate across debounced executions",
+ "items": {
+ "type": "string"
+ }
+ },
+ "max_total_debouncing_time": {
+ "type": "number",
+ "description": "Maximum total time in seconds that a job can be debounced"
+ },
+ "max_total_debounces_amount": {
+ "type": "number",
+ "description": "Maximum number of times a job can be debounced"
},
"skip_expr": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression to conditionally skip the entire flow"
},
"cache_ttl": {
- "type": "number"
+ "type": "number",
+ "description": "Cache duration in seconds for flow results"
+ },
+ "cache_ignore_s3_path": {
+ "type": "boolean"
+ },
+ "flow_env": {
+ "type": "object",
+ "description": "Environment variables available to all steps",
+ "additionalProperties": {
+ "type": "string"
+ }
},
"priority": {
- "type": "number"
+ "type": "number",
+ "description": "Execution priority (higher numbers run first)"
},
"early_return": {
- "type": "string"
+ "type": "string",
+ "description": "JavaScript expression to return early from the flow"
+ },
+ "chat_input_enabled": {
+ "type": "boolean",
+ "description": "Whether this flow accepts chat-style input"
+ },
+ "notes": {
+ "type": "array",
+ "description": "Sticky notes attached to the flow",
+ "items": {
+ "$ref": "#/components/schemas/schemas-FlowNote"
+ }
}
},
"required": [
@@ -29472,6 +38966,9 @@
"type": "array",
"items": {}
},
+ "itered_len": {
+ "type": "integer"
+ },
"args": {}
}
},
@@ -29487,6 +38984,23 @@
"type": "boolean"
}
},
+ "flow_jobs_duration": {
+ "type": "object",
+ "properties": {
+ "started_at": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "duration_ms": {
+ "type": "array",
+ "items": {
+ "type": "integer"
+ }
+ }
+ }
+ },
"branch_chosen": {
"type": "object",
"properties": {
@@ -29547,6 +39061,106 @@
},
"skipped": {
"type": "boolean"
+ },
+ "agent_actions": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "job_id": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "function_name": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "tool_call"
+ ]
+ },
+ "module_id": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "job_id",
+ "function_name",
+ "type",
+ "module_id"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "call_id": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "function_name": {
+ "type": "string"
+ },
+ "resource_path": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "mcp_tool_call"
+ ]
+ },
+ "arguments": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "call_id",
+ "function_name",
+ "resource_path",
+ "type"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "web_search"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "message"
+ ]
+ }
+ },
+ "required": [
+ "content",
+ "type"
+ ]
+ }
+ ]
+ }
+ },
+ "agent_actions_success": {
+ "type": "array",
+ "items": {
+ "type": "boolean"
+ }
}
},
"required": [
diff --git a/backend/windmill-api/openapi-deref.yaml b/backend/windmill-api/openapi-deref.yaml
index 70cc786faf..a500f2e8ee 100644
--- a/backend/windmill-api/openapi-deref.yaml
+++ b/backend/windmill-api/openapi-deref.yaml
@@ -1,6 +1,6 @@
openapi: 3.0.3
info:
- version: 1.520.1
+ version: 1.633.1
title: Windmill API
contact:
name: Windmill Team
@@ -33,6 +33,222 @@ paths:
text/plain:
schema:
type: string
+ /health/status:
+ get:
+ summary: health status
+ description: >
+ Health status endpoint. Returns cached health status (database
+ connectivity, worker count).
+
+ Cache TTL is fixed at 5 seconds. Use force=true query parameter to
+ bypass cache.
+
+ Note: This endpoint is intentionally different from Kubernetes probes to
+ avoid confusion.
+
+ For k8s liveness/readiness probes, use /version endpoint.
+ operationId: getHealthStatus
+ tags:
+ - health
+ security: []
+ parameters:
+ - name: force
+ in: query
+ description: Force a fresh check, bypassing the cache
+ required: false
+ schema:
+ type: boolean
+ default: false
+ responses:
+ '200':
+ description: server is healthy or degraded
+ content:
+ application/json:
+ schema:
+ type: object
+ description: Health status response (cached with 5s TTL)
+ required: &ref_0
+ - status
+ - checked_at
+ - database_healthy
+ - workers_alive
+ properties: &ref_1
+ status:
+ type: string
+ enum:
+ - healthy
+ - degraded
+ - unhealthy
+ description: Overall health status
+ checked_at:
+ type: string
+ format: date-time
+ description: >-
+ Timestamp when the health check was actually performed
+ (not cache return time)
+ database_healthy:
+ type: boolean
+ description: Whether the database is reachable
+ workers_alive:
+ type: integer
+ format: int64
+ description: Number of workers that pinged within last 5 minutes
+ '503':
+ description: server is unhealthy (database unreachable)
+ content:
+ application/json:
+ schema:
+ type: object
+ description: Health status response (cached with 5s TTL)
+ required: *ref_0
+ properties: *ref_1
+ /health/detailed:
+ get:
+ summary: detailed health status
+ description: >
+ Returns detailed health information including database pool stats,
+ worker details, and queue status.
+
+ Requires authentication. Use for monitoring dashboards and debugging.
+
+ This endpoint always returns fresh data (no caching).
+ operationId: getHealthDetailed
+ tags:
+ - health
+ responses:
+ '200':
+ description: server is healthy or degraded
+ content:
+ application/json:
+ schema:
+ type: object
+ description: Detailed health status response (always fresh, no caching)
+ required: &ref_2
+ - status
+ - checked_at
+ - version
+ - checks
+ properties: &ref_3
+ status:
+ type: string
+ enum:
+ - healthy
+ - degraded
+ - unhealthy
+ description: Overall health status
+ checked_at:
+ type: string
+ format: date-time
+ description: Timestamp when the health check was performed
+ version:
+ type: string
+ description: Server version (e.g., "EE 1.615.3")
+ checks:
+ type: object
+ description: Detailed health checks
+ required: &ref_308
+ - database
+ - readiness
+ properties: &ref_309
+ database:
+ type: object
+ description: Database health status
+ required: &ref_310
+ - healthy
+ - latency_ms
+ - pool
+ properties: &ref_311
+ healthy:
+ type: boolean
+ description: Whether the database is reachable
+ latency_ms:
+ type: integer
+ format: int64
+ description: Database query latency in milliseconds
+ pool:
+ type: object
+ description: Database connection pool statistics
+ required: &ref_312
+ - size
+ - idle
+ - max_connections
+ properties: &ref_313
+ size:
+ type: integer
+ description: Current number of connections in the pool
+ idle:
+ type: integer
+ description: Number of idle connections
+ max_connections:
+ type: integer
+ description: Maximum number of connections allowed
+ workers:
+ description: Workers health status
+ nullable: true
+ type: object
+ required: &ref_314
+ - healthy
+ - active_count
+ - worker_groups
+ - min_version
+ - versions
+ properties: &ref_315
+ healthy:
+ type: boolean
+ description: Whether any workers are active
+ active_count:
+ type: integer
+ format: int64
+ description: >-
+ Number of active workers (pinged in last 5
+ minutes)
+ worker_groups:
+ type: array
+ items:
+ type: string
+ description: List of active worker groups
+ min_version:
+ type: string
+ description: Minimum required worker version
+ versions:
+ type: array
+ items:
+ type: string
+ description: List of active worker versions
+ queue:
+ description: Job queue status
+ nullable: true
+ type: object
+ required: &ref_316
+ - pending_jobs
+ - running_jobs
+ properties: &ref_317
+ pending_jobs:
+ type: integer
+ format: int64
+ description: Number of pending jobs in the queue
+ running_jobs:
+ type: integer
+ format: int64
+ description: Number of currently running jobs
+ readiness:
+ type: object
+ description: Server readiness status
+ required: &ref_318
+ - healthy
+ properties: &ref_319
+ healthy:
+ type: boolean
+ description: Whether the server is ready to accept requests
+ '503':
+ description: server is unhealthy (database unreachable)
+ content:
+ application/json:
+ schema:
+ type: object
+ description: Detailed health status response (always fresh, no caching)
+ required: *ref_2
+ properties: *ref_3
/uptodate:
get:
summary: is backend up to date
@@ -59,6 +275,40 @@ paths:
text/plain:
schema:
type: string
+ /inkeep:
+ post:
+ summary: query Windmill AI documentation assistant (EE only)
+ operationId: queryDocumentation
+ x-mcp-tool: true
+ tags:
+ - documentation
+ requestBody:
+ description: query to send to the AI documentation assistant
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ query:
+ type: string
+ description: The documentation query to send to the AI assistant
+ required:
+ - query
+ responses:
+ '200':
+ description: AI documentation assistant response
+ content:
+ application/json:
+ schema:
+ type: object
+ description: Response from Inkeep service
+ '403':
+ description: Enterprise Edition required
+ content:
+ text/plain:
+ schema:
+ type: string
/openapi.yaml:
get:
summary: get openapi yaml spec
@@ -82,12 +332,12 @@ paths:
- name: workspace
in: path
required: true
- schema: &ref_0
+ schema: &ref_4
type: string
- name: id
in: path
required: true
- schema: &ref_41
+ schema: &ref_61
type: integer
responses:
'200':
@@ -96,7 +346,9 @@ paths:
application/json:
schema:
type: object
- properties: &ref_1
+ properties: &ref_5
+ workspace_id:
+ type: string
id:
type: integer
timestamp:
@@ -205,7 +457,8 @@ paths:
type: object
span:
type: string
- required: &ref_2
+ required: &ref_6
+ - workspace_id
- id
- timestamp
- username
@@ -221,38 +474,38 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: &ref_5
+ schema: &ref_13
type: integer
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: &ref_6
+ schema: &ref_14
type: integer
- name: before
description: filter on started before (inclusive) timestamp
in: query
- schema: &ref_200
+ schema: &ref_260
type: string
format: date-time
- name: after
description: filter on created after (exclusive) timestamp
in: query
- schema: &ref_201
+ schema: &ref_261
type: string
format: date-time
- name: username
description: filter on exact username of user
in: query
- schema: &ref_209
+ schema: &ref_269
type: string
- name: operation
description: filter on exact or prefix name of operation
in: query
- schema: &ref_210
+ schema: &ref_270
type: string
- name: operations
in: query
@@ -267,12 +520,12 @@ paths:
- name: resource
description: filter on exact or prefix name of resource
in: query
- schema: &ref_211
+ schema: &ref_271
type: string
- name: action_kind
description: filter on type of operation
in: query
- schema: &ref_212
+ schema: &ref_272
type: string
enum:
- Create
@@ -293,8 +546,8 @@ paths:
type: array
items:
type: object
- properties: *ref_1
- required: *ref_2
+ properties: *ref_5
+ required: *ref_6
/auth/login:
post:
security: []
@@ -309,12 +562,12 @@ paths:
application/json:
schema:
type: object
- properties: &ref_251
+ properties: &ref_357
email:
type: string
password:
type: string
- required: &ref_252
+ required: &ref_358
- email
- password
responses:
@@ -351,6 +604,87 @@ paths:
text/plain:
schema:
type: string
+ /auth/is_smtp_configured:
+ get:
+ security: []
+ summary: check if SMTP is configured for password reset
+ operationId: isSmtpConfigured
+ tags:
+ - user
+ responses:
+ '200':
+ description: returns true if SMTP is configured
+ content:
+ application/json:
+ schema:
+ type: boolean
+ /auth/request_password_reset:
+ post:
+ security: []
+ summary: request password reset email
+ operationId: requestPasswordReset
+ tags:
+ - user
+ requestBody:
+ description: email to send password reset link to
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - email
+ properties:
+ email:
+ type: string
+ format: email
+ responses:
+ '200':
+ description: password reset email sent (if user exists)
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: &ref_7
+ message:
+ type: string
+ required: &ref_8
+ - message
+ '400':
+ description: SMTP not configured
+ /auth/reset_password:
+ post:
+ security: []
+ summary: reset password using token
+ operationId: resetPassword
+ tags:
+ - user
+ requestBody:
+ description: token and new password
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - token
+ - new_password
+ properties:
+ token:
+ type: string
+ new_password:
+ type: string
+ responses:
+ '200':
+ description: password reset successfully
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_7
+ required: *ref_8
+ '400':
+ description: invalid or expired token
/w/{workspace}/users/get/{username}:
get:
summary: get user (require admin privilege)
@@ -362,7 +696,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: username
in: path
required: true
@@ -375,7 +709,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_10
+ properties: &ref_26
email:
type: string
username:
@@ -405,7 +739,31 @@ paths:
type: array
items:
type: string
- required: &ref_11
+ added_via:
+ nullable: true
+ allOf:
+ - type: object
+ properties: &ref_354
+ source:
+ type: string
+ enum:
+ - domain
+ - instance_group
+ - manual
+ description: How the user was added to the workspace
+ domain:
+ type: string
+ description: >-
+ The domain used for auto-invite (when source is
+ 'domain')
+ group:
+ type: string
+ description: >-
+ The instance group name (when source is
+ 'instance_group')
+ required: &ref_355
+ - source
+ required: &ref_27
- email
- username
- is_admin
@@ -426,7 +784,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: username
in: path
required: true
@@ -439,7 +797,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_253
+ properties: &ref_359
is_admin:
type: boolean
operator:
@@ -463,11 +821,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: &ref_31
+ schema: &ref_48
type: string
responses:
'200':
@@ -736,7 +1094,7 @@ paths:
type: array
items:
type: object
- properties: &ref_3
+ properties: &ref_9
email:
type: string
password_hash:
@@ -753,7 +1111,7 @@ paths:
type: boolean
username:
type: string
- required: &ref_4
+ required: &ref_10
- email
- super_admin
- verified
@@ -780,8 +1138,32 @@ paths:
type: array
items:
type: object
- properties: *ref_3
- required: *ref_4
+ properties: *ref_9
+ required: *ref_10
+ /users/onboarding:
+ post:
+ summary: Submit user onboarding data
+ operationId: submitOnboardingData
+ tags:
+ - user
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ touch_point:
+ type: string
+ use_case:
+ type: string
+ responses:
+ '200':
+ description: Onboarding data submitted successfully
+ content:
+ application/json:
+ schema:
+ type: string
/w/{workspace}/users/delete/{username}:
delete:
summary: delete user (require admin privilege)
@@ -793,7 +1175,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: username
in: path
required: true
@@ -806,12 +1188,44 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/users/convert_to_group/{username}:
+ post:
+ summary: convert manual user to group user (require admin privilege)
+ operationId: convertUserToGroup
+ tags:
+ - user
+ - admin
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: username
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: convert user to group user
+ content:
+ text/plain:
+ schema:
+ type: string
/github_app/connected_repositories:
get:
summary: get connected repositories
operationId: getGlobalConnectedRepositories
tags:
- Git Sync
+ parameters:
+ - name: page
+ in: query
+ description: Page number for pagination (default 1)
+ required: false
+ schema:
+ type: integer
+ default: 1
responses:
'200':
description: connected repositories
@@ -819,7 +1233,7 @@ paths:
application/json:
schema:
type: array
- items: &ref_376
+ items: &ref_498
type: object
properties:
workspace_id:
@@ -840,10 +1254,23 @@ paths:
required:
- name
- url
+ total_count:
+ type: number
+ description: >-
+ Total number of repositories available for this
+ installation
+ per_page:
+ type: number
+ description: Number of repositories loaded per page
+ error:
+ type: string
+ description: Error message if token retrieval failed
required:
- installation_id
- account_id
- repositories
+ - total_count
+ - per_page
/workspaces/list:
get:
summary: list all workspaces visible to me
@@ -859,7 +1286,7 @@ paths:
type: array
items:
type: object
- properties: &ref_7
+ properties: &ref_11
id:
type: string
name:
@@ -870,10 +1297,14 @@ paths:
type: string
color:
type: string
- required: &ref_8
+ parent_workspace_id:
+ type: string
+ nullable: true
+ required: &ref_12
- id
- name
- owner
+ - created_at
/workspaces/allowed_domain_auto_invite:
get:
summary: is domain allowed for auto invi
@@ -900,7 +1331,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_325
+ properties: &ref_439
email:
type: string
workspaces:
@@ -919,7 +1350,7 @@ paths:
operator_settings:
nullable: true
type: object
- required: &ref_12
+ required: &ref_28
- runs
- schedules
- resources
@@ -930,7 +1361,7 @@ paths:
- groups
- folders
- workers
- properties: &ref_13
+ properties: &ref_29
runs:
type: boolean
description: Whether operators can view runs
@@ -961,14 +1392,43 @@ paths:
workers:
type: boolean
description: Whether operators can view workers page
+ parent_workspace_id:
+ type: string
+ nullable: true
+ created_by:
+ type: string
+ nullable: true
+ disabled:
+ type: boolean
required:
- id
- name
- username
- color
- required: &ref_326
+ - disabled
+ required: &ref_440
- email
- workspaces
+ /w/{workspace}/workspaces/get_as_superadmin:
+ get:
+ summary: get workspace as super admin (require to be super admin)
+ operationId: getWorkspaceAsSuperAdmin
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: workspace
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_11
+ required: *ref_12
/workspaces/list_as_superadmin:
get:
summary: list all workspaces as super admin (require to be super admin)
@@ -979,11 +1439,11 @@ paths:
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
responses:
'200':
description: workspaces
@@ -993,8 +1453,8 @@ paths:
type: array
items:
type: object
- properties: *ref_7
- required: *ref_8
+ properties: *ref_11
+ required: *ref_12
/workspaces/create:
post:
summary: create workspace
@@ -1008,7 +1468,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_327
+ properties: &ref_441
id:
type: string
name:
@@ -1017,7 +1477,7 @@ paths:
type: string
color:
type: string
- required: &ref_328
+ required: &ref_442
- id
- name
responses:
@@ -1027,6 +1487,72 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/workspaces/create_workspace_fork_branch:
+ post:
+ summary: create forked workspace branch with git sync
+ operationId: createWorkspaceForkGitBranch
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: new forked workspace
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: &ref_15
+ id:
+ type: string
+ name:
+ type: string
+ color:
+ type: string
+ required: &ref_16
+ - id
+ - name
+ - parent_workspace_id
+ responses:
+ '201':
+ description: forked workspace branch created
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
+ format: uuid
+ /w/{workspace}/workspaces/create_fork:
+ post:
+ summary: create forked workspace
+ operationId: createWorkspaceFork
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: new forked workspace
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_15
+ required: *ref_16
+ responses:
+ '201':
+ description: forked workspace created
+ content:
+ text/plain:
+ schema:
+ type: string
/workspaces/exists:
post:
summary: exists workspace
@@ -1079,10 +1605,82 @@ paths:
text/plain:
schema:
type: boolean
- /settings/databases_exist:
+ /settings/refresh_custom_instance_user_pwd:
post:
- summary: checks that all given databases exist or else return the ones that don't
- operationId: databasesExist
+ summary: Refreshes the password for the custom_instance_user
+ operationId: refreshCustomInstanceUserPwd
+ tags:
+ - setting
+ responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ type: object
+ /settings/list_custom_instance_pg_databases:
+ post:
+ summary: Returns the set-up statuses of custom instance pg databases
+ operationId: listCustomInstanceDbs
+ tags:
+ - setting
+ responses:
+ '200':
+ description: Statuses of all custom instance dbs
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: object
+ required: &ref_19
+ - logs
+ - success
+ properties: &ref_20
+ logs:
+ type: object
+ properties: &ref_407
+ super_admin:
+ type: string
+ enum: &ref_17
+ - OK
+ - SKIP
+ - FAIL
+ database_credentials:
+ type: string
+ enum: *ref_17
+ valid_dbname:
+ type: string
+ enum: *ref_17
+ created_database:
+ type: string
+ enum: *ref_17
+ db_connect:
+ type: string
+ enum: *ref_17
+ grant_permissions:
+ type: string
+ enum: *ref_17
+ success:
+ type: boolean
+ description: Whether the operation completed successfully
+ example: true
+ error:
+ type: string
+ nullable: true
+ description: Error message if the operation failed
+ example: Connection timeout
+ tag:
+ type: string
+ enum: &ref_18
+ - ducklake
+ - datatable
+ /settings/setup_custom_instance_pg_database/{name}:
+ post:
+ summary: >-
+ Runs CREATE DATABASE on the Windmill Postgres and grants access to the
+ custom_instance_user
+ operationId: setupCustomInstanceDb
tags:
- setting
requestBody:
@@ -1090,26 +1688,11 @@ paths:
content:
application/json:
schema:
- type: array
- items:
- type: string
- responses:
- '200':
- description: databases that do not exist
- content:
- application/json:
- schema:
- type: array
- items:
+ type: object
+ properties:
+ tag:
type: string
- /settings/create_ducklake_database/{name}:
- post:
- summary: >-
- Runs CREATE DATABASE on the Windmill Postgres and grants access to the
- ducklake_user
- operationId: createDucklakeDatabase
- tags:
- - setting
+ enum: *ref_18
parameters:
- in: path
name: name
@@ -1122,7 +1705,10 @@ paths:
description: status
content:
application/json:
- schema: {}
+ schema:
+ type: object
+ required: *ref_19
+ properties: *ref_20
/settings/global/{key}:
get:
summary: get global settings
@@ -1133,7 +1719,7 @@ paths:
- name: key
in: path
required: true
- schema: &ref_9
+ schema: &ref_21
type: string
responses:
'200':
@@ -1150,7 +1736,7 @@ paths:
- name: key
in: path
required: true
- schema: *ref_9
+ schema: *ref_21
requestBody:
description: value set
required: true
@@ -1297,7 +1883,7 @@ paths:
type: array
items:
type: object
- properties: &ref_34
+ properties: &ref_51
id:
type: integer
description: Unique identifier for the alert
@@ -1425,6 +2011,19 @@ paths:
text/plain:
schema:
type: string
+ /settings/get_stats:
+ get:
+ summary: get encrypted telemetry stats (EE only)
+ operationId: getStats
+ tags:
+ - setting
+ responses:
+ '200':
+ description: base64-encoded encrypted telemetry blob
+ content:
+ text/plain:
+ schema:
+ type: string
/settings/latest_key_renewal_attempt:
get:
summary: get latest key renewal attempt
@@ -1521,14 +2120,186 @@ paths:
type: array
items:
type: object
- properties: &ref_363
+ properties: &ref_481
name:
type: string
- value:
- type: object
- required: &ref_364
+ value: {}
+ required: &ref_482
- name
- value
+ /min_keep_alive_version:
+ get:
+ summary: get minimum worker versions required to stay alive
+ operationId: getMinKeepAliveVersion
+ tags:
+ - setting
+ responses:
+ '200':
+ description: minimum keep-alive versions for workers and agents
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - worker
+ - agent
+ properties:
+ worker:
+ type: string
+ description: minimum version for normal workers
+ agent:
+ type: string
+ description: minimum version for agent workers
+ /.well-known/jwks.json:
+ get:
+ summary: get JWKS for Vault JWT authentication
+ operationId: getJwks
+ tags:
+ - setting
+ responses:
+ '200':
+ description: JSON Web Key Set
+ content:
+ application/json:
+ schema:
+ type: object
+ required: &ref_331
+ - keys
+ properties: &ref_332
+ keys:
+ type: array
+ items:
+ type: object
+ additionalProperties: true
+ description: Array of JSON Web Keys for JWT verification
+ /settings/test_secret_backend:
+ post:
+ summary: test secret backend connection (HashiCorp Vault)
+ operationId: testSecretBackend
+ tags:
+ - setting
+ requestBody:
+ description: Vault settings to test
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required: &ref_22
+ - address
+ - mount_path
+ properties: &ref_23
+ address:
+ type: string
+ description: >-
+ HashiCorp Vault server address (e.g.,
+ https://vault.company.com:8200)
+ mount_path:
+ type: string
+ description: KV v2 secrets engine mount path (e.g., windmill)
+ jwt_role:
+ type: string
+ description: >-
+ Vault JWT auth role name for Windmill (optional, if not
+ provided token auth is used)
+ namespace:
+ type: string
+ description: Vault Enterprise namespace (optional)
+ token:
+ type: string
+ description: >-
+ Static Vault token for testing/development (optional, if
+ provided this is used instead of JWT authentication)
+ responses:
+ '200':
+ description: connection successful
+ content:
+ text/plain:
+ schema:
+ type: string
+ /settings/migrate_secrets_to_vault:
+ post:
+ summary: migrate secrets from database to HashiCorp Vault
+ operationId: migrateSecretsToVault
+ tags:
+ - setting
+ requestBody:
+ description: Vault settings for migration target
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required: *ref_22
+ properties: *ref_23
+ responses:
+ '200':
+ description: migration report
+ content:
+ application/json:
+ schema:
+ type: object
+ required: &ref_24
+ - total_secrets
+ - migrated_count
+ - failed_count
+ - failures
+ properties: &ref_25
+ total_secrets:
+ type: integer
+ format: int64
+ description: Total number of secrets found
+ migrated_count:
+ type: integer
+ format: int64
+ description: Number of secrets successfully migrated
+ failed_count:
+ type: integer
+ format: int64
+ description: Number of secrets that failed to migrate
+ failures:
+ type: array
+ items:
+ type: object
+ required: &ref_329
+ - workspace_id
+ - path
+ - error
+ properties: &ref_330
+ workspace_id:
+ type: string
+ description: Workspace ID where the secret is located
+ path:
+ type: string
+ description: Path of the secret that failed to migrate
+ error:
+ type: string
+ description: Error message
+ description: Details of any failures encountered during migration
+ /settings/migrate_secrets_to_database:
+ post:
+ summary: migrate secrets from HashiCorp Vault to database
+ operationId: migrateSecretsToDatabase
+ tags:
+ - setting
+ requestBody:
+ description: Vault settings for migration source
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required: *ref_22
+ properties: *ref_23
+ responses:
+ '200':
+ description: migration report
+ content:
+ application/json:
+ schema:
+ type: object
+ required: *ref_24
+ properties: *ref_25
/users/email:
get:
summary: get current user email (if logged in)
@@ -1577,6 +2348,8 @@ paths:
properties:
progress:
type: integer
+ skipped_all:
+ type: boolean
post:
summary: update tutorial progress
operationId: updateTutorialProgress
@@ -1592,6 +2365,8 @@ paths:
properties:
progress:
type: integer
+ skipped_all:
+ type: boolean
responses:
'200':
description: tutorial progress
@@ -1645,8 +2420,6 @@ paths:
type: string
endpoint_sync:
type: string
- endpoint_openai_sync:
- type: string
summary:
type: string
description:
@@ -1657,7 +2430,6 @@ paths:
- workspace
- endpoint_async
- endpoint_sync
- - endpoint_openai_sync
- summary
- kind
/users/whoami:
@@ -1673,7 +2445,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_14
+ properties: &ref_30
email:
type: string
login_type:
@@ -1695,11 +2467,14 @@ paths:
type: string
operator_only:
type: boolean
- required: &ref_15
+ first_time_user:
+ type: boolean
+ required: &ref_31
- email
- login_type
- super_admin
- verified
+ - first_time_user
/users/list_invites:
get:
summary: list all workspace invites
@@ -1715,7 +2490,7 @@ paths:
type: array
items:
type: object
- properties: &ref_16
+ properties: &ref_32
workspace_id:
type: string
email:
@@ -1724,7 +2499,10 @@ paths:
type: boolean
operator:
type: boolean
- required: &ref_17
+ parent_workspace_id:
+ type: string
+ nullable: true
+ required: &ref_33
- workspace_id
- email
- is_admin
@@ -1739,7 +2517,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: user
@@ -1747,8 +2525,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_10
- required: *ref_11
+ properties: *ref_26
+ required: *ref_27
/w/{workspace}/github_app/token:
post:
summary: get github app token
@@ -1759,7 +2537,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: jwt job token
required: true
@@ -1794,7 +2572,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
required: true
content:
@@ -1827,7 +2605,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: installation_id
in: path
required: true
@@ -1959,7 +2737,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: WorkspaceInvite
required: true
@@ -1974,6 +2752,9 @@ paths:
type: boolean
operator:
type: boolean
+ parent_workspace_id:
+ type: string
+ nullable: true
required:
- email
- is_admin
@@ -1995,7 +2776,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: WorkspaceInvite
required: true
@@ -2033,7 +2814,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: WorkspaceInvite
required: true
@@ -2069,7 +2850,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -2087,7 +2868,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -2105,7 +2886,12 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
+ - name: only_delete_forks
+ in: query
+ required: false
+ schema:
+ type: boolean
responses:
'200':
description: status
@@ -2123,7 +2909,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -2141,7 +2927,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -2159,7 +2945,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
content:
application/json:
@@ -2187,7 +2973,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
content:
application/json:
@@ -2217,7 +3003,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
content:
application/json:
@@ -2243,7 +3029,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: username
in: path
required: true
@@ -2256,8 +3042,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_10
- required: *ref_11
+ properties: *ref_26
+ required: *ref_27
/w/{workspace}/workspaces/operator_settings:
post:
operationId: updateOperatorSettings
@@ -2271,7 +3057,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
required: true
content:
@@ -2279,8 +3065,8 @@ paths:
schema:
nullable: true
type: object
- required: *ref_12
- properties: *ref_13
+ required: *ref_28
+ properties: *ref_29
responses:
'200':
description: Operator settings updated successfully
@@ -2288,6 +3074,173 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/workspaces/compare/{target_workspace_id}:
+ get:
+ operationId: compareWorkspaces
+ summary: Compare two workspaces
+ description: >-
+ Compares the current workspace with a target workspace to find
+ differences in scripts, flows, apps, resources, and variables. Returns
+ information about items that are ahead, behind, or in conflict.
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: target_workspace_id
+ in: path
+ required: true
+ schema:
+ type: string
+ description: The ID of the workspace to compare with
+ responses:
+ '200':
+ description: Workspace comparison results
+ content:
+ application/json:
+ schema:
+ type: object
+ required: &ref_490
+ - all_ahead_items_visible
+ - all_behind_items_visible
+ - skipped_comparison
+ - diffs
+ - summary
+ properties: &ref_491
+ all_ahead_items_visible:
+ type: boolean
+ description: >-
+ All items with changes ahead are visible by the user of
+ the request.
+ all_behind_items_visible:
+ type: boolean
+ description: >-
+ All items with changes behind are visible by the user of
+ the request.
+ skipped_comparison:
+ type: boolean
+ description: >-
+ Whether the comparison was skipped. This happens with old
+ forks that where not being kept track of
+ diffs:
+ type: array
+ description: List of differences found between workspaces
+ items:
+ type: object
+ required: &ref_492
+ - kind
+ - path
+ - ahead
+ - behind
+ - has_changes
+ - exists_in_source
+ - exists_in_fork
+ properties: &ref_493
+ kind:
+ type: string
+ enum:
+ - script
+ - flow
+ - app
+ - resource
+ - variable
+ - resource_type
+ description: Type of the item
+ path:
+ type: string
+ description: Path of the item in the workspace
+ ahead:
+ type: integer
+ description: Number of versions source is ahead of target
+ behind:
+ type: integer
+ description: Number of versions source is behind target
+ has_changes:
+ type: boolean
+ description: Whether the item has any differences
+ exists_in_source:
+ type: boolean
+ description: If the item exists in the source workspace
+ exists_in_fork:
+ type: boolean
+ description: If the item exists in the fork workspace
+ summary:
+ description: Summary statistics of the comparison
+ type: object
+ required: &ref_494
+ - total_diffs
+ - total_ahead
+ - total_behind
+ - scripts_changed
+ - flows_changed
+ - apps_changed
+ - resources_changed
+ - variables_changed
+ - resource_types_changed
+ - folders_changed
+ - conflicts
+ properties: &ref_495
+ total_diffs:
+ type: integer
+ description: Total number of items with differences
+ total_ahead:
+ type: integer
+ description: Total number of ahead changes
+ total_behind:
+ type: integer
+ description: Total number of behind changes
+ scripts_changed:
+ type: integer
+ description: Number of scripts with differences
+ flows_changed:
+ type: integer
+ description: Number of flows with differences
+ apps_changed:
+ type: integer
+ description: Number of apps with differences
+ resources_changed:
+ type: integer
+ description: Number of resources with differences
+ variables_changed:
+ type: integer
+ description: Number of variables with differences
+ resource_types_changed:
+ type: integer
+ description: Number of resource types with differences
+ folders_changed:
+ type: integer
+ description: Number of folders with differences
+ conflicts:
+ type: integer
+ description: >-
+ Number of items that are both ahead and behind
+ (conflicts)
+ /w/{workspace}/workspaces/reset_diff_tally/{fork_workspace_id}:
+ post:
+ operationId: resetDiffTally
+ summary: Resets the ahead and behind deployement counter after a deployement
+ description: This endpoint should be called after a fork deployement
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: fork_workspace_id
+ in: path
+ required: true
+ schema:
+ type: string
+ description: The ID of the workspace to compare with
+ responses:
+ '200':
+ description: status
+ content:
+ application/json:
+ schema: {}
/users/exists/{email}:
get:
summary: exists email
@@ -2317,11 +3270,11 @@ paths:
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: active_only
in: query
description: filter only active users
@@ -2336,8 +3289,8 @@ paths:
type: array
items:
type: object
- properties: *ref_14
- required: *ref_15
+ properties: *ref_30
+ required: *ref_31
/w/{workspace}/workspaces/list_pending_invites:
get:
summary: list pending invites for a workspace
@@ -2348,7 +3301,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: user
@@ -2358,8 +3311,8 @@ paths:
type: array
items:
type: object
- properties: *ref_16
- required: *ref_17
+ properties: *ref_32
+ required: *ref_33
/w/{workspace}/workspaces/get_settings:
get:
summary: get settings
@@ -2370,7 +3323,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -2387,18 +3340,47 @@ paths:
type: string
slack_command_script:
type: string
+ slack_oauth_client_id:
+ type: string
+ slack_oauth_client_secret:
+ type: string
teams_team_id:
type: string
teams_command_script:
type: string
teams_team_name:
type: string
- auto_invite_domain:
+ teams_team_guid:
type: string
- auto_invite_operator:
- type: boolean
- auto_add:
- type: boolean
+ auto_invite:
+ type: object
+ description: Configuration for auto-inviting users to the workspace
+ properties: &ref_320
+ enabled:
+ type: boolean
+ default: false
+ domain:
+ type: string
+ operator:
+ type: boolean
+ default: false
+ description: >-
+ If true, auto-invited users are added as operators. If
+ false, they are added as developers.
+ mode:
+ type: string
+ enum:
+ - invite
+ - add
+ default: invite
+ instance_groups:
+ type: array
+ items:
+ type: string
+ instance_groups_roles:
+ type: object
+ additionalProperties:
+ type: string
plan:
type: string
customer_id:
@@ -2409,29 +3391,29 @@ paths:
type: string
ai_config:
type: object
- properties: &ref_21
+ properties: &ref_37
providers:
type: object
additionalProperties:
type: object
- properties: &ref_238
+ properties: &ref_340
resource_path:
type: string
models:
type: array
items:
type: string
- required: &ref_239
+ required: &ref_341
- resource_path
- models
default_model:
type: object
- properties: &ref_18
+ properties: &ref_34
model:
type: string
provider:
type: string
- enum: &ref_237
+ enum: &ref_339
- openai
- azure_openai
- anthropic
@@ -2441,25 +3423,56 @@ paths:
- groq
- openrouter
- togetherai
+ - aws_bedrock
- customai
- required: &ref_19
+ required: &ref_35
- model
- provider
code_completion_model:
type: object
- properties: *ref_18
- required: *ref_19
+ properties: *ref_34
+ required: *ref_35
+ custom_prompts:
+ type: object
+ additionalProperties:
+ type: string
+ max_tokens_per_model:
+ type: object
+ additionalProperties:
+ type: integer
+ minimum: 1
+ maximum: 2000000
error_handler:
- type: string
- error_handler_extra_args:
type: object
- description: The arguments to pass to the script or flow
- additionalProperties: &ref_22 {}
- error_handler_muted_on_cancel:
- type: boolean
+ description: Configuration for the workspace error handler
+ properties: &ref_321
+ path:
+ type: string
+ description: Path to the error handler script or flow
+ extra_args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ muted_on_cancel:
+ type: boolean
+ default: false
+ muted_on_user_path:
+ type: boolean
+ default: false
+ success_handler:
+ type: object
+ description: Configuration for the workspace success handler
+ properties: &ref_322
+ path:
+ type: string
+ description: Path to the success handler script or flow
+ extra_args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
large_file_storage:
type: object
- properties: &ref_23
+ properties: &ref_38
type:
type: string
enum:
@@ -2476,6 +3489,18 @@ paths:
type: string
public_resource:
type: boolean
+ advanced_permissions:
+ type: array
+ items:
+ type: object
+ properties: &ref_465
+ pattern:
+ type: string
+ allow:
+ type: string
+ required: &ref_466
+ - pattern
+ - allow
secondary_storage:
type: object
additionalProperties:
@@ -2499,9 +3524,9 @@ paths:
type: boolean
ducklake:
type: object
- required: &ref_24
+ required: &ref_39
- ducklakes
- properties: &ref_25
+ properties: &ref_40
ducklakes:
type: object
additionalProperties:
@@ -2532,14 +3557,40 @@ paths:
type: string
required:
- path
+ extra_args:
+ type: string
+ datatable:
+ type: object
+ required: &ref_41
+ - datatables
+ properties: &ref_42
+ datatables:
+ type: object
+ additionalProperties:
+ type: object
+ required:
+ - database
+ properties:
+ database:
+ type: object
+ properties:
+ resource_type:
+ type: string
+ enum:
+ - postgresql
+ - instance
+ resource_path:
+ type: string
+ required:
+ - resource_type
git_sync:
type: object
- properties: &ref_26
+ properties: &ref_43
repositories:
type: array
items:
type: object
- properties: &ref_27
+ properties: &ref_44
script_path:
type: string
git_repo_resource_path:
@@ -2561,7 +3612,7 @@ paths:
type: array
items:
type: string
- enum: &ref_20
+ enum: &ref_36
- script
- flow
- app
@@ -2588,13 +3639,13 @@ paths:
type: array
items:
type: string
- enum: *ref_20
- required: &ref_28
+ enum: *ref_36
+ required: &ref_45
- script_path
- git_repo_resource_path
deploy_ui:
type: object
- properties: &ref_29
+ properties: &ref_46
include_path:
type: array
items:
@@ -2603,12 +3654,12 @@ paths:
type: array
items:
type: string
- enum: *ref_20
+ enum: *ref_36
default_app:
type: string
default_scripts:
type: object
- properties: &ref_30
+ properties: &ref_47
order:
type: array
items:
@@ -2627,10 +3678,13 @@ paths:
operator_settings:
nullable: true
type: object
- required: *ref_12
- properties: *ref_13
- required:
- - error_handler_muted_on_cancel
+ required: *ref_28
+ properties: *ref_29
+ public_app_execution_limit_per_minute:
+ type: integer
+ description: >-
+ Rate limit for public app executions per minute per
+ server. NULL or 0 means disabled.
/w/{workspace}/workspaces/get_deploy_to:
get:
summary: get deploy to
@@ -2641,7 +3695,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -2662,7 +3716,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -2680,7 +3734,12 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
+ - name: skip_subscription_fetch
+ in: query
+ description: skip fetching subscription status from stripe
+ schema:
+ type: boolean
responses:
'200':
description: status
@@ -2697,9 +3756,14 @@ paths:
type: string
status:
type: string
+ is_past_due:
+ type: boolean
+ max_tolerated_executions:
+ type: number
required:
- premium
- owner
+ - is_past_due
/w/{workspace}/workspaces/threshold_alert:
get:
summary: get threshold alert info
@@ -2710,7 +3774,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -2733,7 +3797,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: threshold alert info
required: true
@@ -2751,6 +3815,141 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/workspaces/rebuild_dependency_map:
+ post:
+ summary: rebuild dependency map
+ operationId: rebuildDependencyMap
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: status
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/workspaces/get_dependents/{imported_path}:
+ get:
+ summary: get dependents of an imported path
+ operationId: getDependents
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: imported_path
+ in: path
+ required: true
+ schema:
+ type: string
+ description: The imported path to get dependents for
+ responses:
+ '200':
+ description: list of dependents
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties: &ref_444
+ importer_path:
+ type: string
+ importer_kind:
+ type: string
+ enum:
+ - script
+ - flow
+ - app
+ importer_node_ids:
+ type: array
+ items:
+ type: string
+ nullable: true
+ required: &ref_445
+ - importer_path
+ - importer_kind
+ /w/{workspace}/workspaces/get_dependents_amounts:
+ post:
+ summary: get dependents amounts for multiple imported paths
+ operationId: getDependentsAmounts
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: List of imported paths to get dependents counts for
+ required: true
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ '200':
+ description: list of dependents amounts
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties: &ref_446
+ imported_path:
+ type: string
+ count:
+ type: integer
+ format: int64
+ required: &ref_447
+ - imported_path
+ - count
+ /w/{workspace}/workspaces/get_dependency_map:
+ get:
+ summary: get dependency map
+ operationId: getDependencyMap
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: dmap
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties: &ref_443
+ workspace_id:
+ type: string
+ nullable: true
+ importer_path:
+ type: string
+ nullable: true
+ importer_kind:
+ type: string
+ nullable: true
+ imported_path:
+ type: string
+ nullable: true
+ importer_node_id:
+ type: string
+ nullable: true
/w/{workspace}/workspaces/edit_slack_command:
post:
summary: edit slack command
@@ -2761,7 +3960,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: WorkspaceInvite
required: true
@@ -2779,6 +3978,81 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/workspaces/slack_oauth_config:
+ get:
+ summary: get workspace slack oauth config
+ operationId: getWorkspaceSlackOauthConfig
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: slack oauth config
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ slack_oauth_client_id:
+ type: string
+ nullable: true
+ slack_oauth_client_secret:
+ type: string
+ nullable: true
+ description: Masked with *** if set
+ post:
+ summary: set workspace slack oauth config
+ operationId: setWorkspaceSlackOauthConfig
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: Slack OAuth Configuration
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - slack_oauth_client_id
+ - slack_oauth_client_secret
+ properties:
+ slack_oauth_client_id:
+ type: string
+ slack_oauth_client_secret:
+ type: string
+ responses:
+ '200':
+ description: status
+ content:
+ text/plain:
+ schema:
+ type: string
+ delete:
+ summary: delete workspace slack oauth config
+ operationId: deleteWorkspaceSlackOauthConfig
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: status
+ content:
+ text/plain:
+ schema:
+ type: string
/w/{workspace}/workspaces/edit_teams_command:
post:
summary: edit teams command
@@ -2789,7 +4063,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: WorkspaceInvite
required: true
@@ -2817,24 +4091,53 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
+ - name: search
+ in: query
+ description: Search teams by name. If omitted, returns first page of all teams.
+ required: false
+ schema:
+ type: string
+ - name: next_link
+ in: query
+ description: >-
+ Pagination cursor URL from previous response. Pass this to fetch the
+ next page of results.
+ required: false
+ schema:
+ type: string
responses:
'200':
description: status
content:
application/json:
schema:
- type: array
- items:
- type: object
- properties:
- team_name:
- type: string
- team_id:
- type: string
+ type: object
+ properties:
+ teams:
+ type: array
+ items:
+ type: object
+ properties:
+ team_name:
+ type: string
+ team_id:
+ type: string
+ total_count:
+ type: integer
+ description: Total number of teams across all pages
+ per_page:
+ type: integer
+ description: >-
+ Number of teams per page (configurable via TEAMS_PER_PAGE
+ env var)
+ next_link:
+ type: string
+ nullable: true
+ description: URL to fetch next page of results. Null if no more pages.
/w/{workspace}/workspaces/available_teams_channels:
get:
- summary: list available teams channels
+ summary: list available channels for a specific team
operationId: listAvailableTeamsChannels
tags:
- workspace
@@ -2842,25 +4145,32 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
+ - name: team_id
+ in: query
+ description: Microsoft Teams team ID
+ required: true
+ schema:
+ type: string
responses:
'200':
- description: status
+ description: List of channels for the specified team
content:
application/json:
schema:
- type: array
- items:
- type: object
- properties:
- channel_name:
- type: string
- channel_id:
- type: string
- service_url:
- type: string
- tenant_id:
- type: string
+ type: object
+ properties:
+ channels:
+ type: array
+ items:
+ type: object
+ properties:
+ channel_name:
+ type: string
+ channel_id:
+ type: string
+ total_count:
+ type: integer
/w/{workspace}/workspaces/connect_teams:
post:
summary: connect teams
@@ -2871,7 +4181,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: connect teams
required: true
@@ -2901,7 +4211,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: path to hub script to run and its corresponding args
required: true
@@ -2936,7 +4246,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: path to hub script to run and its corresponding args
required: true
@@ -2971,7 +4281,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
required: true
content:
@@ -2998,7 +4308,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: WorkspaceInvite
required: true
@@ -3020,6 +4330,40 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/workspaces/edit_instance_groups:
+ post:
+ summary: edit instance groups
+ operationId: editInstanceGroups
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: Instance Groups Configuration
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ groups:
+ type: array
+ items:
+ type: string
+ roles:
+ type: object
+ additionalProperties:
+ type: string
+ responses:
+ '200':
+ description: status
+ content:
+ text/plain:
+ schema:
+ type: string
/w/{workspace}/workspaces/edit_webhook:
post:
summary: edit webhook
@@ -3030,7 +4374,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: WorkspaceWebhook
required: true
@@ -3058,7 +4402,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: WorkspaceCopilotConfig
required: true
@@ -3066,7 +4410,7 @@ paths:
application/json:
schema:
type: object
- properties: *ref_21
+ properties: *ref_37
responses:
'200':
description: status
@@ -3084,7 +4428,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -3092,7 +4436,7 @@ paths:
application/json:
schema:
type: object
- properties: *ref_21
+ properties: *ref_37
/w/{workspace}/workspaces/edit_error_handler:
post:
summary: edit error handler
@@ -3103,23 +4447,100 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: WorkspaceErrorHandler
required: true
content:
application/json:
schema:
- type: object
- properties:
- error_handler:
- type: string
- error_handler_extra_args:
- type: object
- description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- error_handler_muted_on_cancel:
- type: boolean
+ description: >-
+ Request body for editing the workspace error handler. Accepts
+ both new grouped format and legacy flat format for backward
+ compatibility.
+ oneOf: &ref_323
+ - type: object
+ description: New grouped format for editing error handler
+ properties: &ref_324
+ path:
+ type: string
+ description: Path to the error handler script or flow
+ extra_args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ muted_on_cancel:
+ type: boolean
+ default: false
+ muted_on_user_path:
+ type: boolean
+ default: false
+ - type: object
+ description: >-
+ Legacy flat format for editing error handler (deprecated,
+ use new format)
+ properties: &ref_325
+ error_handler:
+ type: string
+ description: Path to the error handler script or flow
+ error_handler_extra_args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ error_handler_muted_on_cancel:
+ type: boolean
+ default: false
+ responses:
+ '200':
+ description: status
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/workspaces/edit_success_handler:
+ post:
+ summary: edit success handler
+ operationId: editSuccessHandler
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: WorkspaceSuccessHandler
+ required: true
+ content:
+ application/json:
+ schema:
+ description: >-
+ Request body for editing the workspace success handler. Accepts
+ both new grouped format and legacy flat format for backward
+ compatibility.
+ oneOf: &ref_326
+ - type: object
+ description: New grouped format for editing success handler
+ properties: &ref_327
+ path:
+ type: string
+ description: Path to the success handler script or flow
+ extra_args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ - type: object
+ description: >-
+ Legacy flat format for editing success handler (deprecated,
+ use new format)
+ properties: &ref_328
+ success_handler:
+ type: string
+ description: Path to the success handler script or flow
+ success_handler_extra_args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
responses:
'200':
description: status
@@ -3137,7 +4558,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: LargeFileStorage info
required: true
@@ -3148,7 +4569,7 @@ paths:
properties:
large_file_storage:
type: object
- properties: *ref_23
+ properties: *ref_38
responses:
'200':
description: status
@@ -3165,7 +4586,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -3175,6 +4596,71 @@ paths:
type: array
items:
type: string
+ /w/{workspace}/workspaces/list_datatables:
+ get:
+ summary: list Datatables
+ operationId: listDataTables
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: status
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
+ /w/{workspace}/workspaces/list_datatable_schemas:
+ get:
+ summary: list schemas of all connected Datatables
+ operationId: listDataTableSchemas
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: schemas of all datatables
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ required: &ref_461
+ - datatable_name
+ - schemas
+ properties: &ref_462
+ datatable_name:
+ type: string
+ schemas:
+ type: object
+ description: >-
+ Hierarchical schema: schema_name -> table_name ->
+ column_name -> compact_type (e.g. 'int4', 'text?',
+ 'int4?=0')
+ additionalProperties:
+ type: object
+ description: Tables in this schema
+ additionalProperties:
+ type: object
+ description: Columns in this table
+ additionalProperties:
+ type: string
+ description: >-
+ Compact type: 'type[?][=default]' where ? means
+ nullable
+ error:
+ type: string
/w/{workspace}/workspaces/edit_ducklake_config:
post:
summary: edit ducklake settings
@@ -3185,7 +4671,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Ducklake settings
required: true
@@ -3198,8 +4684,39 @@ paths:
properties:
settings:
type: object
- required: *ref_24
- properties: *ref_25
+ required: *ref_39
+ properties: *ref_40
+ responses:
+ '200':
+ description: status
+ content:
+ application/json:
+ schema: {}
+ /w/{workspace}/workspaces/edit_datatable_config:
+ post:
+ summary: edit datatable settings
+ operationId: editDataTableConfig
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: DataTable settings
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - settings
+ properties:
+ settings:
+ type: object
+ required: *ref_41
+ properties: *ref_42
responses:
'200':
description: status
@@ -3216,7 +4733,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Workspace Git sync settings
required: true
@@ -3227,7 +4744,7 @@ paths:
properties:
git_sync_settings:
type: object
- properties: *ref_26
+ properties: *ref_43
responses:
'200':
description: status
@@ -3244,7 +4761,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Git sync repository settings to add or update
required: true
@@ -3258,8 +4775,8 @@ paths:
description: The resource path of the git repository to update
repository:
type: object
- properties: *ref_27
- required: *ref_28
+ properties: *ref_44
+ required: *ref_45
required:
- git_repo_resource_path
- repository
@@ -3279,7 +4796,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Git sync repository to delete
required: true
@@ -3309,7 +4826,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Workspace deploy UI settings
required: true
@@ -3320,7 +4837,7 @@ paths:
properties:
deploy_ui_settings:
type: object
- properties: *ref_29
+ properties: *ref_46
responses:
'200':
description: status
@@ -3337,7 +4854,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Workspace default app
required: true
@@ -3365,14 +4882,14 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Workspace default app
content:
application/json:
schema:
type: object
- properties: *ref_30
+ properties: *ref_47
responses:
'200':
description: status
@@ -3389,7 +4906,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -3397,7 +4914,7 @@ paths:
application/json:
schema:
type: object
- properties: *ref_30
+ properties: *ref_47
/w/{workspace}/workspaces/set_environment_variable:
post:
summary: set environment variable
@@ -3408,7 +4925,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Workspace default app
required: true
@@ -3440,7 +4957,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -3462,7 +4979,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: New encryption key
required: true
@@ -3494,7 +5011,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -3505,25 +5022,6 @@ paths:
properties:
default_app_path:
type: string
- /w/{workspace}/workspaces/get_large_file_storage_config:
- get:
- summary: get large file storage config
- operationId: getLargeFileStorageConfig
- tags:
- - workspace
- parameters:
- - name: workspace
- in: path
- required: true
- schema: *ref_0
- responses:
- '200':
- description: status
- content:
- application/json:
- schema:
- type: object
- properties: *ref_23
/w/{workspace}/workspaces/usage:
get:
summary: get usage
@@ -3534,7 +5032,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: usage
@@ -3552,7 +5050,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: status
@@ -3577,6 +5075,10 @@ paths:
type: boolean
sqs_used:
type: boolean
+ email_used:
+ type: boolean
+ nextcloud_used:
+ type: boolean
required:
- http_routes_used
- websocket_used
@@ -3586,6 +5088,8 @@ paths:
- mqtt_used
- gcp_used
- sqs_used
+ - email_used
+ - nextcloud_used
/w/{workspace}/users/list:
get:
summary: list users
@@ -3596,7 +5100,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: user
@@ -3606,8 +5110,8 @@ paths:
type: array
items:
type: object
- properties: *ref_10
- required: *ref_11
+ properties: *ref_26
+ required: *ref_27
/w/{workspace}/users/list_usage:
get:
summary: list users usage
@@ -3618,7 +5122,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: user
@@ -3628,7 +5132,7 @@ paths:
type: array
items:
type: object
- properties: &ref_250
+ properties: &ref_356
email:
type: string
executions:
@@ -3643,7 +5147,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: user
@@ -3663,7 +5167,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: username
in: path
required: true
@@ -3691,7 +5195,7 @@ paths:
type: array
items:
type: object
- properties: &ref_339
+ properties: &ref_456
name:
type: string
description:
@@ -3701,7 +5205,7 @@ paths:
type: array
items:
type: object
- properties: &ref_337
+ properties: &ref_454
value:
type: string
label:
@@ -3711,11 +5215,11 @@ paths:
nullable: true
requires_resource_path:
type: boolean
- required: &ref_338
+ required: &ref_455
- value
- label
- requires_resource_path
- required: &ref_340
+ required: &ref_457
- name
- scopes
/users/tokens/create:
@@ -3731,7 +5235,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_254
+ properties: &ref_360
label:
type: string
expiration:
@@ -3763,7 +5267,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_255
+ properties: &ref_361
label:
type: string
expiration:
@@ -3773,7 +5277,7 @@ paths:
type: string
workspace_id:
type: string
- required: &ref_256
+ required: &ref_362
- impersonate_email
responses:
'201':
@@ -3815,11 +5319,11 @@ paths:
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
responses:
'200':
description: truncated token
@@ -3829,7 +5333,7 @@ paths:
type: array
items:
type: object
- properties: &ref_54
+ properties: &ref_82
label:
type: string
expiration:
@@ -3849,7 +5353,7 @@ paths:
type: string
email:
type: string
- required: &ref_55
+ required: &ref_83
- token_prefix
- created_at
- last_used_at
@@ -3863,12 +5367,16 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: audience
in: path
required: true
schema:
type: string
+ - name: expires_in
+ in: query
+ schema:
+ type: number
responses:
'200':
description: new oidc token
@@ -3887,7 +5395,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: already_encrypted
description: whether the variable is already encrypted (default false)
in: query
@@ -3900,7 +5408,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_259
+ properties: &ref_365
path:
type: string
description: The path to the variable
@@ -3923,7 +5431,7 @@ paths:
type: string
description: The expiration date of the variable
format: date-time
- required: &ref_260
+ required: &ref_366
- path
- value
- is_secret
@@ -3945,7 +5453,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new variable
required: true
@@ -3971,11 +5479,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: variable deleted
@@ -3983,6 +5491,40 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/variables/delete_bulk:
+ delete:
+ summary: delete variables in bulk
+ operationId: deleteVariablesBulk
+ tags:
+ - variable
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: paths to delete
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ paths:
+ type: array
+ items:
+ type: string
+ required:
+ - paths
+ responses:
+ '200':
+ description: deleted paths
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
/w/{workspace}/variables/update/{path}:
post:
summary: update variable
@@ -3994,11 +5536,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: already_encrypted
description: whether the variable is already encrypted (default false)
in: query
@@ -4011,7 +5553,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_261
+ properties: &ref_367
path:
type: string
description: The path to the variable
@@ -4042,11 +5584,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: decrypt_secret
description: |
ask to decrypt secret if this variable is secret
@@ -4068,7 +5610,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_32
+ properties: &ref_49
workspace_id:
type: string
path:
@@ -4098,7 +5640,7 @@ paths:
expires_at:
type: string
format: date-time
- required: &ref_33
+ required: &ref_50
- workspace_id
- path
- is_secret
@@ -4113,11 +5655,17 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
+ - name: allow_cache
+ description: |
+ allow getting a cached value for improved performance
+ in: query
+ schema:
+ type: boolean
responses:
'200':
description: variable
@@ -4135,11 +5683,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: variable
@@ -4158,7 +5706,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path_start
description: filter variables by path prefix
in: query
@@ -4167,11 +5715,11 @@ paths:
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
responses:
'200':
description: variable list
@@ -4181,8 +5729,8 @@ paths:
type: array
items:
type: object
- properties: *ref_32
- required: *ref_33
+ properties: *ref_49
+ required: *ref_50
/w/{workspace}/variables/list_contextual:
get:
summary: list contextual variables
@@ -4193,7 +5741,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: contextual variable list
@@ -4203,7 +5751,7 @@ paths:
type: array
items:
type: object
- properties: &ref_257
+ properties: &ref_363
name:
type: string
value:
@@ -4212,7 +5760,7 @@ paths:
type: string
is_custom:
type: boolean
- required: &ref_258
+ required: &ref_364
- name
- value
- description
@@ -4227,7 +5775,16 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
+ - name: include_default
+ in: query
+ description: >-
+ If true, include "_default_" in the list if primary workspace
+ storage is set
+ required: false
+ schema:
+ type: boolean
+ default: false
responses:
'200':
description: status
@@ -4247,7 +5804,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- in: query
name: page
schema:
@@ -4281,7 +5838,7 @@ paths:
type: array
items:
type: object
- properties: *ref_34
+ properties: *ref_51
total_rows:
type: integer
description: Total number of rows matching the query.
@@ -4300,7 +5857,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- in: path
name: id
required: true
@@ -4325,7 +5882,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: Successfully acknowledged all unacknowledged critical alerts.
@@ -4344,7 +5901,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Boolean flag to mute critical alerts.
required: true
@@ -4367,6 +5924,215 @@ paths:
example: >-
Updated mute critical alert UI settings for workspace:
workspace_id
+ /w/{workspace}/workspaces/protection_rules:
+ get:
+ summary: list all protection rules for a workspace
+ operationId: listProtectionRules
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: list of protection rules
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ description: >-
+ A workspace protection rule defining restrictions and bypass
+ permissions
+ required: &ref_499
+ - name
+ - rules
+ - bypass_groups
+ - bypass_users
+ properties: &ref_500
+ name:
+ type: string
+ description: Unique name for the protection rule
+ example: Production Protection
+ workspace_id:
+ type: string
+ rules:
+ type: array
+ description: Configuration of protection restrictions
+ items: &ref_52
+ type: string
+ enum: &ref_501
+ - DisableDirectDeployment
+ - DisableWorkspaceForking
+ bypass_groups:
+ type: array
+ description: Groups that can bypass this ruleset
+ items: &ref_53
+ type: string
+ bypass_users:
+ type: array
+ description: Users that can bypass this ruleset
+ items: &ref_54
+ type: string
+ post:
+ summary: create a new protection rule
+ operationId: createProtectionRule
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: New protection rule configuration
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - name
+ - rules
+ - bypass_groups
+ - bypass_users
+ properties:
+ name:
+ type: string
+ description: Unique name for the protection rule
+ example: Production Protection
+ rules:
+ type: array
+ description: Configuration of protection restrictions
+ items: *ref_52
+ bypass_groups:
+ type: array
+ description: Groups that can bypass this ruleset
+ items: *ref_53
+ bypass_users:
+ type: array
+ description: Users that can bypass this ruleset
+ items: *ref_54
+ responses:
+ '200':
+ description: protection rule created successfully
+ content:
+ text/plain:
+ schema:
+ type: string
+ '400':
+ description: rule with this name already exists
+ /w/{workspace}/workspaces/protection_rules/{rule_name}:
+ post:
+ summary: update an existing protection rule
+ operationId: updateProtectionRule
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: rule_name
+ in: path
+ required: true
+ schema:
+ type: string
+ description: Name of the protection rule to update
+ requestBody:
+ description: Updated protection rule configuration
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - rules
+ - bypass_groups
+ - bypass_users
+ properties:
+ rules:
+ type: array
+ description: Configuration of protection restrictions
+ items: *ref_52
+ bypass_groups:
+ type: array
+ description: Groups that can bypass this ruleset
+ items: *ref_53
+ bypass_users:
+ type: array
+ description: Users that can bypass this ruleset
+ items: *ref_54
+ responses:
+ '200':
+ description: protection rule updated successfully
+ content:
+ text/plain:
+ schema:
+ type: string
+ '404':
+ description: protection rule not found
+ delete:
+ summary: delete a protection rule
+ operationId: deleteProtectionRule
+ tags:
+ - workspace
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: rule_name
+ in: path
+ required: true
+ schema:
+ type: string
+ description: Name of the protection rule to delete
+ responses:
+ '200':
+ description: protection rule deleted successfully
+ content:
+ text/plain:
+ schema:
+ type: string
+ '404':
+ description: protection rule not found
+ /w/{workspace}/workspaces/public_app_rate_limit:
+ post:
+ summary: Set public app rate limit for this workspace
+ operationId: setPublicAppRateLimit
+ tags:
+ - setting
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: Public app rate limit configuration
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ public_app_execution_limit_per_minute:
+ type: integer
+ description: >-
+ Rate limit for public app executions per minute per server.
+ NULL or 0 to disable.
+ example: 100
+ responses:
+ '200':
+ description: Successfully updated public app rate limit settings.
+ content:
+ application/json:
+ schema:
+ type: string
+ example: 'Updated public app rate limit for workspace: workspace_id'
/oauth/login_callback/{client_name}:
post:
security: []
@@ -4378,7 +6144,7 @@ paths:
- name: client_name
in: path
required: true
- schema: &ref_35
+ schema: &ref_55
type: string
requestBody:
description: Partially filled script
@@ -4418,7 +6184,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: code endpoint
required: true
@@ -4479,7 +6245,7 @@ paths:
- name: client_name
in: path
required: true
- schema: *ref_35
+ schema: *ref_55
requestBody:
description: code endpoint
required: true
@@ -4502,7 +6268,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_36
+ properties: &ref_56
access_token:
type: string
expires_in:
@@ -4515,7 +6281,7 @@ paths:
type: string
grant_type:
type: string
- required: &ref_37
+ required: &ref_57
- access_token
/w/{workspace}/oauth/create_account:
post:
@@ -4527,7 +6293,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: code endpoint
required: true
@@ -4538,6 +6304,10 @@ paths:
properties:
refresh_token:
type: string
+ description: >-
+ OAuth refresh token. For authorization_code flow, this
+ contains the actual refresh token. For client_credentials
+ flow, this must be set to an empty string.
expires_in:
type: integer
client:
@@ -4560,7 +6330,11 @@ paths:
description: >-
OAuth token URL override for resource-level authentication
(client_credentials flow only)
+ mcp_server_url:
+ type: string
+ description: MCP server URL for MCP OAuth token refresh
required:
+ - refresh_token
- expires_in
- client
responses:
@@ -4614,8 +6388,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_36
- required: *ref_37
+ properties: *ref_56
+ required: *ref_57
/w/{workspace}/oauth/refresh_token/{id}:
post:
summary: refresh token
@@ -4626,11 +6400,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: &ref_38
+ schema: &ref_58
type: integer
requestBody:
description: variable path
@@ -4661,11 +6435,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_38
+ schema: *ref_58
responses:
'200':
description: disconnected client
@@ -4683,7 +6457,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: disconnected slack
@@ -4701,7 +6475,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: disconnected teams
@@ -4784,62 +6558,6 @@ paths:
type: array
items:
type: string
- /teams/sync:
- post:
- operationId: syncTeams
- summary: synchronize Microsoft Teams information (teams/channels)
- tags:
- - teams
- responses:
- '200':
- description: Teams information successfully synchronized
- content:
- application/json:
- schema:
- type: array
- items:
- type: object
- required: &ref_372
- - team_id
- - team_name
- - channels
- properties: &ref_373
- team_id:
- type: string
- description: The unique identifier of the Microsoft Teams team
- example: 19:abc123def456@thread.tacv2
- team_name:
- type: string
- description: The display name of the Microsoft Teams team
- example: Engineering Team
- channels:
- type: array
- description: List of channels within the team
- items:
- type: object
- required: &ref_374
- - channel_id
- - channel_name
- - tenant_id
- - service_url
- properties: &ref_375
- channel_id:
- type: string
- description: The unique identifier of the channel
- example: 19:channel123@thread.tacv2
- channel_name:
- type: string
- description: The display name of the channel
- example: General
- tenant_id:
- type: string
- description: The Microsoft Teams tenant identifier
- example: 12345678-1234-1234-1234-123456789012
- service_url:
- type: string
- description: The service URL for the channel
- example: >-
- https://smba.trafficmanager.net/amer/12345678-1234-1234-1234-123456789012/
/teams/activities:
post:
summary: send update to Microsoft Teams activity
@@ -4884,7 +6602,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: update_if_exists
description: update the resource if it already exists (default false)
in: query
@@ -4897,7 +6615,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_266
+ properties: &ref_372
path:
type: string
description: The path to the resource
@@ -4908,7 +6626,7 @@ paths:
resource_type:
type: string
description: The resource_type associated with the resource
- required: &ref_267
+ required: &ref_373
- path
- value
- resource_type
@@ -4930,11 +6648,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: resource deleted
@@ -4942,6 +6660,40 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/resources/delete_bulk:
+ delete:
+ summary: delete resources in bulk
+ operationId: deleteResourcesBulk
+ tags:
+ - resource
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: paths to delete
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ paths:
+ type: array
+ items:
+ type: string
+ required:
+ - paths
+ responses:
+ '200':
+ description: deleted paths
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
/w/{workspace}/resources/update/{path}:
post:
summary: update resource
@@ -4953,11 +6705,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated resource
required: true
@@ -4965,7 +6717,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_268
+ properties: &ref_374
path:
type: string
description: The path to the resource
@@ -4993,11 +6745,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated resource
required: true
@@ -5025,11 +6777,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: resource
@@ -5037,7 +6789,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_269
+ properties: &ref_375
workspace_id:
type: string
path:
@@ -5058,7 +6810,7 @@ paths:
edited_at:
type: string
format: date-time
- required: &ref_270
+ required: &ref_376
- path
- resource_type
- is_oauth
@@ -5072,17 +6824,22 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: job_id
description: job id
in: query
schema:
type: string
format: uuid
+ - name: allow_cache
+ description: allow getting a cached value for improved performance
+ in: query
+ schema:
+ type: boolean
responses:
'200':
description: resource value
@@ -5099,17 +6856,49 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: resource value
content:
application/json:
schema: {}
+ /w/{workspace}/resources/git_commit_hash/{path}:
+ get:
+ summary: get git repository latest commit hash
+ operationId: getGitCommitHash
+ tags:
+ - resource
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_48
+ - name: git_ssh_identity
+ in: query
+ schema:
+ type: string
+ responses:
+ '200':
+ description: git commit hash
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ commit_hash:
+ type: string
+ description: Latest commit hash from git ls-remote
+ required:
+ - commit_hash
/w/{workspace}/resources/exists/{path}:
get:
summary: does resource exists
@@ -5120,11 +6909,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: does resource exists
@@ -5143,15 +6932,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: resource_type
description: resource_types to list from, separated by ',',
in: query
@@ -5176,7 +6965,7 @@ paths:
type: array
items:
type: object
- properties: &ref_271
+ properties: &ref_377
workspace_id:
type: string
path:
@@ -5207,7 +6996,7 @@ paths:
edited_at:
type: string
format: date-time
- required: &ref_272
+ required: &ref_378
- path
- resource_type
- is_oauth
@@ -5223,7 +7012,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: resource list
@@ -5240,6 +7029,40 @@ paths:
required:
- path
- value
+ /w/{workspace}/resources/mcp_tools/{path}:
+ get:
+ summary: get MCP tools from resource
+ operationId: getMcpTools
+ tags:
+ - resource
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_48
+ responses:
+ '200':
+ description: list of MCP tools
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ description:
+ type: string
+ parameters:
+ type: object
+ required:
+ - name
+ - parameters
/w/{workspace}/resources/list_names/{name}:
get:
summary: list resource names
@@ -5250,11 +7073,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: &ref_180
+ schema: &ref_235
type: string
responses:
'200':
@@ -5283,7 +7106,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new resource_type
required: true
@@ -5291,7 +7114,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_39
+ properties: &ref_59
workspace_id:
type: string
name:
@@ -5306,7 +7129,7 @@ paths:
format: date-time
format_extension:
type: string
- required: &ref_40
+ required: &ref_60
- name
responses:
'201':
@@ -5325,7 +7148,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: map from resource type to file ext
@@ -5342,11 +7165,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: resource_type deleted
@@ -5364,11 +7187,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated resource_type
required: true
@@ -5376,7 +7199,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_273
+ properties: &ref_379
schema: {}
description:
type: string
@@ -5397,11 +7220,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: resource_type deleted
@@ -5409,8 +7232,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_39
- required: *ref_40
+ properties: *ref_59
+ required: *ref_60
/w/{workspace}/resources/type/exists/{path}:
get:
summary: does resource_type exists
@@ -5421,11 +7244,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: does resource_type exist
@@ -5444,7 +7267,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: resource_type list
@@ -5454,8 +7277,8 @@ paths:
type: array
items:
type: object
- properties: *ref_39
- required: *ref_40
+ properties: *ref_59
+ required: *ref_60
/w/{workspace}/resources/type/listnames:
get:
summary: list resource_types names
@@ -5466,7 +7289,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: resource_type list
@@ -5476,6 +7299,149 @@ paths:
type: array
items:
type: string
+ /w/{workspace}/npm_proxy/metadata/{package}:
+ get:
+ summary: get npm package metadata from private registry
+ operationId: getNpmPackageMetadata
+ tags:
+ - npm_proxy
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: package
+ description: npm package name
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: package metadata
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ tags:
+ type: object
+ additionalProperties:
+ type: string
+ versions:
+ type: array
+ items:
+ type: string
+ /w/{workspace}/npm_proxy/resolve/{package}:
+ get:
+ summary: resolve npm package version from private registry
+ operationId: resolveNpmPackageVersion
+ tags:
+ - npm_proxy
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: package
+ description: npm package name
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: tag
+ description: version tag or reference
+ in: query
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: resolved version
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ version:
+ type: string
+ nullable: true
+ /w/{workspace}/npm_proxy/filetree/{package}/{version}:
+ get:
+ summary: get npm package file tree from private registry
+ operationId: getNpmPackageFiletree
+ tags:
+ - npm_proxy
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: package
+ description: npm package name
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: version
+ description: package version
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: package file tree
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ default:
+ type: string
+ files:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ /w/{workspace}/npm_proxy/file/{package}/{version}/{filepath}:
+ get:
+ summary: get specific file from npm package in private registry
+ operationId: getNpmPackageFile
+ tags:
+ - npm_proxy
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: package
+ description: npm package name
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: version
+ description: package version
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: filepath
+ description: file path within package
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: file content
+ content:
+ text/plain:
+ schema:
+ type: string
/w/{workspace}/embeddings/query_resource_types:
get:
summary: query resource types by similarity
@@ -5486,7 +7452,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: text
description: query text
in: query
@@ -5594,7 +7560,7 @@ paths:
- name: id
in: path
required: true
- schema: *ref_41
+ schema: *ref_61
responses:
'200':
description: flow
@@ -5605,61 +7571,137 @@ paths:
properties:
flow:
type: object
- properties: &ref_68
+ description: >-
+ Top-level flow definition containing metadata,
+ configuration, and the flow structure
+ properties: &ref_98
summary:
type: string
+ description: Short description of what this flow does
description:
type: string
+ description: Detailed documentation for this flow
value:
type: object
- properties: &ref_377
+ description: >-
+ The flow structure containing modules and optional
+ preprocessor/failure handlers
+ properties: &ref_530
modules:
type: array
+ description: >-
+ Array of steps that execute in sequence. Each step
+ can be a script, subflow, loop, or branch
items:
type: object
- properties: &ref_44
+ description: >-
+ A single step in a flow. Can be a script,
+ subflow, loop, or branch
+ properties: &ref_64
id:
type: string
+ description: >-
+ Unique identifier for this step. Used to
+ reference results via 'results.step_id'.
+ Must be a valid identifier (alphanumeric,
+ underscore, hyphen)
value:
- oneOf: &ref_216
+ description: >-
+ The actual implementation of a flow step.
+ Can be a script (inline or referenced),
+ subflow, loop, branch, or special module
+ type
+ oneOf: &ref_70
- type: object
- properties: &ref_219
+ description: >-
+ Inline script with code defined directly
+ in the flow. Use 'bun' as default
+ language if unspecified. The script
+ receives arguments from input_transforms
+ properties: &ref_284
input_transforms:
type: object
+ description: >-
+ Map of parameter names to their values
+ (static or JavaScript expressions).
+ These become the script's input
+ arguments
additionalProperties:
- oneOf: &ref_42
+ description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: &ref_62
- type: object
- properties: &ref_84
- value: {}
+ description: >-
+ Static value passed directly to the
+ step. Use for hardcoded values or
+ resource references like
+ '$res:path/to/resource'
+ properties: &ref_114
+ value:
+ description: >-
+ The static value. For resources, use
+ format '$res:path/to/resource'
type:
type: string
enum:
- static
- required: &ref_85
- - value
+ required: &ref_115
- type
- type: object
- properties: &ref_86
+ description: >-
+ JavaScript expression evaluated at
+ runtime. Can reference previous step
+ results via 'results.step_id' or flow
+ inputs via 'flow_input.property'. Inside
+ loops, use 'flow_input.iter.value' for
+ the current iteration value
+ properties: &ref_66
expr:
type: string
+ description: >-
+ JavaScript expression returning the
+ value. Available variables - results
+ (object with all previous step results),
+ flow_input (flow inputs),
+ flow_input.iter (in loops)
type:
type: string
enum:
- javascript
- required: &ref_87
+ required: &ref_67
- expr
- type
- discriminator: &ref_43
+ - type: object
+ description: >-
+ Value resolved by the AI runtime for
+ this input. The AI engine decides how to
+ satisfy the parameter.
+ properties: &ref_68
+ type:
+ type: string
+ enum:
+ - ai
+ required: &ref_69
+ - type
+ discriminator: &ref_63
propertyName: type
mapping:
static: >-
#/components/schemas/schemas-StaticTransform
javascript: >-
#/components/schemas/schemas-JavascriptTransform
+ ai: '#/components/schemas/schemas-AiTransform'
content:
type: string
+ description: >-
+ The script source code. Should export a
+ 'main' function
language:
type: string
+ description: Programming language for this script
enum:
- deno
- bun
@@ -5676,26 +7718,49 @@ paths:
- graphql
- nativets
- php
+ - rust
+ - ansible
+ - csharp
+ - nu
+ - java
+ - ruby
+ - duckdb
path:
type: string
+ description: Optional path for saving this script
lock:
type: string
+ description: Lock file content for dependencies
type:
type: string
enum:
- rawscript
tag:
type: string
+ description: Worker group tag for execution routing
concurrent_limit:
type: number
+ description: >-
+ Maximum concurrent executions of this
+ script
concurrency_time_window_s:
type: number
+ description: Time window for concurrent_limit
custom_concurrency_key:
type: string
+ description: >-
+ Custom key for grouping concurrent
+ executions
is_trigger:
type: boolean
+ description: >-
+ If true, this script is a trigger that
+ can start the flow
assets:
type: array
+ description: >-
+ External resources this script accesses
+ (S3 objects, resources, etc.)
items:
type: object
required:
@@ -5704,172 +7769,331 @@ paths:
properties:
path:
type: string
+ description: Path to the asset
kind:
type: string
+ description: Type of asset
enum:
- s3object
- resource
- ducklake
+ - datatable
access_type:
type: string
+ nullable: true
+ description: Access level for this asset
enum:
- r
- w
- rw
alt_access_type:
type: string
+ nullable: true
+ description: Alternative access level
enum:
- r
- w
- rw
- required: &ref_220
+ required: &ref_285
- type
- content
- language
- input_transforms
- type: object
- properties: &ref_221
+ description: >-
+ Reference to an existing script by path.
+ Use this when calling a previously saved
+ script instead of writing inline code
+ properties: &ref_286
input_transforms:
type: object
+ description: >-
+ Map of parameter names to their values
+ (static or JavaScript expressions).
+ These become the script's input
+ arguments
additionalProperties:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
path:
type: string
+ description: >-
+ Path to the script in the workspace
+ (e.g., 'f/scripts/send_email')
hash:
type: string
+ description: >-
+ Optional specific version hash of the
+ script to use
type:
type: string
enum:
- script
tag_override:
type: string
+ description: >-
+ Override the script's default worker
+ group tag
is_trigger:
type: boolean
- required: &ref_222
+ description: >-
+ If true, this script is a trigger that
+ can start the flow
+ required: &ref_287
- type
- path
- input_transforms
- type: object
- properties: &ref_223
+ description: >-
+ Reference to an existing flow by path.
+ Use this to call another flow as a
+ subflow
+ properties: &ref_288
input_transforms:
type: object
+ description: >-
+ Map of parameter names to their values
+ (static or JavaScript expressions).
+ These become the subflow's input
+ arguments
additionalProperties:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
path:
type: string
+ description: >-
+ Path to the flow in the workspace (e.g.,
+ 'f/flows/process_user')
type:
type: string
enum:
- flow
- required: &ref_224
+ required: &ref_289
- type
- path
- input_transforms
- type: object
- properties: &ref_225
+ description: >-
+ Executes nested modules in a loop over
+ an iterator. Inside the loop, use
+ 'flow_input.iter.value' to access the
+ current iteration value, and
+ 'flow_input.iter.index' for the index.
+ Supports parallel execution for better
+ performance on I/O-bound operations
+ properties: &ref_290
modules:
type: array
+ description: >-
+ Steps to execute for each iteration.
+ These can reference the iteration value
+ via 'flow_input.iter.value'
items:
type: object
- properties: *ref_44
- required: &ref_45
+ description: >-
+ A single step in a flow. Can be a
+ script, subflow, loop, or branch
+ properties: *ref_64
+ required: &ref_65
- value
- id
iterator:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
skip_failures:
type: boolean
+ description: >-
+ If true, iteration failures don't stop
+ the loop. Failed iterations return null
type:
type: string
enum:
- forloopflow
parallel:
type: boolean
+ description: >-
+ If true, iterations run concurrently
+ (faster for I/O-bound operations). Use
+ with parallelism to control concurrency
parallelism:
- type: integer
- required: &ref_226
+ description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ squash:
+ type: boolean
+ required: &ref_291
- modules
- iterator
- skip_failures
- type
- type: object
- properties: &ref_227
+ description: >-
+ Executes nested modules repeatedly while
+ a condition is true. The loop checks the
+ condition after each iteration. Use
+ stop_after_if on modules to control loop
+ termination
+ properties: &ref_292
modules:
type: array
+ description: >-
+ Steps to execute in each iteration. Use
+ stop_after_if to control when the loop
+ ends
items:
type: object
- properties: *ref_44
- required: *ref_45
+ description: >-
+ A single step in a flow. Can be a
+ script, subflow, loop, or branch
+ properties: *ref_64
+ required: *ref_65
skip_failures:
type: boolean
+ description: >-
+ If true, iteration failures don't stop
+ the loop. Failed iterations return null
type:
type: string
enum:
- whileloopflow
parallel:
type: boolean
+ description: >-
+ If true, iterations run concurrently
+ (use with caution in while loops)
parallelism:
- type: integer
- required: &ref_228
+ description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ squash:
+ type: boolean
+ required: &ref_293
- modules
- skip_failures
- type
- type: object
- properties: &ref_229
+ description: >-
+ Conditional branching where only the
+ first matching branch executes. Branches
+ are evaluated in order, and the first
+ one with a true expression runs. If no
+ branches match, the default branch
+ executes
+ properties: &ref_294
branches:
type: array
+ description: >-
+ Array of branches to evaluate in order.
+ The first branch with expr evaluating to
+ true executes
items:
type: object
properties:
summary:
type: string
+ description: >-
+ Short description of this branch
+ condition
expr:
type: string
+ description: >-
+ JavaScript expression that returns
+ boolean. Can use 'results.step_id' or
+ 'flow_input'. First true expr wins
modules:
type: array
+ description: >-
+ Steps to execute if this branch's expr
+ is true
items:
type: object
- properties: *ref_44
- required: *ref_45
+ description: >-
+ A single step in a flow. Can be a
+ script, subflow, loop, or branch
+ properties: *ref_64
+ required: *ref_65
required:
- modules
- expr
default:
type: array
+ description: >-
+ Steps to execute if no branch
+ expressions match
items:
type: object
- properties: *ref_44
- required: *ref_45
- required:
- - modules
+ description: >-
+ A single step in a flow. Can be a
+ script, subflow, loop, or branch
+ properties: *ref_64
+ required: *ref_65
type:
type: string
enum:
- branchone
- required: &ref_230
+ required: &ref_295
- branches
- default
- type
- type: object
- properties: &ref_231
+ description: >-
+ Parallel branching where all branches
+ execute simultaneously. Unlike
+ BranchOne, all branches run regardless
+ of conditions. Useful for executing
+ independent tasks concurrently
+ properties: &ref_296
branches:
type: array
+ description: >-
+ Array of branches that all execute
+ (either in parallel or sequentially)
items:
type: object
properties:
summary:
type: string
+ description: >-
+ Short description of this branch's
+ purpose
skip_failure:
type: boolean
+ description: >-
+ If true, failure in this branch doesn't
+ fail the entire flow
modules:
type: array
+ description: Steps to execute in this branch
items:
type: object
- properties: *ref_44
- required: *ref_45
+ description: >-
+ A single step in a flow. Can be a
+ script, subflow, loop, or branch
+ properties: *ref_64
+ required: *ref_65
required:
- modules
type:
@@ -5878,150 +8102,862 @@ paths:
- branchall
parallel:
type: boolean
- required: &ref_232
+ description: >-
+ If true, all branches execute
+ concurrently. If false, they execute
+ sequentially
+ required: &ref_297
- branches
- type
- type: object
- properties: &ref_233
+ description: >-
+ Pass-through module that returns its
+ input unchanged. Useful for flow
+ structure or as a placeholder
+ properties: &ref_298
type:
type: string
enum:
- identity
flow:
type: boolean
- required: &ref_234
+ description: >-
+ If true, marks this as a flow identity
+ (special handling)
+ required: &ref_299
- type
- discriminator: &ref_217
- propertyName: type
- mapping:
- rawscript: '#/components/schemas/schemas-RawScript'
- script: '#/components/schemas/schemas-PathScript'
- flow: '#/components/schemas/schemas-PathFlow'
- forloopflow: '#/components/schemas/schemas-ForloopFlow'
- whileloopflow: >-
- #/components/schemas/schemas-WhileloopFlow
- branchone: '#/components/schemas/schemas-BranchOne'
- branchall: '#/components/schemas/schemas-BranchAll'
- identity: '#/components/schemas/schemas-Identity'
+ - type: object
+ description: >-
+ AI agent step that can use tools to
+ accomplish tasks. The agent receives
+ inputs and can call any of its
+ configured tools to complete the task
+ properties: &ref_300
+ input_transforms:
+ type: object
+ description: >-
+ Input parameters for the AI agent mapped
+ to their values
+ properties:
+ provider:
+ description: >-
+ Provider configuration - can be static
+ (ProviderConfig), JavaScript expression,
+ or AI-determined
+ oneOf: &ref_302
+ - type: object
+ description: >-
+ Static provider configuration passed
+ directly to the AI agent
+ properties: &ref_515
+ value:
+ type: object
+ description: >-
+ Complete AI provider configuration with
+ resource reference and model selection
+ properties: &ref_513
+ kind:
+ type: string
+ description: Supported AI provider types
+ enum: &ref_277
+ - openai
+ - azure_openai
+ - anthropic
+ - mistral
+ - deepseek
+ - googleai
+ - groq
+ - openrouter
+ - togetherai
+ - customai
+ - aws_bedrock
+ resource:
+ type: string
+ description: >-
+ Resource reference in format
+ '$res:{resource_path}' pointing to
+ provider credentials
+ model:
+ type: string
+ description: >-
+ Model identifier (e.g., 'gpt-4',
+ 'claude-3-opus-20240229', 'gemini-pro')
+ required: &ref_514
+ - kind
+ - resource
+ - model
+ type:
+ type: string
+ enum:
+ - static
+ required: &ref_516
+ - type
+ - value
+ - type: object
+ description: >-
+ JavaScript expression evaluated at
+ runtime. Can reference previous step
+ results via 'results.step_id' or flow
+ inputs via 'flow_input.property'. Inside
+ loops, use 'flow_input.iter.value' for
+ the current iteration value
+ properties: *ref_66
+ required: *ref_67
+ - type: object
+ description: >-
+ Value resolved by the AI runtime for
+ this input. The AI engine decides how to
+ satisfy the parameter.
+ properties: *ref_68
+ required: *ref_69
+ discriminator: &ref_303
+ propertyName: type
+ mapping:
+ static: >-
+ #/components/schemas/StaticProviderTransform
+ javascript: >-
+ #/components/schemas/schemas-JavascriptTransform
+ ai: '#/components/schemas/schemas-AiTransform'
+ output_type:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ Output format type.
+
+ Valid values: 'text' (default) - plain
+ text response, 'image' - image
+ generation
+ user_message:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >-
+ The user's prompt/message to the AI
+ agent. Supports variable interpolation
+ with flow.input syntax.
+ system_prompt:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >-
+ System instructions that guide the AI's
+ behavior, persona, and response style.
+ Optional.
+ streaming:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ Boolean. If true, stream the AI response
+ incrementally.
+
+ Streaming events include: token_delta,
+ tool_call, tool_call_arguments,
+ tool_execution, tool_result
+ memory:
+ description: >-
+ Memory configuration - can be static
+ (MemoryConfig), JavaScript expression,
+ or AI-determined
+ oneOf: &ref_304
+ - type: object
+ description: >-
+ Static memory configuration passed
+ directly to the AI agent
+ properties: &ref_521
+ value:
+ description: Conversation memory configuration
+ oneOf: &ref_519
+ - type: object
+ description: No conversation memory/context
+ properties: &ref_278
+ kind:
+ type: string
+ enum:
+ - 'off'
+ required: &ref_279
+ - kind
+ - type: object
+ description: Automatic context management
+ properties: &ref_280
+ kind:
+ type: string
+ enum:
+ - auto
+ context_length:
+ type: integer
+ description: >-
+ Maximum number of messages to retain in
+ context
+ memory_id:
+ type: string
+ description: >-
+ Identifier for persistent memory across
+ agent invocations
+ required: &ref_281
+ - kind
+ - type: object
+ description: Explicit message history
+ properties: &ref_282
+ kind:
+ type: string
+ enum:
+ - manual
+ messages:
+ type: array
+ items:
+ type: object
+ description: A single message in conversation history
+ properties: &ref_517
+ role:
+ type: string
+ enum:
+ - user
+ - assistant
+ - system
+ content:
+ type: string
+ required: &ref_518
+ - role
+ - content
+ required: &ref_283
+ - kind
+ - messages
+ discriminator: &ref_520
+ propertyName: kind
+ mapping:
+ 'off': '#/components/schemas/MemoryOff'
+ auto: '#/components/schemas/MemoryAuto'
+ manual: '#/components/schemas/MemoryManual'
+ type:
+ type: string
+ enum:
+ - static
+ required: &ref_522
+ - type
+ - value
+ - type: object
+ description: >-
+ JavaScript expression evaluated at
+ runtime. Can reference previous step
+ results via 'results.step_id' or flow
+ inputs via 'flow_input.property'. Inside
+ loops, use 'flow_input.iter.value' for
+ the current iteration value
+ properties: *ref_66
+ required: *ref_67
+ - type: object
+ description: >-
+ Value resolved by the AI runtime for
+ this input. The AI engine decides how to
+ satisfy the parameter.
+ properties: *ref_68
+ required: *ref_69
+ discriminator: &ref_305
+ propertyName: type
+ mapping:
+ static: >-
+ #/components/schemas/StaticMemoryTransform
+ javascript: >-
+ #/components/schemas/schemas-JavascriptTransform
+ ai: '#/components/schemas/schemas-AiTransform'
+ output_schema:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ JSON Schema object defining structured
+ output format. Used when you need the AI
+ to return data in a specific shape.
+
+ Supports standard JSON Schema
+ properties: type, properties, required,
+ items, enum, pattern, minLength,
+ maxLength, minimum, maximum, etc.
+
+ Example: { type: 'object', properties: {
+ name: { type: 'string' }, age: { type:
+ 'integer' } }, required: ['name'] }
+ user_images:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ Array of image references for
+ vision-capable models.
+
+ Format: Array<{ bucket: string, key:
+ string }> - S3 object references
+
+ Example: [{ bucket: 'my-bucket', key:
+ 'images/photo.jpg' }]
+ max_completion_tokens:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ Integer. Maximum number of tokens the AI
+ will generate in its response.
+
+ Range: 1 to 4,294,967,295. Typical
+ values: 256-4096 for most use cases.
+ temperature:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ Float. Controls randomness/creativity of
+ responses.
+
+ Range: 0.0 to 2.0 (provider-dependent)
+
+ - 0.0 = deterministic, focused responses
+
+ - 0.7 = balanced (common default)
+
+ - 1.0+ = more creative/random
+ required:
+ - provider
+ - user_message
+ - output_type
+ tools:
+ type: array
+ description: >-
+ Array of tools the agent can use. The
+ agent decides which tools to call based
+ on the task
+ items:
+ type: object
+ description: >-
+ A tool available to an AI agent. Can be
+ a flow module or an external MCP (Model
+ Context Protocol) tool
+ properties: &ref_306
+ id:
+ type: string
+ description: >-
+ Unique identifier for this tool. Cannot
+ contain spaces - use underscores instead
+ (e.g., 'get_user_data' not 'get user
+ data')
+ summary:
+ type: string
+ description: >-
+ Short description of what this tool does
+ (shown to the AI)
+ value:
+ description: >-
+ The implementation of a tool. Can be a
+ flow module (script/flow) or an MCP tool
+ reference
+ oneOf: &ref_528
+ - description: >-
+ A tool implemented as a flow module
+ (script, flow, etc.). The AI can call
+ this like any other flow module
+ allOf: &ref_523
+ - type: object
+ properties:
+ tool_type:
+ type: string
+ enum:
+ - flowmodule
+ required:
+ - tool_type
+ - description: >-
+ The actual implementation of a flow
+ step. Can be a script (inline or
+ referenced), subflow, loop, branch, or
+ special module type
+ oneOf: *ref_70
+ discriminator: &ref_71
+ propertyName: type
+ mapping:
+ rawscript: '#/components/schemas/schemas-RawScript'
+ script: '#/components/schemas/schemas-PathScript'
+ flow: '#/components/schemas/schemas-PathFlow'
+ forloopflow: '#/components/schemas/schemas-ForloopFlow'
+ whileloopflow: >-
+ #/components/schemas/schemas-WhileloopFlow
+ branchone: '#/components/schemas/schemas-BranchOne'
+ branchall: '#/components/schemas/schemas-BranchAll'
+ identity: '#/components/schemas/schemas-Identity'
+ aiagent: '#/components/schemas/schemas-AiAgent'
+ - type: object
+ description: >-
+ Reference to an external MCP (Model
+ Context Protocol) tool. The AI can call
+ tools from MCP servers
+ properties: &ref_524
+ tool_type:
+ type: string
+ enum:
+ - mcp
+ resource_path:
+ type: string
+ description: >-
+ Path to the MCP resource/server
+ configuration
+ include_tools:
+ type: array
+ description: >-
+ Whitelist of specific tools to include
+ from this MCP server
+ items:
+ type: string
+ exclude_tools:
+ type: array
+ description: >-
+ Blacklist of tools to exclude from this
+ MCP server
+ items:
+ type: string
+ required: &ref_525
+ - tool_type
+ - resource_path
+ - type: object
+ description: >-
+ A tool implemented as a websearch tool.
+ The AI can call this like any other
+ websearch tool
+ properties: &ref_526
+ tool_type:
+ type: string
+ enum:
+ - websearch
+ required: &ref_527
+ - tool_type
+ discriminator: &ref_529
+ propertyName: tool_type
+ mapping:
+ flowmodule: '#/components/schemas/FlowModuleTool'
+ mcp: '#/components/schemas/McpToolValue'
+ websearch: '#/components/schemas/WebsearchToolValue'
+ required: &ref_307
+ - id
+ - value
+ type:
+ type: string
+ enum:
+ - aiagent
+ parallel:
+ type: boolean
+ description: >-
+ If true, the agent can execute multiple
+ tool calls in parallel
+ required: &ref_301
+ - tools
+ - type
+ - input_transforms
+ discriminator: *ref_71
stop_after_if:
+ description: Early termination condition for a module
type: object
- properties: &ref_46
+ properties: &ref_72
skip_if_stopped:
type: boolean
+ description: >-
+ If true, following steps are skipped
+ when this condition triggers
expr:
type: string
+ description: >-
+ JavaScript expression evaluated after
+ the module runs. Can use 'result'
+ (step's result) or 'flow_input'. Return
+ true to stop
error_message:
type: string
- required: &ref_47
+ description: Custom error message shown when stopping
+ required: &ref_73
- expr
stop_after_all_iters_if:
+ description: Early termination condition for a module
type: object
- properties: *ref_46
- required: *ref_47
+ properties: *ref_72
+ required: *ref_73
skip_if:
type: object
+ description: >-
+ Conditionally skip this step based on
+ previous results or flow inputs
properties:
expr:
type: string
+ description: >-
+ JavaScript expression that returns true
+ to skip. Can use 'flow_input' or
+ 'results.'
required:
- expr
sleep:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be a
+ static value or a JavaScript expression that
+ references previous results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
cache_ttl:
type: number
+ description: >-
+ Cache duration in seconds for this step's
+ results
+ cache_ignore_s3_path:
+ type: boolean
timeout:
- type: number
+ description: >-
+ Maps input parameters for a step. Can be a
+ static value or a JavaScript expression that
+ references previous results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
delete_after_use:
type: boolean
+ description: >-
+ If true, this step's result is deleted after
+ use to save memory
summary:
type: string
+ description: Short description of what this step does
mock:
type: object
+ description: >-
+ Mock configuration for testing without
+ executing the actual step
properties:
enabled:
type: boolean
- return_value: {}
+ description: >-
+ If true, return mock value instead of
+ executing
+ return_value:
+ description: Value to return when mocked
suspend:
type: object
+ description: >-
+ Configuration for approval/resume steps that
+ wait for user input
properties:
required_events:
type: integer
+ description: >-
+ Number of approvals required before
+ continuing
timeout:
type: integer
+ description: >-
+ Timeout in seconds before
+ auto-continuing or canceling
resume_form:
type: object
+ description: >-
+ Form schema for collecting input when
+ resuming
properties:
schema:
type: object
+ description: JSON Schema for the resume form
user_auth_required:
type: boolean
+ description: >-
+ If true, only authenticated users can
+ approve
user_groups_required:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be
+ a static value or a JavaScript
+ expression that references previous
+ results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
self_approval_disabled:
type: boolean
+ description: >-
+ If true, the user who started the flow
+ cannot approve
hide_cancel:
type: boolean
+ description: >-
+ If true, hide the cancel button on the
+ approval form
continue_on_disapprove_timeout:
type: boolean
+ description: >-
+ If true, continue flow on timeout
+ instead of canceling
priority:
type: number
+ description: >-
+ Execution priority for this step (higher
+ numbers run first)
continue_on_error:
type: boolean
+ description: >-
+ If true, flow continues even if this step
+ fails
retry:
+ description: >-
+ Retry configuration for failed module
+ executions
type: object
- properties: &ref_218
+ properties: &ref_276
constant:
type: object
+ description: >-
+ Retry with constant delay between
+ attempts
properties:
attempts:
type: integer
+ description: Number of retry attempts
seconds:
type: integer
+ description: Seconds to wait between retries
exponential:
type: object
+ description: >-
+ Retry with exponential backoff (delay
+ doubles each time)
properties:
attempts:
type: integer
+ description: Number of retry attempts
multiplier:
type: integer
+ description: Multiplier for exponential backoff
seconds:
type: integer
+ minimum: 1
+ description: Initial delay in seconds
random_factor:
type: integer
minimum: 0
maximum: 100
- required: *ref_45
+ description: >-
+ Random jitter percentage (0-100) to
+ avoid thundering herd
+ retry_if:
+ type: object
+ description: >-
+ Conditional retry based on error or
+ result
+ properties: &ref_167
+ expr:
+ type: string
+ description: >-
+ JavaScript expression that returns true
+ to retry. Has access to 'result' and
+ 'error' variables
+ required: &ref_168
+ - expr
+ required: *ref_65
failure_module:
+ description: >-
+ A single step in a flow. Can be a script, subflow,
+ loop, or branch
type: object
- properties: *ref_44
- required: *ref_45
+ properties: *ref_64
+ required: *ref_65
preprocessor_module:
+ description: >-
+ A single step in a flow. Can be a script, subflow,
+ loop, or branch
type: object
- properties: *ref_44
- required: *ref_45
+ properties: *ref_64
+ required: *ref_65
same_worker:
type: boolean
+ description: >-
+ If true, all steps run on the same worker for
+ better performance
concurrent_limit:
type: number
+ description: >-
+ Maximum number of concurrent executions of this
+ flow
concurrency_key:
type: string
+ description: >-
+ Expression to group concurrent executions (e.g.,
+ by user ID)
concurrency_time_window_s:
type: number
+ description: Time window in seconds for concurrent_limit
+ debounce_delay_s:
+ type: number
+ description: Delay in seconds to debounce flow executions
+ debounce_key:
+ type: string
+ description: Expression to group debounced executions
+ debounce_args_to_accumulate:
+ type: array
+ description: >-
+ Arguments to accumulate across debounced
+ executions
+ items:
+ type: string
+ max_total_debouncing_time:
+ type: number
+ description: >-
+ Maximum total time in seconds that a job can be
+ debounced
+ max_total_debounces_amount:
+ type: number
+ description: Maximum number of times a job can be debounced
skip_expr:
type: string
+ description: >-
+ JavaScript expression to conditionally skip the
+ entire flow
cache_ttl:
type: number
+ description: Cache duration in seconds for flow results
+ cache_ignore_s3_path:
+ type: boolean
+ flow_env:
+ type: object
+ description: Environment variables available to all steps
+ additionalProperties:
+ type: string
priority:
type: number
+ description: Execution priority (higher numbers run first)
early_return:
type: string
- required: &ref_378
+ description: >-
+ JavaScript expression to return early from the
+ flow
+ chat_input_enabled:
+ type: boolean
+ description: Whether this flow accepts chat-style input
+ notes:
+ type: array
+ description: Sticky notes attached to the flow
+ items:
+ type: object
+ description: >-
+ A sticky note attached to a flow for
+ documentation and annotation
+ properties: &ref_120
+ id:
+ type: string
+ description: Unique identifier for the note
+ text:
+ type: string
+ description: Content of the note
+ position:
+ type: object
+ description: Position of the note in the flow editor
+ properties:
+ x:
+ type: number
+ description: X coordinate
+ 'y':
+ type: number
+ description: Y coordinate
+ required:
+ - x
+ - 'y'
+ size:
+ type: object
+ description: Size of the note in the flow editor
+ properties:
+ width:
+ type: number
+ description: Width in pixels
+ height:
+ type: number
+ description: Height in pixels
+ required:
+ - width
+ - height
+ color:
+ type: string
+ description: >-
+ Color of the note (e.g., "yellow",
+ "#ffff00")
+ type:
+ type: string
+ enum:
+ - free
+ - group
+ description: >-
+ Type of note - 'free' for standalone notes,
+ 'group' for notes that group other nodes
+ locked:
+ type: boolean
+ default: false
+ description: >-
+ Whether the note is locked and cannot be
+ edited or moved
+ contained_node_ids:
+ type: array
+ items:
+ type: string
+ description: >-
+ For group notes, the IDs of nodes contained
+ within this group
+ required: &ref_121
+ - id
+ - text
+ - color
+ - type
+ required: &ref_531
- modules
schema:
type: object
- required: &ref_69
+ description: >-
+ JSON Schema for flow inputs. Use this to define input
+ parameters, their types, defaults, and validation. For
+ resource inputs, set type to 'object' and format to
+ 'resource-' (e.g., 'resource-stripe')
+ on_behalf_of_email:
+ type: string
+ description: >-
+ The flow will be run with the permissions of the user
+ with this email.
+ required: &ref_99
- summary
- value
/apps/hub/list:
@@ -6074,7 +9010,7 @@ paths:
- name: id
in: path
required: true
- schema: *ref_41
+ schema: *ref_61
responses:
'200':
description: app
@@ -6094,6 +9030,36 @@ paths:
- value
required:
- app
+ /apps/hub/get_raw/{id}:
+ get:
+ summary: get hub raw app by id
+ operationId: getHubRawAppById
+ tags:
+ - app
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema: *ref_61
+ responses:
+ '200':
+ description: raw app
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ app:
+ type: object
+ properties:
+ summary:
+ type: string
+ value: {}
+ required:
+ - summary
+ - value
+ required:
+ - app
/apps_u/public_app_by_custom_path/{custom_path}:
get:
summary: get public app by custom path
@@ -6104,7 +9070,7 @@ paths:
- name: custom_path
in: path
required: true
- schema: &ref_81
+ schema: &ref_111
type: string
responses:
'200':
@@ -6114,7 +9080,7 @@ paths:
schema:
allOf:
- type: object
- properties: &ref_76
+ properties: &ref_106
id:
type: integer
workspace_id:
@@ -6132,11 +9098,10 @@ paths:
created_at:
type: string
format: date-time
- value:
- type: object
+ value: {}
policy:
type: object
- properties: &ref_75
+ properties: &ref_105
triggerables:
type: object
additionalProperties:
@@ -6180,7 +9145,11 @@ paths:
type: boolean
custom_path:
type: string
- required: &ref_77
+ raw_app:
+ type: boolean
+ bundle_secret:
+ type: string
+ required: &ref_107
- id
- workspace_id
- path
@@ -6192,6 +9161,7 @@ paths:
- policy
- execution_mode
- extra_perms
+ - raw_app
- type: object
properties:
workspace_id:
@@ -6206,7 +9176,7 @@ paths:
- name: path
in: path
required: true
- schema: &ref_48
+ schema: &ref_74
type: string
responses:
'200':
@@ -6225,7 +9195,7 @@ paths:
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: script details
@@ -6246,6 +9216,29 @@ paths:
required:
- content
- language
+ /scripts/hub/pick/{path}:
+ get:
+ summary: record hub script pick
+ operationId: pickHubScriptByPath
+ tags:
+ - script
+ parameters:
+ - name: path
+ in: path
+ required: true
+ schema: *ref_74
+ responses:
+ '200':
+ description: script pick recorded
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ success:
+ type: boolean
+ required:
+ - success
/scripts/hub/top:
get:
summary: get top hub scripts
@@ -6296,7 +9289,7 @@ paths:
type: number
kind:
type: string
- enum: &ref_49
+ enum: &ref_75
- script
- failure
- trigger
@@ -6367,7 +9360,7 @@ paths:
type: string
kind:
type: string
- enum: *ref_49
+ enum: *ref_75
score:
type: number
required:
@@ -6388,7 +9381,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: script list
@@ -6417,24 +9410,24 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: order_desc
description: order by desc order (default true)
in: query
- schema: &ref_66
+ schema: &ref_96
type: boolean
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: &ref_67
+ schema: &ref_97
type: string
- name: path_start
description: mask to filter matching starting path
@@ -6545,6 +9538,21 @@ paths:
Accepts multiple values as a comma-separated list.
schema:
type: string
+ - name: without_description
+ in: query
+ description: |
+ (default false)
+ If true, the description field will be omitted from the response.
+ schema:
+ type: boolean
+ - name: dedicated_worker
+ in: query
+ description: |
+ (default regardless)
+ If true, show only scripts with dedicated_worker enabled.
+ If false, show only scripts with dedicated_worker disabled.
+ schema:
+ type: boolean
responses:
'200':
description: All scripts
@@ -6554,7 +9562,7 @@ paths:
type: array
items:
type: object
- properties: &ref_51
+ properties: &ref_79
workspace_id:
type: string
hash:
@@ -6597,7 +9605,7 @@ paths:
type: string
language:
type: string
- enum: &ref_50
+ enum: &ref_76
- python3
- deno
- go
@@ -6618,7 +9626,9 @@ paths:
- csharp
- nu
- java
+ - ruby
- duckdb
+ - bunnative
kind:
type: string
enum:
@@ -6646,6 +9656,18 @@ paths:
type: integer
concurrency_key:
type: string
+ debounce_key:
+ type: string
+ debounce_delay_s:
+ type: integer
+ debounce_args_to_accumulate:
+ type: array
+ items:
+ type: string
+ max_total_debouncing_time:
+ type: integer
+ max_total_debounces_amount:
+ type: integer
cache_ttl:
type: number
dedicated_worker:
@@ -6670,7 +9692,7 @@ paths:
type: boolean
on_behalf_of_email:
type: string
- required: &ref_52
+ required: &ref_80
- hash
- path
- summary
@@ -6697,7 +9719,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: list of script paths
@@ -6717,7 +9739,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
required: true
content:
@@ -6755,7 +9777,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: kind
in: path
required: true
@@ -6768,7 +9790,7 @@ paths:
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: draft deleted
@@ -6780,13 +9802,27 @@ paths:
post:
summary: create script
operationId: createScript
+ x-mcp-tool: true
+ x-mcp-instructions: >-
+ To create a script, specify the path (e.g., 'f/my_folder/my_script'),
+ the content (source code), and the language. For TypeScript, use 'bun'
+ unless deno-specific APIs are needed.
+ x-mcp-tool-include-fields:
+ - path
+ - content
+ - language
+ - summary
+ - description
+ - kind
+ - tag
+ - deployment_message
tags:
- script
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Partially filled script
required: true
@@ -6794,7 +9830,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_56
+ properties: &ref_84
path:
type: string
parent_hash:
@@ -6813,7 +9849,7 @@ paths:
type: string
language:
type: string
- enum: *ref_50
+ enum: *ref_76
kind:
type: string
enum:
@@ -6837,6 +9873,8 @@ paths:
type: integer
cache_ttl:
type: number
+ cache_ignore_s3_path:
+ type: boolean
dedicated_worker:
type: boolean
ws_error_handler_muted:
@@ -6853,6 +9891,18 @@ paths:
type: string
concurrency_key:
type: string
+ debounce_key:
+ type: string
+ debounce_delay_s:
+ type: integer
+ debounce_args_to_accumulate:
+ type: array
+ items:
+ type: string
+ max_total_debouncing_time:
+ type: integer
+ max_total_debounces_amount:
+ type: integer
visible_to_runner_only:
type: boolean
no_main_func:
@@ -6875,10 +9925,11 @@ paths:
type: string
kind:
type: string
- enum: &ref_202
+ enum: &ref_262
- s3object
- resource
- ducklake
+ - datatable
access_type:
type: string
enum:
@@ -6891,7 +9942,7 @@ paths:
- r
- w
- rw
- required: &ref_57
+ required: &ref_85
- path
- summary
- description
@@ -6914,11 +9965,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
requestBody:
description: Workspace error handler enabled
required: true
@@ -6945,11 +9996,6 @@ paths:
tags:
- worker
parameters:
- - name: workspace
- in: query
- schema:
- type: string
- required: false
- name: show_workspace_restriction
in: query
schema:
@@ -6964,6 +10010,26 @@ paths:
type: array
items:
type: string
+ /w/{workspace}/workers/custom_tags:
+ get:
+ summary: get custom tags available for this workspace
+ operationId: getCustomTagsForWorkspace
+ tags:
+ - worker
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: list of custom tags for workspace
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
/workers/get_default_tags:
get:
summary: get all instance default tags
@@ -6992,6 +10058,180 @@ paths:
application/json:
schema:
type: boolean
+ /w/{workspace}/workspace_dependencies/create:
+ post:
+ summary: create workspace dependencies
+ operationId: createWorkspaceDependencies
+ tags:
+ - workspace_dependencies
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: New workspace dependencies
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: &ref_345
+ workspace_id:
+ type: string
+ language:
+ type: string
+ enum: *ref_76
+ name:
+ type: string
+ description:
+ type: string
+ content:
+ type: string
+ required: &ref_346
+ - workspace_id
+ - language
+ - content
+ responses:
+ '201':
+ description: workspace dependencies created
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/workspace_dependencies/archive/{language}:
+ post:
+ summary: archive workspace dependencies (require admin)
+ operationId: archiveWorkspaceDependencies
+ tags:
+ - workspace_dependencies
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: language
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_76
+ - name: name
+ in: query
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: result
+ content:
+ application/json:
+ schema: {}
+ /w/{workspace}/workspace_dependencies/delete/{language}:
+ post:
+ summary: delete workspace dependencies (require admin)
+ operationId: deleteWorkspaceDependencies
+ tags:
+ - workspace_dependencies
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: language
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_76
+ - name: name
+ in: query
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: result
+ content:
+ application/json:
+ schema: {}
+ /w/{workspace}/workspace_dependencies/list:
+ get:
+ summary: list all workspace dependencies
+ operationId: listWorkspaceDependencies
+ tags:
+ - workspace_dependencies
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: All workspace dependencies
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties: &ref_77
+ id:
+ type: integer
+ archived:
+ type: boolean
+ name:
+ type: string
+ description:
+ type: string
+ content:
+ type: string
+ language:
+ type: string
+ enum: *ref_76
+ workspace_id:
+ type: string
+ created_at:
+ type: string
+ format: date-time
+ required: &ref_78
+ - workspace_id
+ - language
+ - created_at
+ - content
+ - id
+ - archived
+ /w/{workspace}/workspace_dependencies/get_latest/{language}:
+ get:
+ summary: get latest workspace dependencies by language and name
+ operationId: getLatestWorkspaceDependencies
+ tags:
+ - workspace_dependencies
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: language
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_76
+ - name: name
+ in: query
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Latest workspace dependencies
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_77
+ required: *ref_78
/w/{workspace}/scripts/archive/p/{path}:
post:
summary: archive script by path
@@ -7002,11 +10242,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: script archived
@@ -7024,11 +10264,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: hash
in: path
required: true
- schema: &ref_53
+ schema: &ref_81
type: string
responses:
'200':
@@ -7037,23 +10277,24 @@ paths:
application/json:
schema:
type: object
- properties: *ref_51
- required: *ref_52
+ properties: *ref_79
+ required: *ref_80
/w/{workspace}/scripts/delete/h/{hash}:
post:
summary: delete script by hash (erase content but keep hash, require admin)
operationId: deleteScriptByHash
+ x-mcp-tool: true
tags:
- script
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: hash
in: path
required: true
- schema: *ref_53
+ schema: *ref_81
responses:
'200':
description: script details
@@ -7061,23 +10302,24 @@ paths:
application/json:
schema:
type: object
- properties: *ref_51
- required: *ref_52
+ properties: *ref_79
+ required: *ref_80
/w/{workspace}/scripts/delete/p/{path}:
post:
summary: delete script at a given path (require admin)
operationId: deleteScriptByPath
+ x-mcp-tool: true
tags:
- script
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: keep_captures
description: keep captures
in: query
@@ -7090,6 +10332,40 @@ paths:
application/json:
schema:
type: string
+ /w/{workspace}/scripts/delete_bulk:
+ delete:
+ summary: delete scripts in bulk
+ operationId: deleteScriptsBulk
+ tags:
+ - script
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: paths to delete
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ paths:
+ type: array
+ items:
+ type: string
+ required:
+ - paths
+ responses:
+ '200':
+ description: deleted paths
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
/w/{workspace}/scripts/get/p/{path}:
get:
summary: get script by path
@@ -7101,11 +10377,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: with_starred_info
in: query
schema:
@@ -7117,8 +10393,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_51
- required: *ref_52
+ properties: *ref_79
+ required: *ref_80
/w/{workspace}/scripts/get_triggers_count/{path}:
get:
summary: get triggers count of script
@@ -7129,11 +10405,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: triggers count
@@ -7141,7 +10417,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_73
+ properties: &ref_103
primary_schedule:
type: object
properties:
@@ -7155,6 +10431,8 @@ paths:
type: number
email_count:
type: number
+ default_email_count:
+ type: number
websocket_count:
type: number
postgres_count:
@@ -7169,6 +10447,8 @@ paths:
type: number
sqs_count:
type: number
+ nextcloud_count:
+ type: number
/w/{workspace}/scripts/list_tokens/{path}:
get:
summary: get tokens with script scope
@@ -7179,11 +10459,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: tokens list
@@ -7193,8 +10473,8 @@ paths:
type: array
items:
type: object
- properties: *ref_54
- required: *ref_55
+ properties: *ref_82
+ required: *ref_83
/w/{workspace}/scripts/get/draft/{path}:
get:
summary: get script by path with draft
@@ -7205,27 +10485,27 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: script details
content:
application/json:
schema:
- allOf: &ref_243
+ allOf: &ref_347
- type: object
- properties: *ref_56
- required: *ref_57
+ properties: *ref_84
+ required: *ref_85
- type: object
properties:
draft:
type: object
- properties: *ref_56
- required: *ref_57
+ properties: *ref_84
+ required: *ref_85
hash:
type: string
required:
@@ -7240,11 +10520,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: script history
@@ -7254,12 +10534,12 @@ paths:
type: array
items:
type: object
- properties: &ref_58
+ properties: &ref_86
script_hash:
type: string
deployment_msg:
type: string
- required: &ref_59
+ required: &ref_87
- script_hash
/w/{workspace}/scripts/list_paths_from_workspace_runnable/{path}:
get:
@@ -7271,11 +10551,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: list of script paths
@@ -7293,11 +10573,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
tags:
- script
responses:
@@ -7307,8 +10587,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_58
- required: *ref_59
+ properties: *ref_86
+ required: *ref_87
/w/{workspace}/scripts/history_update/h/{hash}/p/{path}:
post:
summary: update history of a script
@@ -7319,15 +10599,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: hash
in: path
required: true
- schema: *ref_53
+ schema: *ref_81
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
requestBody:
description: Script deployment message
required: true
@@ -7355,11 +10635,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: script content
@@ -7379,16 +10659,16 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: token
in: path
required: true
- schema: &ref_207
+ schema: &ref_266
type: string
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: script content
@@ -7406,11 +10686,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: does it exists
@@ -7428,11 +10708,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: hash
in: path
required: true
- schema: *ref_53
+ schema: *ref_81
- name: with_starred_info
in: query
schema:
@@ -7448,8 +10728,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_51
- required: *ref_52
+ properties: *ref_79
+ required: *ref_80
/w/{workspace}/scripts/raw/h/{path}:
get:
summary: raw script by hash
@@ -7460,11 +10740,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: script content
@@ -7482,11 +10762,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: hash
in: path
required: true
- schema: *ref_53
+ schema: *ref_81
responses:
'200':
description: script details
@@ -7499,6 +10779,9 @@ paths:
type: string
lock_error_logs:
type: string
+ job_id:
+ type: string
+ format: uuid
/w/{workspace}/jobs/list_selected_job_groups:
post:
summary: list selected jobs script/flow schemas grouped by (kind, path)
@@ -7509,7 +10792,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: script args
required: true
@@ -7565,17 +10848,22 @@ paths:
post:
summary: run script by path
operationId: runScriptByPath
+ x-mcp-tool: true
+ x-mcp-instructions: >-
+ You should first use getScriptByPath to retrieve the script's schema and
+ understand what arguments are expected.
+ x-mcp-tool-include-query-params: []
tags:
- job
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: scheduled_for
description: when to schedule this job (leave empty for immediate run)
in: query
@@ -7597,20 +10885,20 @@ paths:
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: &ref_60
+ schema: &ref_88
type: string
format: uuid
- name: tag
description: Override the tag to use
in: query
- schema: &ref_62
+ schema: &ref_89
type: string
- name: cache_ttl
description: >-
Override the cache time to live (in seconds). Can not be used to
disable caching, only override with a new cache ttl
in: query
- schema: &ref_63
+ schema: &ref_90
type: string
- name: job_id
description: >-
@@ -7619,7 +10907,7 @@ paths:
queue or as a completed job, the request to create one will fail
(Bad Request)
in: query
- schema: &ref_61
+ schema: &ref_91
type: string
format: uuid
- name: invisible_to_owner
@@ -7635,7 +10923,7 @@ paths:
schema:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
responses:
'201':
description: job created
@@ -7644,67 +10932,6 @@ paths:
schema:
type: string
format: uuid
- /w/{workspace}/jobs/openai_sync/p/{path}:
- post:
- summary: run script by path in openai format
- operationId: openaiSyncScriptByPath
- tags:
- - job
- parameters:
- - name: workspace
- in: path
- required: true
- schema: *ref_0
- - name: path
- in: path
- required: true
- schema: *ref_48
- - name: parent_job
- description: >-
- The parent job that is at the origin and responsible for the
- execution of this script if any
- in: query
- schema: *ref_60
- - name: job_id
- description: >-
- The job id to assign to the created job. if missing, job is chosen
- randomly using the ULID scheme. If a job id already exists in the
- queue or as a completed job, the request to create one will fail
- (Bad Request)
- in: query
- schema: *ref_61
- - name: include_header
- description: >
- List of headers's keys (separated with ',') whove value are added to
- the args
-
- Header's key lowercased and '-'' replaced to '_' such that
- 'Content-Type' becomes the 'content_type' arg key
- in: query
- schema: &ref_64
- type: string
- - name: queue_limit
- description: >
- The maximum size of the queue for which the request would get
- rejected if that job would push it above that limit
- in: query
- schema: &ref_65
- type: string
- requestBody:
- description: script args
- required: true
- content:
- application/json:
- schema:
- type: object
- description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- responses:
- '200':
- description: job result
- content:
- application/json:
- schema: {}
/w/{workspace}/jobs/run_wait_result/p/{path}:
post:
summary: run script by path
@@ -7715,27 +10942,27 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: tag
description: Override the tag to use
in: query
- schema: *ref_62
+ schema: *ref_89
- name: cache_ttl
description: >-
Override the cache time to live (in seconds). Can not be used to
disable caching, only override with a new cache ttl
in: query
- schema: *ref_63
+ schema: *ref_90
- name: job_id
description: >-
The job id to assign to the created job. if missing, job is chosen
@@ -7743,7 +10970,7 @@ paths:
queue or as a completed job, the request to create one will fail
(Bad Request)
in: query
- schema: *ref_61
+ schema: *ref_91
- name: include_header
description: >
List of headers's keys (separated with ',') whove value are added to
@@ -7752,13 +10979,20 @@ paths:
Header's key lowercased and '-'' replaced to '_' such that
'Content-Type' becomes the 'content_type' arg key
in: query
- schema: *ref_64
+ schema: &ref_92
+ type: string
- name: queue_limit
description: >
The maximum size of the queue for which the request would get
rejected if that job would push it above that limit
in: query
- schema: *ref_65
+ schema: &ref_93
+ type: string
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: &ref_94
+ type: boolean
requestBody:
description: script args
required: true
@@ -7767,7 +11001,7 @@ paths:
schema:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
responses:
'200':
description: job result
@@ -7783,27 +11017,27 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: tag
description: Override the tag to use
in: query
- schema: *ref_62
+ schema: *ref_89
- name: cache_ttl
description: >-
Override the cache time to live (in seconds). Can not be used to
disable caching, only override with a new cache ttl
in: query
- schema: *ref_63
+ schema: *ref_90
- name: job_id
description: >-
The job id to assign to the created job. if missing, job is chosen
@@ -7811,7 +11045,7 @@ paths:
queue or as a completed job, the request to create one will fail
(Bad Request)
in: query
- schema: *ref_61
+ schema: *ref_91
- name: include_header
description: >
List of headers's keys (separated with ',') whove value are added to
@@ -7820,13 +11054,13 @@ paths:
Header's key lowercased and '-'' replaced to '_' such that
'Content-Type' becomes the 'content_type' arg key
in: query
- schema: *ref_64
+ schema: *ref_92
- name: queue_limit
description: >
The maximum size of the queue for which the request would get
rejected if that job would push it above that limit
in: query
- schema: *ref_65
+ schema: *ref_93
- name: payload
description: >
The base64 encoded payload that has been encoded as a JSON. e.g how
@@ -7834,61 +11068,12 @@ paths:
`encodeURIComponent(btoa(JSON.stringify({a: 2})))`
in: query
- schema: &ref_126
+ schema: &ref_95
type: string
- responses:
- '200':
- description: job result
- content:
- application/json:
- schema: {}
- /w/{workspace}/jobs/openai_sync/f/{path}:
- post:
- summary: run flow by path and wait until completion in openai format
- operationId: openaiSyncFlowByPath
- tags:
- - job
- parameters:
- - name: workspace
- in: path
- required: true
- schema: *ref_0
- - name: path
- in: path
- required: true
- schema: *ref_48
- - name: include_header
- description: >
- List of headers's keys (separated with ',') whove value are added to
- the args
-
- Header's key lowercased and '-'' replaced to '_' such that
- 'Content-Type' becomes the 'content_type' arg key
+ - name: skip_preprocessor
+ description: skip the preprocessor
in: query
- schema: *ref_64
- - name: queue_limit
- description: >
- The maximum size of the queue for which the request would get
- rejected if that job would push it above that limit
- in: query
- schema: *ref_65
- - name: job_id
- description: >-
- The job id to assign to the created job. if missing, job is chosen
- randomly using the ULID scheme. If a job id already exists in the
- queue or as a completed job, the request to create one will fail
- (Bad Request)
- in: query
- schema: *ref_61
- requestBody:
- description: script args
- required: true
- content:
- application/json:
- schema:
- type: object
- description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ schema: *ref_94
responses:
'200':
description: job result
@@ -7905,11 +11090,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: include_header
description: >
List of headers's keys (separated with ',') whove value are added to
@@ -7918,13 +11103,13 @@ paths:
Header's key lowercased and '-'' replaced to '_' such that
'Content-Type' becomes the 'content_type' arg key
in: query
- schema: *ref_64
+ schema: *ref_92
- name: queue_limit
description: >
The maximum size of the queue for which the request would get
rejected if that job would push it above that limit
in: query
- schema: *ref_65
+ schema: *ref_93
- name: job_id
description: >-
The job id to assign to the created job. if missing, job is chosen
@@ -7932,7 +11117,17 @@ paths:
queue or as a completed job, the request to create one will fail
(Bad Request)
in: query
- schema: *ref_61
+ schema: *ref_91
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
requestBody:
description: script args
required: true
@@ -7941,13 +11136,743 @@ paths:
schema:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
responses:
'200':
description: job result
content:
application/json:
schema: {}
+ /w/{workspace}/jobs/run_wait_result/fv/{version}:
+ post:
+ summary: run flow by version and wait until completion
+ operationId: runWaitResultFlowByVersion
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: version
+ description: flow version ID
+ in: path
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: script args
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ responses:
+ '200':
+ description: job result
+ content:
+ application/json:
+ schema: {}
+ get:
+ summary: run flow by version with GET and wait until completion
+ operationId: runWaitResultFlowByVersionGet
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: version
+ description: flow version ID
+ in: path
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: payload
+ description: >
+ The base64 encoded payload that has been encoded as a JSON. e.g how
+ to encode such payload encodeURIComponent
+
+ `encodeURIComponent(btoa(JSON.stringify({a: 2})))`
+ in: query
+ schema: *ref_95
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: job result
+ content:
+ application/json:
+ schema: {}
+ /w/{workspace}/jobs/run_and_stream/f/{path}:
+ post:
+ summary: run flow by path and stream updates via SSE
+ operationId: runAndStreamFlowByPath
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_74
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
+ - name: poll_delay_ms
+ description: delay between polling for job updates in milliseconds
+ in: query
+ schema:
+ type: integer
+ format: int64
+ requestBody:
+ description: flow args
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ responses:
+ '200':
+ description: server-sent events stream of job updates
+ content:
+ text/event-stream:
+ schema:
+ type: string
+ get:
+ summary: run flow by path with GET and stream updates via SSE
+ operationId: runAndStreamFlowByPathGet
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_74
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: payload
+ description: >
+ The base64 encoded payload that has been encoded as a JSON. e.g how
+ to encode such payload encodeURIComponent
+
+ `encodeURIComponent(btoa(JSON.stringify({a: 2})))`
+ in: query
+ schema: *ref_95
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
+ - name: poll_delay_ms
+ description: delay between polling for job updates in milliseconds
+ in: query
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: server-sent events stream of job updates
+ content:
+ text/event-stream:
+ schema:
+ type: string
+ /w/{workspace}/jobs/run_and_stream/fv/{version}:
+ post:
+ summary: run flow by version and stream updates via SSE
+ operationId: runAndStreamFlowByVersion
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: version
+ description: flow version ID
+ in: path
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
+ - name: poll_delay_ms
+ description: delay between polling for job updates in milliseconds
+ in: query
+ schema:
+ type: integer
+ format: int64
+ requestBody:
+ description: flow args
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ responses:
+ '200':
+ description: server-sent events stream of job updates
+ content:
+ text/event-stream:
+ schema:
+ type: string
+ get:
+ summary: run flow by version with GET and stream updates via SSE
+ operationId: runAndStreamFlowByVersionGet
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: version
+ description: flow version ID
+ in: path
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: payload
+ description: >
+ The base64 encoded payload that has been encoded as a JSON. e.g how
+ to encode such payload encodeURIComponent
+
+ `encodeURIComponent(btoa(JSON.stringify({a: 2})))`
+ in: query
+ schema: *ref_95
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
+ - name: poll_delay_ms
+ description: delay between polling for job updates in milliseconds
+ in: query
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: server-sent events stream of job updates
+ content:
+ text/event-stream:
+ schema:
+ type: string
+ /w/{workspace}/jobs/run_and_stream/p/{path}:
+ post:
+ summary: run script by path and stream updates via SSE
+ operationId: runAndStreamScriptByPath
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_74
+ - name: parent_job
+ description: >-
+ The parent job that is at the origin and responsible for the
+ execution of this script if any
+ in: query
+ schema: *ref_88
+ - name: tag
+ description: Override the tag to use
+ in: query
+ schema: *ref_89
+ - name: cache_ttl
+ description: >-
+ Override the cache time to live (in seconds). Can not be used to
+ disable caching, only override with a new cache ttl
+ in: query
+ schema: *ref_90
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: poll_delay_ms
+ description: delay between polling for job updates in milliseconds
+ in: query
+ schema:
+ type: integer
+ format: int64
+ requestBody:
+ description: script args
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ responses:
+ '200':
+ description: server-sent events stream of job updates
+ content:
+ text/event-stream:
+ schema:
+ type: string
+ get:
+ summary: run script by path with GET and stream updates via SSE
+ operationId: runAndStreamScriptByPathGet
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_74
+ - name: parent_job
+ description: >-
+ The parent job that is at the origin and responsible for the
+ execution of this script if any
+ in: query
+ schema: *ref_88
+ - name: tag
+ description: Override the tag to use
+ in: query
+ schema: *ref_89
+ - name: cache_ttl
+ description: >-
+ Override the cache time to live (in seconds). Can not be used to
+ disable caching, only override with a new cache ttl
+ in: query
+ schema: *ref_90
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: payload
+ description: >
+ The base64 encoded payload that has been encoded as a JSON. e.g how
+ to encode such payload encodeURIComponent
+
+ `encodeURIComponent(btoa(JSON.stringify({a: 2})))`
+ in: query
+ schema: *ref_95
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: poll_delay_ms
+ description: delay between polling for job updates in milliseconds
+ in: query
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: server-sent events stream of job updates
+ content:
+ text/event-stream:
+ schema:
+ type: string
+ /w/{workspace}/jobs/run_and_stream/h/{hash}:
+ post:
+ summary: run script by hash and stream updates via SSE
+ operationId: runAndStreamScriptByHash
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: hash
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: parent_job
+ description: >-
+ The parent job that is at the origin and responsible for the
+ execution of this script if any
+ in: query
+ schema: *ref_88
+ - name: tag
+ description: Override the tag to use
+ in: query
+ schema: *ref_89
+ - name: cache_ttl
+ description: >-
+ Override the cache time to live (in seconds). Can not be used to
+ disable caching, only override with a new cache ttl
+ in: query
+ schema: *ref_90
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: poll_delay_ms
+ description: delay between polling for job updates in milliseconds
+ in: query
+ schema:
+ type: integer
+ format: int64
+ requestBody:
+ description: script args
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ responses:
+ '200':
+ description: server-sent events stream of job updates
+ content:
+ text/event-stream:
+ schema:
+ type: string
+ get:
+ summary: run script by hash with GET and stream updates via SSE
+ operationId: runAndStreamScriptByHashGet
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: hash
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: parent_job
+ description: >-
+ The parent job that is at the origin and responsible for the
+ execution of this script if any
+ in: query
+ schema: *ref_88
+ - name: tag
+ description: Override the tag to use
+ in: query
+ schema: *ref_89
+ - name: cache_ttl
+ description: >-
+ Override the cache time to live (in seconds). Can not be used to
+ disable caching, only override with a new cache ttl
+ in: query
+ schema: *ref_90
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: queue_limit
+ description: >
+ The maximum size of the queue for which the request would get
+ rejected if that job would push it above that limit
+ in: query
+ schema: *ref_93
+ - name: payload
+ description: >
+ The base64 encoded payload that has been encoded as a JSON. e.g how
+ to encode such payload encodeURIComponent
+
+ `encodeURIComponent(btoa(JSON.stringify({a: 2})))`
+ in: query
+ schema: *ref_95
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: poll_delay_ms
+ description: delay between polling for job updates in milliseconds
+ in: query
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: server-sent events stream of job updates
+ content:
+ text/event-stream:
+ schema:
+ type: string
/w/{workspace}/jobs/result_by_id/{flow_job_id}/{node_id}:
get:
summary: get job result by id
@@ -7958,7 +11883,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: flow_job_id
in: path
required: true
@@ -7985,7 +11910,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: list of flow paths
@@ -8005,7 +11930,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: flow list
@@ -8033,23 +11958,23 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: order_desc
description: order by desc order (default true)
in: query
- schema: *ref_66
+ schema: *ref_96
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
- name: path_start
description: mask to filter matching starting path
in: query
@@ -8094,6 +12019,21 @@ paths:
in: query
schema:
type: boolean
+ - name: without_description
+ in: query
+ description: |
+ (default false)
+ If true, the description field will be omitted from the response.
+ schema:
+ type: boolean
+ - name: dedicated_worker
+ in: query
+ description: |
+ (default regardless)
+ If true, show only flows with dedicated_worker enabled.
+ If false, show only flows with dedicated_worker disabled.
+ schema:
+ type: boolean
responses:
'200':
description: All flow
@@ -8103,12 +12043,15 @@ paths:
type: array
items:
allOf:
- - allOf: &ref_72
+ - allOf: &ref_102
- type: object
- properties: *ref_68
- required: *ref_69
+ description: >-
+ Top-level flow definition containing metadata,
+ configuration, and the flow structure
+ properties: *ref_98
+ required: *ref_99
- type: object
- properties: &ref_330
+ properties: &ref_449
workspace_id:
type: string
path:
@@ -8122,7 +12065,7 @@ paths:
type: boolean
extra_perms:
type: object
- additionalProperties: &ref_329
+ additionalProperties: &ref_448
type: boolean
starred:
type: boolean
@@ -8142,7 +12085,7 @@ paths:
type: boolean
on_behalf_of_email:
type: string
- required: &ref_331
+ required: &ref_450
- path
- edited_by
- edited_at
@@ -8152,6 +12095,8 @@ paths:
properties:
lock_error_logs:
type: string
+ version_id:
+ type: number
- type: object
properties:
has_draft:
@@ -8166,11 +12111,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
tags:
- flow
responses:
@@ -8182,7 +12127,7 @@ paths:
type: array
items:
type: object
- properties: &ref_70
+ properties: &ref_100
id:
type: integer
created_at:
@@ -8190,7 +12135,7 @@ paths:
format: date-time
deployment_msg:
type: string
- required: &ref_71
+ required: &ref_101
- id
- created_at
/w/{workspace}/flows/get_latest_version/{path}:
@@ -8201,11 +12146,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
tags:
- flow
responses:
@@ -8215,8 +12160,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_70
- required: *ref_71
+ properties: *ref_100
+ required: *ref_101
/w/{workspace}/flows/list_paths_from_workspace_runnable/{runnable_kind}/{path}:
get:
summary: list flow paths from workspace runnable
@@ -8227,11 +12172,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: runnable_kind
in: path
required: true
- schema: &ref_80
+ schema: &ref_110
type: string
enum:
- script
@@ -8239,7 +12184,11 @@ paths:
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
+ - name: match_path_start
+ in: query
+ schema:
+ type: boolean
responses:
'200':
description: list of flow paths
@@ -8249,7 +12198,7 @@ paths:
type: array
items:
type: string
- /w/{workspace}/flows/get/v/{version}/p/{path}:
+ /w/{workspace}/flows/get/v/{version}:
get:
summary: get flow version
operationId: getFlowVersion
@@ -8257,16 +12206,12 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: version
in: path
required: true
schema:
type: number
- - name: path
- in: path
- required: true
- schema: *ref_48
tags:
- flow
responses:
@@ -8275,8 +12220,8 @@ paths:
content:
application/json:
schema:
- allOf: *ref_72
- /w/{workspace}/flows/history_update/v/{version}/p/{path}:
+ allOf: *ref_102
+ /w/{workspace}/flows/history_update/v/{version}:
post:
summary: update flow history
operationId: updateFlowHistory
@@ -8284,16 +12229,12 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: version
in: path
required: true
schema:
type: number
- - name: path
- in: path
- required: true
- schema: *ref_48
requestBody:
description: Flow deployment message
required: true
@@ -8326,11 +12267,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: with_starred_info
in: query
schema:
@@ -8341,7 +12282,7 @@ paths:
content:
application/json:
schema:
- allOf: *ref_72
+ allOf: *ref_102
/w/{workspace}/flows/deployment_status/p/{path}:
get:
summary: get flow deployment status
@@ -8352,11 +12293,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: flow status
@@ -8367,6 +12308,9 @@ paths:
properties:
lock_error_logs:
type: string
+ job_id:
+ type: string
+ format: uuid
/w/{workspace}/flows/get_triggers_count/{path}:
get:
summary: get triggers count of flow
@@ -8377,11 +12321,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: triggers count
@@ -8389,7 +12333,7 @@ paths:
application/json:
schema:
type: object
- properties: *ref_73
+ properties: *ref_103
/w/{workspace}/flows/list_tokens/{path}:
get:
summary: get tokens with flow scope
@@ -8400,11 +12344,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: tokens list
@@ -8414,8 +12358,8 @@ paths:
type: array
items:
type: object
- properties: *ref_54
- required: *ref_55
+ properties: *ref_82
+ required: *ref_83
/w/{workspace}/flows/toggle_workspace_error_handler/{path}:
post:
summary: Toggle ON and OFF the workspace error handler for a given flow
@@ -8426,11 +12370,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
requestBody:
description: Workspace error handler enabled
required: true
@@ -8458,11 +12402,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: flow details with draft
@@ -8470,11 +12414,11 @@ paths:
application/json:
schema:
allOf:
- - allOf: *ref_72
+ - allOf: *ref_102
- type: object
properties:
draft:
- allOf: *ref_72
+ allOf: *ref_102
/w/{workspace}/flows/exists/{path}:
get:
summary: exists flow by path
@@ -8485,11 +12429,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: flow details
@@ -8501,13 +12445,25 @@ paths:
post:
summary: create flow
operationId: createFlow
+ x-mcp-tool: true
+ x-mcp-tool-include-fields:
+ - path
+ - summary
+ - description
+ - value
+ - schema
+ - tag
+ - deployment_message
+ x-mcp-tool-opaque-fields:
+ - value
+ - schema
tags:
- flow
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Partially filled flow
required: true
@@ -8515,10 +12471,13 @@ paths:
application/json:
schema:
allOf:
- - allOf: &ref_74
+ - allOf: &ref_104
- type: object
- properties: *ref_68
- required: *ref_69
+ description: >-
+ Top-level flow definition containing metadata,
+ configuration, and the flow structure
+ properties: *ref_98
+ required: *ref_99
- type: object
properties:
path:
@@ -8556,17 +12515,29 @@ paths:
post:
summary: update flow
operationId: updateFlow
+ x-mcp-tool: true
+ x-mcp-tool-include-fields:
+ - path
+ - summary
+ - description
+ - value
+ - schema
+ - tag
+ - deployment_message
+ x-mcp-tool-opaque-fields:
+ - value
+ - schema
tags:
- flow
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
requestBody:
description: Partially filled flow
required: true
@@ -8574,7 +12545,7 @@ paths:
application/json:
schema:
allOf:
- - allOf: *ref_74
+ - allOf: *ref_104
- type: object
properties:
deployment_message:
@@ -8596,11 +12567,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
requestBody:
description: archiveFlow
required: true
@@ -8622,17 +12593,18 @@ paths:
delete:
summary: delete flow by path
operationId: deleteFlowByPath
+ x-mcp-tool: true
tags:
- flow
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: keep_captures
description: keep captures
in: query
@@ -8645,6 +12617,180 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/flow_conversations/list:
+ get:
+ summary: list flow conversations
+ operationId: listFlowConversations
+ tags:
+ - flow_conversation
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: page
+ description: which page to return (start at 1, default 1)
+ in: query
+ schema: *ref_13
+ - name: per_page
+ description: number of items to return for a given page (default 30, max 100)
+ in: query
+ schema: *ref_14
+ - name: flow_path
+ description: filter conversations by flow path
+ in: query
+ schema:
+ type: string
+ responses:
+ '200':
+ description: flow conversations list
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ required: &ref_333
+ - id
+ - workspace_id
+ - flow_path
+ - created_at
+ - updated_at
+ - created_by
+ properties: &ref_334
+ id:
+ type: string
+ format: uuid
+ description: Unique identifier for the conversation
+ workspace_id:
+ type: string
+ description: The workspace ID where the conversation belongs
+ flow_path:
+ type: string
+ description: Path of the flow this conversation is for
+ title:
+ type: string
+ description: Optional title for the conversation
+ nullable: true
+ created_at:
+ type: string
+ format: date-time
+ description: When the conversation was created
+ updated_at:
+ type: string
+ format: date-time
+ description: When the conversation was last updated
+ created_by:
+ type: string
+ description: Username who created the conversation
+ /w/{workspace}/flow_conversations/delete/{conversation_id}:
+ delete:
+ summary: delete flow conversation
+ operationId: deleteFlowConversation
+ tags:
+ - flow_conversation
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: conversation_id
+ description: conversation id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: flow conversation deleted
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/flow_conversations/{conversation_id}/messages:
+ get:
+ summary: list conversation messages
+ operationId: listConversationMessages
+ tags:
+ - flow_conversation
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: page
+ description: which page to return (start at 1, default 1)
+ in: query
+ schema: *ref_13
+ - name: per_page
+ description: number of items to return for a given page (default 30, max 100)
+ in: query
+ schema: *ref_14
+ - name: conversation_id
+ description: conversation id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: after_id
+ description: id to fetch only the messages after that id
+ in: query
+ required: false
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: conversation messages
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ required: &ref_335
+ - id
+ - conversation_id
+ - message_type
+ - content
+ - created_at
+ properties: &ref_336
+ id:
+ type: string
+ format: uuid
+ description: Unique identifier for the message
+ conversation_id:
+ type: string
+ format: uuid
+ description: The conversation this message belongs to
+ message_type:
+ type: string
+ enum:
+ - user
+ - assistant
+ - system
+ - tool
+ description: Type of the message
+ content:
+ type: string
+ description: The message content
+ job_id:
+ type: string
+ format: uuid
+ nullable: true
+ description: Associated job ID if this message came from a flow run
+ created_at:
+ type: string
+ format: date-time
+ description: When the message was created
+ step_name:
+ type: string
+ description: The step name that produced that message
+ success:
+ type: boolean
+ description: Whether the message is a success
/w/{workspace}/raw_apps/list:
get:
summary: list all raw apps
@@ -8655,23 +12801,23 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: order_desc
description: order by desc order (default true)
in: query
- schema: *ref_66
+ schema: *ref_96
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
- name: path_start
description: mask to filter matching starting path
in: query
@@ -8698,7 +12844,7 @@ paths:
type: array
items:
type: object
- properties: &ref_341
+ properties: &ref_458
workspace_id:
type: string
path:
@@ -8716,55 +12862,29 @@ paths:
edited_at:
type: string
format: date-time
- required: &ref_342
+ required: &ref_459
- workspace_id
- path
- summary
- extra_perms
- version
- edited_at
- /w/{workspace}/raw_apps/exists/{path}:
+ /w/{workspace}/apps/get_data/v/{secretWithExtension}:
get:
- summary: does an app exisst at path
- operationId: existsRawApp
- tags:
- - raw_app
- parameters:
- - name: workspace
- in: path
- required: true
- schema: *ref_0
- - name: path
- in: path
- required: true
- schema: *ref_31
- responses:
- '200':
- description: app exists
- content:
- application/json:
- schema:
- type: boolean
- /w/{workspace}/apps/get_data/{version}/{path}:
- get:
- summary: get app by path
+ summary: get raw app data by
operationId: getRawAppData
tags:
- - raw_app
+ - app
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
- - name: version
+ schema: *ref_4
+ - name: secretWithExtension
in: path
required: true
- schema: &ref_206
- type: number
- - name: path
- in: path
- required: true
- schema: *ref_48
+ schema:
+ type: string
responses:
'200':
description: app details
@@ -8782,7 +12902,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: app list
@@ -8809,23 +12929,23 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: order_desc
description: order by desc order (default true)
in: query
- schema: *ref_66
+ schema: *ref_96
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
- name: path_start
description: mask to filter matching starting path
in: query
@@ -8866,7 +12986,7 @@ paths:
type: array
items:
type: object
- properties: &ref_335
+ properties: &ref_452
id:
type: integer
workspace_id:
@@ -8894,7 +13014,7 @@ paths:
- anonymous
raw_app:
type: boolean
- required: &ref_336
+ required: &ref_453
- id
- workspace_id
- path
@@ -8907,13 +13027,23 @@ paths:
post:
summary: create app
operationId: createApp
+ x-mcp-tool: true
+ x-mcp-tool-include-fields:
+ - path
+ - value
+ - summary
+ - policy
+ - deployment_message
+ x-mcp-tool-opaque-fields:
+ - value
+ - policy
tags:
- app
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new app
required: true
@@ -8929,7 +13059,7 @@ paths:
type: string
policy:
type: object
- properties: *ref_75
+ properties: *ref_105
draft_only:
type: boolean
deployment_message:
@@ -8958,7 +13088,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new app
required: true
@@ -8977,7 +13107,7 @@ paths:
type: string
policy:
type: object
- properties: *ref_75
+ properties: *ref_105
draft_only:
type: boolean
deployment_message:
@@ -9010,11 +13140,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: app exists
@@ -9032,11 +13162,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: with_starred_info
in: query
schema:
@@ -9048,8 +13178,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_76
- required: *ref_77
+ properties: *ref_106
+ required: *ref_107
/w/{workspace}/apps/get/lite/{path}:
get:
summary: get app lite by path
@@ -9060,11 +13190,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: app lite details
@@ -9072,8 +13202,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_76
- required: *ref_77
+ properties: *ref_106
+ required: *ref_107
/w/{workspace}/apps/get/draft/{path}:
get:
summary: get app by path with draft
@@ -9084,21 +13214,21 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: app details with draft
content:
application/json:
schema:
- allOf: &ref_343
+ allOf: &ref_460
- type: object
- properties: *ref_76
- required: *ref_77
+ properties: *ref_106
+ required: *ref_107
- type: object
properties:
draft_only:
@@ -9114,11 +13244,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: app history
@@ -9128,12 +13258,12 @@ paths:
type: array
items:
type: object
- properties: &ref_78
+ properties: &ref_108
version:
type: integer
deployment_msg:
type: string
- required: &ref_79
+ required: &ref_109
- version
/w/{workspace}/apps/get_latest_version/{path}:
get:
@@ -9143,11 +13273,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
tags:
- app
responses:
@@ -9157,8 +13287,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_78
- required: *ref_79
+ properties: *ref_108
+ required: *ref_109
/w/{workspace}/apps/list_paths_from_workspace_runnable/{runnable_kind}/{path}:
get:
summary: list app paths from workspace runnable
@@ -9169,15 +13299,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: runnable_kind
in: path
required: true
- schema: *ref_80
+ schema: *ref_110
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
responses:
'200':
description: list of app paths
@@ -9197,15 +13327,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_41
+ schema: *ref_61
- name: version
in: path
required: true
- schema: &ref_208
+ schema: &ref_267
type: integer
requestBody:
description: App deployment message
@@ -9234,11 +13364,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: app details
@@ -9246,8 +13376,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_76
- required: *ref_77
+ properties: *ref_106
+ required: *ref_107
/w/{workspace}/apps_u/public_resource/{path}:
get:
summary: get public resource
@@ -9258,11 +13388,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: resource value
@@ -9279,11 +13409,33 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
+ responses:
+ '200':
+ description: app secret
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/apps/secret_of_latest_version/{path}:
+ get:
+ summary: get public secret of latest version of an app bundle
+ operationId: getPublicSecretOfLatestVersionOfApp
+ tags:
+ - app
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_48
responses:
'200':
description: app secret
@@ -9301,11 +13453,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_41
+ schema: *ref_61
responses:
'200':
description: app details
@@ -9313,102 +13465,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_76
- required: *ref_77
- /w/{workspace}/raw_apps/create:
- post:
- summary: create raw app
- operationId: createRawApp
- tags:
- - raw_app
- parameters:
- - name: workspace
- in: path
- required: true
- schema: *ref_0
- requestBody:
- description: new raw app
- required: true
- content:
- application/json:
- schema:
- type: object
- properties:
- path:
- type: string
- value:
- type: string
- summary:
- type: string
- required:
- - path
- - value
- - summary
- responses:
- '201':
- description: raw app created
- content:
- text/plain:
- schema:
- type: string
- /w/{workspace}/raw_apps/update/{path}:
- post:
- summary: update app
- operationId: updateRawApp
- tags:
- - raw_app
- parameters:
- - name: workspace
- in: path
- required: true
- schema: *ref_0
- - name: path
- in: path
- required: true
- schema: *ref_48
- requestBody:
- description: updateraw app
- required: true
- content:
- application/json:
- schema:
- type: object
- properties:
- path:
- type: string
- summary:
- type: string
- value:
- type: string
- responses:
- '200':
- description: app updated
- content:
- text/plain:
- schema:
- type: string
- /w/{workspace}/raw_apps/delete/{path}:
- delete:
- summary: delete raw app
- operationId: deleteRawApp
- tags:
- - raw_app
- parameters:
- - name: workspace
- in: path
- required: true
- schema: *ref_0
- - name: path
- in: path
- required: true
- schema: *ref_31
- responses:
- '200':
- description: app deleted
- content:
- text/plain:
- schema:
- type: string
+ properties: *ref_106
+ required: *ref_107
/w/{workspace}/apps/delete/{path}:
delete:
summary: delete app
@@ -9419,11 +13477,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: app deleted
@@ -9435,17 +13493,27 @@ paths:
post:
summary: update app
operationId: updateApp
+ x-mcp-tool: true
+ x-mcp-tool-include-fields:
+ - path
+ - value
+ - summary
+ - policy
+ - deployment_message
+ x-mcp-tool-opaque-fields:
+ - value
+ - policy
tags:
- app
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
requestBody:
description: update app
required: true
@@ -9461,7 +13529,7 @@ paths:
value: {}
policy:
type: object
- properties: *ref_75
+ properties: *ref_105
deployment_message:
type: string
custom_path:
@@ -9483,11 +13551,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
requestBody:
description: update app
required: true
@@ -9506,7 +13574,7 @@ paths:
value: {}
policy:
type: object
- properties: *ref_75
+ properties: *ref_105
deployment_message:
type: string
custom_path:
@@ -9532,11 +13600,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: custom_path
in: path
required: true
- schema: *ref_81
+ schema: *ref_111
responses:
'200':
description: custom path exists
@@ -9554,7 +13622,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: s3 objects to sign
required: true
@@ -9567,7 +13635,7 @@ paths:
type: array
items:
type: object
- properties: &ref_82
+ properties: &ref_112
s3:
type: string
filename:
@@ -9576,7 +13644,7 @@ paths:
type: string
presigned:
type: string
- required: &ref_83
+ required: &ref_113
- s3
required:
- s3_objects
@@ -9589,8 +13657,8 @@ paths:
type: array
items:
type: object
- properties: *ref_82
- required: *ref_83
+ properties: *ref_112
+ required: *ref_113
/w/{workspace}/apps_u/execute_component/{path}:
post:
summary: executeComponent
@@ -9601,11 +13669,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
requestBody:
description: update app
required: true
@@ -9647,6 +13715,9 @@ paths:
type: array
items:
type: string
+ run_query_params:
+ type: object
+ description: Runnable query parameters
required:
- args
- component
@@ -9667,11 +13738,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: file_key
in: query
required: false
@@ -9737,7 +13808,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: delete_token
in: query
required: true
@@ -9754,17 +13825,22 @@ paths:
post:
summary: run flow by path
operationId: runFlowByPath
+ x-mcp-tool: true
+ x-mcp-instructions: >-
+ You should first use getFlowByPath to retrieve the flow's schema and
+ understand what arguments are expected.
+ x-mcp-tool-include-query-params: []
tags:
- job
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
- name: scheduled_for
description: when to schedule this job (leave empty for immediate run)
in: query
@@ -9779,18 +13855,17 @@ paths:
- name: skip_preprocessor
description: skip the preprocessor
in: query
- schema:
- type: boolean
+ schema: *ref_94
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: tag
description: Override the tag to use
in: query
- schema: *ref_62
+ schema: *ref_89
- name: job_id
description: >-
The job id to assign to the created job. if missing, job is chosen
@@ -9798,7 +13873,7 @@ paths:
queue or as a completed job, the request to create one will fail
(Bad Request)
in: query
- schema: *ref_61
+ schema: *ref_91
- name: include_header
description: >
List of headers's keys (separated with ',') whove value are added to
@@ -9807,12 +13882,18 @@ paths:
Header's key lowercased and '-'' replaced to '_' such that
'Content-Type' becomes the 'content_type' arg key
in: query
- schema: *ref_64
+ schema: *ref_92
- name: invisible_to_owner
description: make the run invisible to the the flow owner (default false)
in: query
schema:
type: boolean
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
requestBody:
description: flow args
required: true
@@ -9821,7 +13902,95 @@ paths:
schema:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
+ responses:
+ '201':
+ description: job created
+ content:
+ text/plain:
+ schema:
+ type: string
+ format: uuid
+ /w/{workspace}/jobs/run/fv/{version}:
+ post:
+ summary: run flow by version
+ operationId: runFlowByVersion
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: version
+ description: flow version ID
+ in: path
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: scheduled_for
+ description: when to schedule this job (leave empty for immediate run)
+ in: query
+ schema:
+ type: string
+ format: date-time
+ - name: scheduled_in_secs
+ description: schedule the script to execute in the number of seconds starting now
+ in: query
+ schema:
+ type: integer
+ - name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
+ - name: parent_job
+ description: >-
+ The parent job that is at the origin and responsible for the
+ execution of this script if any
+ in: query
+ schema: *ref_88
+ - name: tag
+ description: Override the tag to use
+ in: query
+ schema: *ref_89
+ - name: job_id
+ description: >-
+ The job id to assign to the created job. if missing, job is chosen
+ randomly using the ULID scheme. If a job id already exists in the
+ queue or as a completed job, the request to create one will fail
+ (Bad Request)
+ in: query
+ schema: *ref_91
+ - name: include_header
+ description: >
+ List of headers's keys (separated with ',') whove value are added to
+ the args
+
+ Header's key lowercased and '-'' replaced to '_' such that
+ 'Content-Type' becomes the 'content_type' arg key
+ in: query
+ schema: *ref_92
+ - name: invisible_to_owner
+ description: make the run invisible to the the flow owner (default false)
+ in: query
+ schema:
+ type: boolean
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: flow args
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
responses:
'201':
description: job created
@@ -9840,7 +14009,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: list of job ids to re run and arg tranforms
required: true
@@ -9865,18 +14034,41 @@ paths:
input_transforms:
type: object
additionalProperties:
- oneOf: &ref_88
+ description: >-
+ Maps input parameters for a step. Can be a static
+ value or a JavaScript expression that references
+ previous results or flow inputs
+ oneOf: &ref_116
- type: object
- properties: *ref_84
- required: *ref_85
+ description: >-
+ Static value passed directly to the step. Use
+ for hardcoded values or resource references like
+ '$res:path/to/resource'
+ properties: *ref_114
+ required: *ref_115
- type: object
- properties: *ref_86
- required: *ref_87
- discriminator: &ref_89
+ description: >-
+ JavaScript expression evaluated at runtime. Can
+ reference previous step results via
+ 'results.step_id' or flow inputs via
+ 'flow_input.property'. Inside loops, use
+ 'flow_input.iter.value' for the current
+ iteration value
+ properties: *ref_66
+ required: *ref_67
+ - type: object
+ description: >-
+ Value resolved by the AI runtime for this input.
+ The AI engine decides how to satisfy the
+ parameter.
+ properties: *ref_68
+ required: *ref_69
+ discriminator: &ref_117
propertyName: type
mapping:
static: '#/components/schemas/schemas-StaticTransform'
javascript: '#/components/schemas/schemas-JavascriptTransform'
+ ai: '#/components/schemas/schemas-AiTransform'
use_latest_version:
type: boolean
flow_options_by_path:
@@ -9887,8 +14079,12 @@ paths:
input_transforms:
type: object
additionalProperties:
- oneOf: *ref_88
- discriminator: *ref_89
+ description: >-
+ Maps input parameters for a step. Can be a static
+ value or a JavaScript expression that references
+ previous results or flow inputs
+ oneOf: *ref_116
+ discriminator: *ref_117
use_latest_version:
type: boolean
responses:
@@ -9900,7 +14096,7 @@ paths:
text/event-stream:
schema:
type: string
- /w/{workspace}/jobs/restart/f/{id}/from/{step_id}/{branch_or_iteration_n}:
+ /w/{workspace}/jobs/restart/f/{id}:
post:
summary: restart a completed flow at a given step
operationId: restartFlowAtStep
@@ -9910,27 +14106,13 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: &ref_123
+ schema: &ref_144
type: string
format: uuid
- - name: step_id
- description: step id to restart the flow from
- required: true
- in: path
- schema:
- type: string
- - name: branch_or_iteration_n
- description: >-
- for branchall or loop, the iteration at which the flow should
- restart
- required: true
- in: path
- schema:
- type: integer
- name: scheduled_for
description: when to schedule this job (leave empty for immediate run)
in: query
@@ -9947,11 +14129,11 @@ paths:
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: tag
description: Override the tag to use
in: query
- schema: *ref_62
+ schema: *ref_89
- name: job_id
description: >-
The job id to assign to the created job. if missing, job is chosen
@@ -9959,7 +14141,7 @@ paths:
queue or as a completed job, the request to create one will fail
(Bad Request)
in: query
- schema: *ref_61
+ schema: *ref_91
- name: include_header
description: >
List of headers's keys (separated with ',') whove value are added to
@@ -9968,21 +14150,35 @@ paths:
Header's key lowercased and '-'' replaced to '_' such that
'Content-Type' becomes the 'content_type' arg key
in: query
- schema: *ref_64
+ schema: *ref_92
- name: invisible_to_owner
description: make the run invisible to the the flow owner (default false)
in: query
schema:
type: boolean
requestBody:
- description: flow args
+ description: restart flow parameters
required: true
content:
application/json:
schema:
type: object
- description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ required:
+ - step_id
+ properties:
+ step_id:
+ type: string
+ description: step id to restart the flow from
+ branch_or_iteration_n:
+ type: integer
+ description: >-
+ for branchall or loop, the iteration at which the flow
+ should restart (optional)
+ flow_version:
+ type: integer
+ description: >-
+ specific flow version to use for restart (optional, uses
+ current version if not specified)
responses:
'201':
description: job created
@@ -10001,11 +14197,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: hash
in: path
required: true
- schema: *ref_53
+ schema: *ref_81
- name: scheduled_for
description: when to schedule this job (leave empty for immediate run)
in: query
@@ -10020,24 +14216,23 @@ paths:
- name: skip_preprocessor
description: skip the preprocessor
in: query
- schema:
- type: boolean
+ schema: *ref_94
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: tag
description: Override the tag to use
in: query
- schema: *ref_62
+ schema: *ref_89
- name: cache_ttl
description: >-
Override the cache time to live (in seconds). Can not be used to
disable caching, only override with a new cache ttl
in: query
- schema: *ref_63
+ schema: *ref_90
- name: job_id
description: >-
The job id to assign to the created job. if missing, job is chosen
@@ -10045,7 +14240,7 @@ paths:
queue or as a completed job, the request to create one will fail
(Bad Request)
in: query
- schema: *ref_61
+ schema: *ref_91
- name: include_header
description: >
List of headers's keys (separated with ',') whove value are added to
@@ -10054,7 +14249,7 @@ paths:
Header's key lowercased and '-'' replaced to '_' such that
'Content-Type' becomes the 'content_type' arg key
in: query
- schema: *ref_64
+ schema: *ref_92
- name: invisible_to_owner
description: make the run invisible to the the script owner (default false)
in: query
@@ -10085,7 +14280,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: include_header
description: >
List of headers's keys (separated with ',') whove value are added to
@@ -10094,7 +14289,7 @@ paths:
Header's key lowercased and '-'' replaced to '_' such that
'Content-Type' becomes the 'content_type' arg key
in: query
- schema: *ref_64
+ schema: *ref_92
- name: invisible_to_owner
description: make the run invisible to the the script owner (default false)
in: query
@@ -10107,7 +14302,7 @@ paths:
queue or as a completed job, the request to create one will fail
(Bad Request)
in: query
- schema: *ref_61
+ schema: *ref_91
requestBody:
description: preview
required: true
@@ -10115,20 +14310,23 @@ paths:
application/json:
schema:
type: object
- properties: &ref_262
+ properties: &ref_118
content:
type: string
+ description: The code to run
path:
type: string
+ description: The path to the script
script_hash:
type: string
+ description: The hash of the script
args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
language:
type: string
- enum: *ref_50
+ enum: *ref_76
tag:
type: string
kind:
@@ -10141,7 +14339,7 @@ paths:
type: boolean
lock:
type: string
- required: &ref_263
+ required: &ref_119
- args
responses:
'201':
@@ -10151,6 +14349,80 @@ paths:
schema:
type: string
format: uuid
+ /w/{workspace}/jobs/run_inline/preview:
+ post:
+ summary: run script preview without starting a new job
+ operationId: runScriptPreviewInline
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: preview
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: &ref_368
+ content:
+ type: string
+ description: The code to run
+ args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ language:
+ type: string
+ enum: *ref_76
+ required: &ref_369
+ - content
+ - args
+ - language
+ responses:
+ '200':
+ description: script result
+ content:
+ application/json:
+ schema: {}
+ /w/{workspace}/jobs/run_wait_result/preview:
+ post:
+ summary: run script preview and wait for result
+ operationId: runScriptPreviewAndWaitResult
+ x-mcp-tool: true
+ x-mcp-instructions: >-
+ Allows testing a script before deploying it. For typescript code, the
+ language to send is either bun or deno. By default, send bun if no deno
+ specific code is detected.
+ x-mcp-required-fields:
+ - content
+ - language
+ - args
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: preview
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_118
+ required: *ref_119
+ responses:
+ '200':
+ description: job result
+ content:
+ application/json:
+ schema: {}
/w/{workspace}/jobs/workflow_as_code/{job_id}/{entrypoint}:
post:
summary: run code-workflow task
@@ -10161,7 +14433,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: job_id
in: path
required: true
@@ -10179,12 +14451,12 @@ paths:
application/json:
schema:
type: object
- properties: &ref_264
+ properties: &ref_370
args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- required: &ref_265
+ additionalProperties: true
+ required: &ref_371
- args
responses:
'201':
@@ -10204,7 +14476,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: raw script content
required: true
@@ -10217,15 +14489,15 @@ paths:
type: array
items:
type: object
- properties: &ref_357
+ properties: &ref_475
raw_code:
type: string
path:
type: string
language:
type: string
- enum: *ref_50
- required: &ref_358
+ enum: *ref_76
+ required: &ref_476
- raw_code
- path
- language
@@ -10256,7 +14528,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: include_header
description: >
List of headers's keys (separated with ',') whove value are added to
@@ -10265,7 +14537,7 @@ paths:
Header's key lowercased and '-'' replaced to '_' such that
'Content-Type' becomes the 'content_type' arg key
in: query
- schema: *ref_64
+ schema: *ref_92
- name: invisible_to_owner
description: make the run invisible to the the script owner (default false)
in: query
@@ -10278,7 +14550,13 @@ paths:
queue or as a completed job, the request to create one will fail
(Bad Request)
in: query
- schema: *ref_61
+ schema: *ref_91
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
requestBody:
description: preview
required: true
@@ -10286,53 +14564,121 @@ paths:
application/json:
schema:
type: object
- properties: &ref_332
+ properties: &ref_122
value:
type: object
- properties: &ref_92
+ description: >-
+ The flow structure containing modules and optional
+ preprocessor/failure handlers
+ properties: &ref_126
modules:
type: array
+ description: >-
+ Array of steps that execute in sequence. Each step can
+ be a script, subflow, loop, or branch
items:
type: object
- properties: *ref_44
- required: *ref_45
+ description: >-
+ A single step in a flow. Can be a script, subflow,
+ loop, or branch
+ properties: *ref_64
+ required: *ref_65
failure_module:
+ description: >-
+ A single step in a flow. Can be a script, subflow, loop,
+ or branch
type: object
- properties: *ref_44
- required: *ref_45
+ properties: *ref_64
+ required: *ref_65
preprocessor_module:
+ description: >-
+ A single step in a flow. Can be a script, subflow, loop,
+ or branch
type: object
- properties: *ref_44
- required: *ref_45
+ properties: *ref_64
+ required: *ref_65
same_worker:
type: boolean
+ description: >-
+ If true, all steps run on the same worker for better
+ performance
concurrent_limit:
type: number
+ description: Maximum number of concurrent executions of this flow
concurrency_key:
type: string
+ description: >-
+ Expression to group concurrent executions (e.g., by user
+ ID)
concurrency_time_window_s:
type: number
+ description: Time window in seconds for concurrent_limit
+ debounce_delay_s:
+ type: number
+ description: Delay in seconds to debounce flow executions
+ debounce_key:
+ type: string
+ description: Expression to group debounced executions
+ debounce_args_to_accumulate:
+ type: array
+ description: Arguments to accumulate across debounced executions
+ items:
+ type: string
+ max_total_debouncing_time:
+ type: number
+ description: >-
+ Maximum total time in seconds that a job can be
+ debounced
+ max_total_debounces_amount:
+ type: number
+ description: Maximum number of times a job can be debounced
skip_expr:
type: string
+ description: >-
+ JavaScript expression to conditionally skip the entire
+ flow
cache_ttl:
type: number
+ description: Cache duration in seconds for flow results
+ cache_ignore_s3_path:
+ type: boolean
+ flow_env:
+ type: object
+ description: Environment variables available to all steps
+ additionalProperties:
+ type: string
priority:
type: number
+ description: Execution priority (higher numbers run first)
early_return:
type: string
- required: &ref_93
+ description: JavaScript expression to return early from the flow
+ chat_input_enabled:
+ type: boolean
+ description: Whether this flow accepts chat-style input
+ notes:
+ type: array
+ description: Sticky notes attached to the flow
+ items:
+ type: object
+ description: >-
+ A sticky note attached to a flow for documentation and
+ annotation
+ properties: *ref_120
+ required: *ref_121
+ required: &ref_127
- modules
path:
type: string
args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
tag:
type: string
restarted_from:
type: object
- properties: &ref_334
+ properties: &ref_451
flow_job_id:
type: string
format: uuid
@@ -10340,7 +14686,9 @@ paths:
type: string
branch_or_iteration_n:
type: integer
- required: &ref_333
+ flow_version:
+ type: integer
+ required: &ref_123
- value
- content
- args
@@ -10352,6 +14700,110 @@ paths:
schema:
type: string
format: uuid
+ /w/{workspace}/jobs/run_wait_result/preview_flow:
+ post:
+ summary: run flow preview and wait for result
+ operationId: runFlowPreviewAndWaitResult
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: memory_id
+ description: memory ID for chat-enabled flows
+ in: query
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: preview
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_122
+ required: *ref_123
+ responses:
+ '200':
+ description: job result
+ content:
+ application/json:
+ schema: {}
+ /w/{workspace}/jobs/run/dynamic_select:
+ post:
+ summary: run dynamic select helper function
+ operationId: runDynamicSelect
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: dynamic select request
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: &ref_463
+ entrypoint_function:
+ type: string
+ description: Name of the function to execute for dynamic select
+ args:
+ type: object
+ description: Arguments to pass to the function
+ runnable_ref:
+ type: object
+ oneOf:
+ - type: object
+ properties:
+ source:
+ type: string
+ enum:
+ - deployed
+ path:
+ type: string
+ description: Path to the deployed script or flow
+ runnable_kind:
+ type: string
+ enum: &ref_172
+ - script
+ - flow
+ required:
+ - source
+ - path
+ - runnable_kind
+ - type: object
+ properties:
+ source:
+ type: string
+ enum:
+ - inline
+ code:
+ type: string
+ description: Code content for inline execution
+ language:
+ type: string
+ enum: *ref_76
+ required:
+ - source
+ - code
+ required: &ref_464
+ - entrypoint_function
+ - runnable_ref
+ responses:
+ '201':
+ description: dynamic select job created
+ content:
+ text/plain:
+ schema:
+ type: string
+ format: uuid
/w/{workspace}/jobs/queue/list:
get:
summary: list all queued jobs
@@ -10363,117 +14815,141 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: order_desc
description: order by desc order (default true)
in: query
- schema: *ref_66
+ schema: *ref_96
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: worker
description: worker this job was ran on
in: query
- schema: &ref_94
+ schema: &ref_128
type: string
- name: script_path_exact
description: mask to filter exact matching path
in: query
- schema: &ref_95
+ schema: &ref_129
type: string
- name: script_path_start
description: mask to filter matching starting path
in: query
- schema: &ref_96
+ schema: &ref_130
type: string
- name: schedule_path
description: mask to filter by schedule path
in: query
- schema: &ref_97
+ schema: &ref_131
type: string
+ - name: trigger_path
+ description: mask to filter by trigger path
+ in: query
+ schema: &ref_268
+ type: string
+ - name: trigger_kind
+ description: trigger kind (schedule, http, websocket...)
+ in: query
+ schema: &ref_160
+ description: job trigger kind (schedule, http, websocket...)
+ type: string
+ enum: &ref_145
+ - webhook
+ - default_email
+ - email
+ - schedule
+ - http
+ - websocket
+ - postgres
+ - kafka
+ - nats
+ - mqtt
+ - sqs
+ - gcp
- name: script_hash
description: mask to filter exact matching path
in: query
- schema: &ref_98
+ schema: &ref_132
type: string
- name: started_before
description: filter on started before (inclusive) timestamp
in: query
- schema: &ref_99
+ schema: &ref_133
type: string
format: date-time
- name: started_after
description: filter on started after (exclusive) timestamp
in: query
- schema: &ref_100
+ schema: &ref_134
type: string
format: date-time
- name: success
description: filter on successful jobs
in: query
- schema: &ref_108
+ schema: &ref_142
type: boolean
- name: scheduled_for_before_now
description: filter on jobs scheduled_for before now (hence waitinf for a worker)
in: query
- schema: &ref_102
+ schema: &ref_136
type: boolean
- name: job_kinds
description: >-
filter on job kind (values 'preview', 'script', 'dependencies',
'flow') separated by,
in: query
- schema: &ref_103
+ schema: &ref_137
type: string
- name: suspended
description: filter on suspended jobs
in: query
- schema: &ref_104
+ schema: &ref_138
type: boolean
- name: running
description: filter on running jobs
in: query
- schema: &ref_101
+ schema: &ref_135
type: boolean
- name: args
description: >-
filter on jobs containing those args as a json subset (@> in
postgres)
in: query
- schema: &ref_105
+ schema: &ref_139
type: string
- name: result
description: >-
filter on jobs containing those result as a json subset (@> in
postgres)
in: query
- schema: &ref_107
+ schema: &ref_141
type: string
- name: allow_wildcards
description: allow wildcards (*) in the filter of label, tag, worker
in: query
- schema: &ref_109
+ schema: &ref_143
type: boolean
- name: tag
description: filter on jobs with a given tag/worker group
in: query
- schema: &ref_106
+ schema: &ref_140
type: string
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: all_workspaces
description: >-
get jobs from all workspaces (only valid if request come from the
@@ -10495,7 +14971,7 @@ paths:
type: array
items:
type: object
- properties: &ref_121
+ properties: &ref_163
workspace_id:
type: string
id:
@@ -10524,7 +15000,7 @@ paths:
args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
logs:
type: string
raw_code:
@@ -10551,10 +15027,14 @@ paths:
- script_hub
- identity
- deploymentcallback
- - singlescriptflow
+ - singlestepflow
- flowscript
- flownode
- appscript
+ - aiagent
+ - unassigned_script
+ - unassigned_flow
+ - unassigned_singlestepflow
schedule_path:
type: string
permissioned_as:
@@ -10566,14 +15046,14 @@ paths:
by extension its DT_TOKEN.
flow_status:
type: object
- properties: &ref_111
+ properties: &ref_147
step:
type: integer
modules:
type: array
items:
type: object
- properties: &ref_90
+ properties: &ref_124
type:
type: string
enum:
@@ -10600,6 +15080,8 @@ paths:
itered:
type: array
items: {}
+ itered_len:
+ type: integer
args: {}
flow_jobs:
type: array
@@ -10609,6 +15091,17 @@ paths:
type: array
items:
type: boolean
+ flow_jobs_duration:
+ type: object
+ properties:
+ started_at:
+ type: array
+ items:
+ type: string
+ duration_ms:
+ type: array
+ items:
+ type: integer
branch_chosen:
type: object
properties:
@@ -10650,20 +15143,84 @@ paths:
format: uuid
skipped:
type: boolean
- required: &ref_91
+ agent_actions:
+ type: array
+ items:
+ type: object
+ oneOf:
+ - type: object
+ properties:
+ job_id:
+ type: string
+ format: uuid
+ function_name:
+ type: string
+ type:
+ type: string
+ enum:
+ - tool_call
+ module_id:
+ type: string
+ required:
+ - job_id
+ - function_name
+ - type
+ - module_id
+ - type: object
+ properties:
+ call_id:
+ type: string
+ format: uuid
+ function_name:
+ type: string
+ resource_path:
+ type: string
+ type:
+ type: string
+ enum:
+ - mcp_tool_call
+ arguments:
+ type: object
+ required:
+ - call_id
+ - function_name
+ - resource_path
+ - type
+ - type: object
+ properties:
+ type:
+ type: string
+ enum:
+ - web_search
+ required:
+ - type
+ - type: object
+ properties:
+ type:
+ type: string
+ enum:
+ - message
+ required:
+ - content
+ - type
+ agent_actions_success:
+ type: array
+ items:
+ type: boolean
+ required: &ref_125
- type
user_states:
additionalProperties: true
preprocessor_module:
allOf:
- type: object
- properties: *ref_90
- required: *ref_91
+ properties: *ref_124
+ required: *ref_125
failure_module:
allOf:
- type: object
- properties: *ref_90
- required: *ref_91
+ properties: *ref_124
+ required: *ref_125
- type: object
properties:
parent_module:
@@ -10678,13 +15235,13 @@ paths:
items:
type: string
format: uuid
- required: &ref_112
+ required: &ref_148
- step
- modules
- failure_module
workflow_as_code_status:
type: object
- properties: &ref_113
+ properties: &ref_149
scheduled_for:
type: string
format: date-time
@@ -10697,13 +15254,16 @@ paths:
type: string
raw_flow:
type: object
- properties: *ref_92
- required: *ref_93
+ description: >-
+ The flow structure containing modules and optional
+ preprocessor/failure handlers
+ properties: *ref_126
+ required: *ref_127
is_flow_step:
type: boolean
language:
type: string
- enum: *ref_50
+ enum: *ref_76
email:
type: string
visible_to_owner:
@@ -10724,7 +15284,7 @@ paths:
type: boolean
worker:
type: string
- required: &ref_122
+ required: &ref_164
- id
- running
- canceled
@@ -10744,7 +15304,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: all_workspaces
description: >-
get jobs from all workspaces (only valid if request come from the
@@ -10776,7 +15336,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: completed count
@@ -10799,7 +15359,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: completed_after_s_ago
in: query
schema:
@@ -10833,132 +15393,131 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
- name: label
description: >-
mask to filter exact matching job's label (job labels are completed
jobs with as a result an object containing a string in the array at
key 'wm_labels')
in: query
- schema: &ref_110
+ schema: &ref_146
type: string
- name: worker
description: worker this job was ran on
in: query
- schema: *ref_94
+ schema: *ref_128
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: script_path_exact
description: mask to filter exact matching path
in: query
- schema: *ref_95
+ schema: *ref_129
- name: script_path_start
description: mask to filter matching starting path
in: query
- schema: *ref_96
+ schema: *ref_130
- name: schedule_path
description: mask to filter by schedule path
in: query
- schema: *ref_97
+ schema: *ref_131
- name: script_hash
description: mask to filter exact matching path
in: query
- schema: *ref_98
+ schema: *ref_132
- name: started_before
description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_99
+ schema: *ref_133
- name: started_after
description: filter on started after (exclusive) timestamp
in: query
- schema: *ref_100
+ schema: *ref_134
- name: created_before
description: filter on created before (inclusive) timestamp
in: query
- schema: &ref_114
+ schema: &ref_154
type: string
format: date-time
- name: created_after
description: filter on created after (exclusive) timestamp
in: query
- schema: &ref_115
+ schema: &ref_155
type: string
format: date-time
- - name: created_or_started_before
- description: >-
- filter on created_at for non non started job and started_at
- otherwise before (inclusive) timestamp
+ - name: completed_before
+ description: filter on started before (inclusive) timestamp
in: query
- schema: &ref_116
+ schema: &ref_156
+ type: string
+ format: date-time
+ - name: completed_after
+ description: filter on started after (exclusive) timestamp
+ in: query
+ schema: &ref_157
+ type: string
+ format: date-time
+ - name: created_before_queue
+ description: filter on jobs created before X for jobs in the queue only
+ in: query
+ schema: &ref_158
+ type: string
+ format: date-time
+ - name: created_after_queue
+ description: filter on jobs created after X for jobs in the queue only
+ in: query
+ schema: &ref_159
type: string
format: date-time
- name: running
description: filter on running jobs
in: query
- schema: *ref_101
+ schema: *ref_135
- name: scheduled_for_before_now
description: filter on jobs scheduled_for before now (hence waitinf for a worker)
in: query
- schema: *ref_102
- - name: created_or_started_after
- description: >-
- filter on created_at for non non started job and started_at
- otherwise after (exclusive) timestamp
- in: query
- schema: &ref_117
- type: string
- format: date-time
- - name: created_or_started_after_completed_jobs
- description: >-
- filter on created_at for non non started job and started_at
- otherwise after (exclusive) timestamp but only for the completed
- jobs
- in: query
- schema: &ref_118
- type: string
- format: date-time
+ schema: *ref_136
- name: job_kinds
description: >-
filter on job kind (values 'preview', 'script', 'dependencies',
'flow') separated by,
in: query
- schema: *ref_103
+ schema: *ref_137
- name: suspended
description: filter on suspended jobs
in: query
- schema: *ref_104
+ schema: *ref_138
- name: args
description: >-
filter on jobs containing those args as a json subset (@> in
postgres)
in: query
- schema: *ref_105
+ schema: *ref_139
- name: tag
description: filter on jobs with a given tag/worker group
in: query
- schema: *ref_106
+ schema: *ref_140
- name: result
description: >-
filter on jobs containing those result as a json subset (@> in
postgres)
in: query
- schema: *ref_107
+ schema: *ref_141
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: is_skipped
description: is the job skipped
in: query
@@ -11010,95 +15569,95 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: order_desc
description: order by desc order (default true)
in: query
- schema: *ref_66
+ schema: *ref_96
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: script_path_exact
description: mask to filter exact matching path
in: query
- schema: *ref_95
+ schema: *ref_129
- name: script_path_start
description: mask to filter matching starting path
in: query
- schema: *ref_96
+ schema: *ref_130
- name: schedule_path
description: mask to filter by schedule path
in: query
- schema: *ref_97
+ schema: *ref_131
- name: script_hash
description: mask to filter exact matching path
in: query
- schema: *ref_98
+ schema: *ref_132
- name: started_before
description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_99
+ schema: *ref_133
- name: started_after
description: filter on started after (exclusive) timestamp
in: query
- schema: *ref_100
+ schema: *ref_134
- name: success
description: filter on successful jobs
in: query
- schema: *ref_108
+ schema: *ref_142
- name: scheduled_for_before_now
description: filter on jobs scheduled_for before now (hence waitinf for a worker)
in: query
- schema: *ref_102
+ schema: *ref_136
- name: job_kinds
description: >-
filter on job kind (values 'preview', 'script', 'dependencies',
'flow') separated by,
in: query
- schema: *ref_103
+ schema: *ref_137
- name: suspended
description: filter on suspended jobs
in: query
- schema: *ref_104
+ schema: *ref_138
- name: running
description: filter on running jobs
in: query
- schema: *ref_101
+ schema: *ref_135
- name: args
description: >-
filter on jobs containing those args as a json subset (@> in
postgres)
in: query
- schema: *ref_105
+ schema: *ref_139
- name: result
description: >-
filter on jobs containing those result as a json subset (@> in
postgres)
in: query
- schema: *ref_107
+ schema: *ref_141
- name: allow_wildcards
description: allow wildcards (*) in the filter of label, tag, worker
in: query
- schema: *ref_109
+ schema: *ref_143
- name: tag
description: filter on jobs with a given tag/worker group
in: query
- schema: *ref_106
+ schema: *ref_140
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: concurrency_key
in: query
required: false
@@ -11135,7 +15694,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
+ - name: force_cancel
+ in: query
+ schema:
+ type: boolean
requestBody:
description: uuids of the jobs to cancel
required: true
@@ -11154,6 +15717,132 @@ paths:
type: array
items:
type: string
+ /w/{workspace}/jobs/get_otel_traces/{id}:
+ get:
+ summary: get OpenTelemetry traces for a job
+ operationId: getJobOtelTraces
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: id
+ in: path
+ required: true
+ schema: *ref_144
+ responses:
+ '200':
+ description: list of OTEL Span objects (compatible with OpenTelemetry Span proto)
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ /w/{workspace}/trigger/{trigger_kind}/resume_suspended_trigger_jobs/{trigger_path}:
+ post:
+ summary: resume all suspended jobs for a specific trigger
+ operationId: resumeSuspendedTriggerJobs
+ tags:
+ - trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: trigger_kind
+ description: The kind of trigger
+ in: path
+ required: true
+ schema:
+ description: job trigger kind (schedule, http, websocket...)
+ type: string
+ enum: *ref_145
+ - name: trigger_path
+ description: The path of the trigger (can contain forward slashes)
+ in: path
+ required: true
+ schema:
+ type: string
+ style: simple
+ explode: false
+ requestBody:
+ description: Optional list of job IDs to reassign
+ required: false
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ job_ids:
+ type: array
+ items:
+ type: string
+ format: uuid
+ description: >-
+ Optional list of specific job UUIDs to reassign. If not
+ provided, all suspended jobs for the trigger will be
+ reassigned.
+ responses:
+ '200':
+ description: confirmation message
+ content:
+ application/json:
+ schema:
+ type: string
+ /w/{workspace}/trigger/{trigger_kind}/cancel_suspended_trigger_jobs/{trigger_path}:
+ post:
+ summary: cancel all suspended jobs for a specific trigger
+ operationId: cancelSuspendedTriggerJobs
+ tags:
+ - trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: trigger_kind
+ description: The kind of trigger
+ in: path
+ required: true
+ schema:
+ description: job trigger kind (schedule, http, websocket...)
+ type: string
+ enum: *ref_145
+ - name: trigger_path
+ description: The path of the trigger (can contain forward slashes)
+ in: path
+ required: true
+ schema:
+ type: string
+ style: simple
+ explode: false
+ requestBody:
+ description: Optional list of job IDs to cancel
+ required: false
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ job_ids:
+ type: array
+ items:
+ type: string
+ format: uuid
+ description: >-
+ Optional list of specific job UUIDs to cancel. If not
+ provided, all suspended jobs for the trigger will be
+ canceled.
+ responses:
+ '200':
+ description: confirmation message
+ content:
+ application/json:
+ schema:
+ type: string
/w/{workspace}/jobs/completed/list:
get:
summary: list all completed jobs
@@ -11164,94 +15853,94 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: order_desc
description: order by desc order (default true)
in: query
- schema: *ref_66
+ schema: *ref_96
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
- name: label
description: >-
mask to filter exact matching job's label (job labels are completed
jobs with as a result an object containing a string in the array at
key 'wm_labels')
in: query
- schema: *ref_110
+ schema: *ref_146
- name: worker
description: worker this job was ran on
in: query
- schema: *ref_94
+ schema: *ref_128
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: script_path_exact
description: mask to filter exact matching path
in: query
- schema: *ref_95
+ schema: *ref_129
- name: script_path_start
description: mask to filter matching starting path
in: query
- schema: *ref_96
+ schema: *ref_130
- name: schedule_path
description: mask to filter by schedule path
in: query
- schema: *ref_97
+ schema: *ref_131
- name: script_hash
description: mask to filter exact matching path
in: query
- schema: *ref_98
+ schema: *ref_132
- name: started_before
description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_99
+ schema: *ref_133
- name: started_after
description: filter on started after (exclusive) timestamp
in: query
- schema: *ref_100
+ schema: *ref_134
- name: success
description: filter on successful jobs
in: query
- schema: *ref_108
+ schema: *ref_142
- name: job_kinds
description: >-
filter on job kind (values 'preview', 'script', 'dependencies',
'flow') separated by,
in: query
- schema: *ref_103
+ schema: *ref_137
- name: args
description: >-
filter on jobs containing those args as a json subset (@> in
postgres)
in: query
- schema: *ref_105
+ schema: *ref_139
- name: result
description: >-
filter on jobs containing those result as a json subset (@> in
postgres)
in: query
- schema: *ref_107
+ schema: *ref_141
- name: allow_wildcards
description: allow wildcards (*) in the filter of label, tag, worker
in: query
- schema: *ref_109
+ schema: *ref_143
- name: tag
description: filter on jobs with a given tag/worker group
in: query
- schema: *ref_106
+ schema: *ref_140
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: is_skipped
description: is the job skipped
in: query
@@ -11281,7 +15970,7 @@ paths:
type: array
items:
type: object
- properties: &ref_119
+ properties: &ref_161
workspace_id:
type: string
id:
@@ -11298,6 +15987,9 @@ paths:
started_at:
type: string
format: date-time
+ completed_at:
+ type: string
+ format: date-time
duration_ms:
type: integer
success:
@@ -11309,7 +16001,7 @@ paths:
args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
result: {}
logs:
type: string
@@ -11336,10 +16028,14 @@ paths:
- script_hub
- identity
- deploymentcallback
- - singlescriptflow
+ - singlestepflow
- flowscript
- flownode
- appscript
+ - aiagent
+ - unassigned_script
+ - unassigned_flow
+ - unassigned_singlestepflow
schedule_path:
type: string
permissioned_as:
@@ -11351,20 +16047,23 @@ paths:
by extension its DT_TOKEN.
flow_status:
type: object
- properties: *ref_111
- required: *ref_112
+ properties: *ref_147
+ required: *ref_148
workflow_as_code_status:
type: object
- properties: *ref_113
+ properties: *ref_149
raw_flow:
type: object
- properties: *ref_92
- required: *ref_93
+ description: >-
+ The flow structure containing modules and optional
+ preprocessor/failure handlers
+ properties: *ref_126
+ required: *ref_127
is_flow_step:
type: boolean
language:
type: string
- enum: *ref_50
+ enum: *ref_76
is_skipped:
type: boolean
email:
@@ -11389,7 +16088,7 @@ paths:
type: boolean
worker:
type: string
- required: &ref_120
+ required: &ref_162
- id
- created_by
- duration_ms
@@ -11404,6 +16103,436 @@ paths:
- email
- visible_to_owner
- tag
+ /w/{workspace}/jobs/completed/export:
+ get:
+ summary: export all completed jobs for backup/migration
+ operationId: exportCompletedJobs
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: page
+ description: which page to return (start at 1, default 1)
+ in: query
+ schema: *ref_13
+ - name: per_page
+ description: number of items to return for a given page (default 30, max 100)
+ in: query
+ schema: *ref_14
+ responses:
+ '200':
+ description: All completed jobs exported
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ description: Completed job with full data for export/import operations
+ properties: &ref_150
+ id:
+ type: string
+ format: uuid
+ parent_job:
+ type: string
+ format: uuid
+ created_by:
+ type: string
+ created_at:
+ type: string
+ format: date-time
+ started_at:
+ type: string
+ format: date-time
+ completed_at:
+ type: string
+ format: date-time
+ duration_ms:
+ type: integer
+ script_path:
+ type: string
+ script_hash:
+ type: string
+ args:
+ type: object
+ description: Full job arguments without size restrictions
+ result:
+ type: object
+ description: Full job result without size restrictions
+ logs:
+ type: string
+ description: Complete job logs from v2_job table
+ raw_code:
+ type: string
+ raw_lock:
+ type: string
+ canceled_by:
+ type: string
+ canceled_reason:
+ type: string
+ job_kind:
+ type: string
+ enum:
+ - script
+ - preview
+ - dependencies
+ - flow
+ - flowdependencies
+ - appdependencies
+ - flowpreview
+ - script_hub
+ - identity
+ - deploymentcallback
+ - singlestepflow
+ - flowscript
+ - flownode
+ - appscript
+ - aiagent
+ - unassigned_script
+ - unassigned_flow
+ - unassigned_singlestepflow
+ trigger:
+ type: string
+ description: Trigger path for the job (replaces schedule_path)
+ trigger_kind:
+ type: string
+ enum:
+ - webhook
+ - http
+ - websocket
+ - kafka
+ - email
+ - nats
+ - schedule
+ - app
+ - ui
+ - postgres
+ - sqs
+ - gcp
+ permissioned_as:
+ type: string
+ permissioned_as_email:
+ type: string
+ flow_status:
+ type: object
+ description: Flow status from v2_job_status table
+ workflow_as_code_status:
+ type: object
+ raw_flow:
+ type: object
+ is_flow_step:
+ type: boolean
+ language:
+ type: string
+ enum: *ref_76
+ is_skipped:
+ type: boolean
+ email:
+ type: string
+ visible_to_owner:
+ type: boolean
+ mem_peak:
+ type: integer
+ tag:
+ type: string
+ priority:
+ type: integer
+ labels:
+ type: array
+ items:
+ type: string
+ same_worker:
+ type: boolean
+ flow_step_id:
+ type: string
+ flow_innermost_root_job:
+ type: string
+ format: uuid
+ concurrent_limit:
+ type: integer
+ concurrency_time_window_s:
+ type: integer
+ timeout:
+ type: integer
+ cache_ttl:
+ type: integer
+ self_wait_time_ms:
+ type: integer
+ aggregate_wait_time_ms:
+ type: integer
+ preprocessed:
+ type: boolean
+ worker:
+ type: string
+ status:
+ type: string
+ description: Actual job status from database
+ required: &ref_151
+ - id
+ - created_by
+ - created_at
+ - job_kind
+ - permissioned_as
+ - email
+ - visible_to_owner
+ /w/{workspace}/jobs/completed/import:
+ post:
+ summary: import completed jobs from backup/migration
+ operationId: importCompletedJobs
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ description: Completed job with full data for export/import operations
+ properties: *ref_150
+ required: *ref_151
+ responses:
+ '200':
+ description: Successfully imported completed jobs
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/jobs/queue/export:
+ get:
+ summary: export all queued jobs for backup/migration
+ operationId: exportQueuedJobs
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: page
+ description: which page to return (start at 1, default 1)
+ in: query
+ schema: *ref_13
+ - name: per_page
+ description: number of items to return for a given page (default 30, max 100)
+ in: query
+ schema: *ref_14
+ responses:
+ '200':
+ description: All queued jobs exported
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ description: Queued job with full data for export/import operations
+ properties: &ref_152
+ id:
+ type: string
+ format: uuid
+ parent_job:
+ type: string
+ format: uuid
+ created_by:
+ type: string
+ created_at:
+ type: string
+ format: date-time
+ started_at:
+ type: string
+ format: date-time
+ scheduled_for:
+ type: string
+ format: date-time
+ script_path:
+ type: string
+ script_hash:
+ type: string
+ args:
+ type: object
+ description: Full job arguments without size restrictions
+ logs:
+ type: string
+ description: Complete job logs from v2_job table
+ raw_code:
+ type: string
+ raw_lock:
+ type: string
+ canceled_by:
+ type: string
+ canceled_reason:
+ type: string
+ job_kind:
+ type: string
+ enum:
+ - script
+ - preview
+ - dependencies
+ - flowdependencies
+ - appdependencies
+ - flow
+ - flowpreview
+ - script_hub
+ - identity
+ - deploymentcallback
+ - singlestepflow
+ - flowscript
+ - flownode
+ - appscript
+ - aiagent
+ - unassigned_script
+ - unassigned_flow
+ - unassigned_singlestepflow
+ trigger:
+ type: string
+ description: Trigger path for the job (replaces schedule_path)
+ trigger_kind:
+ type: string
+ enum:
+ - webhook
+ - http
+ - websocket
+ - kafka
+ - email
+ - nats
+ - schedule
+ - app
+ - ui
+ - postgres
+ - sqs
+ - gcp
+ permissioned_as:
+ type: string
+ permissioned_as_email:
+ type: string
+ flow_status:
+ type: object
+ description: Flow status from v2_job_status table
+ workflow_as_code_status:
+ type: object
+ raw_flow:
+ type: object
+ is_flow_step:
+ type: boolean
+ language:
+ type: string
+ enum: *ref_76
+ email:
+ type: string
+ visible_to_owner:
+ type: boolean
+ mem_peak:
+ type: integer
+ tag:
+ type: string
+ priority:
+ type: integer
+ labels:
+ type: array
+ items:
+ type: string
+ same_worker:
+ type: boolean
+ flow_step_id:
+ type: string
+ flow_innermost_root_job:
+ type: string
+ format: uuid
+ concurrent_limit:
+ type: integer
+ concurrency_time_window_s:
+ type: integer
+ timeout:
+ type: integer
+ cache_ttl:
+ type: integer
+ self_wait_time_ms:
+ type: integer
+ aggregate_wait_time_ms:
+ type: integer
+ preprocessed:
+ type: boolean
+ suspend:
+ type: integer
+ suspend_until:
+ type: string
+ format: date-time
+ required: &ref_153
+ - id
+ - created_by
+ - created_at
+ - job_kind
+ - permissioned_as
+ - email
+ - visible_to_owner
+ /w/{workspace}/jobs/queue/import:
+ post:
+ summary: import queued jobs from backup/migration
+ operationId: importQueuedJobs
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ description: Queued job with full data for export/import operations
+ properties: *ref_152
+ required: *ref_153
+ responses:
+ '200':
+ description: Successfully imported queued jobs
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/jobs/delete:
+ post:
+ summary: delete jobs by IDs from all related tables
+ operationId: deleteJobs
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
+ format: uuid
+ description: Array of job IDs to delete
+ responses:
+ '200':
+ description: Successfully deleted jobs
+ content:
+ text/plain:
+ schema:
+ type: string
+ description: Summary of deleted jobs and rows
/w/{workspace}/jobs/list:
get:
summary: list all jobs
@@ -11415,125 +16544,122 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
- name: label
description: >-
mask to filter exact matching job's label (job labels are completed
jobs with as a result an object containing a string in the array at
key 'wm_labels')
in: query
- schema: *ref_110
+ schema: *ref_146
- name: worker
description: worker this job was ran on
in: query
- schema: *ref_94
+ schema: *ref_128
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: script_path_exact
description: mask to filter exact matching path
in: query
- schema: *ref_95
+ schema: *ref_129
- name: script_path_start
description: mask to filter matching starting path
in: query
- schema: *ref_96
+ schema: *ref_130
- name: schedule_path
description: mask to filter by schedule path
in: query
- schema: *ref_97
+ schema: *ref_131
- name: script_hash
description: mask to filter exact matching path
in: query
- schema: *ref_98
+ schema: *ref_132
- name: started_before
description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_99
+ schema: *ref_133
- name: started_after
description: filter on started after (exclusive) timestamp
in: query
- schema: *ref_100
+ schema: *ref_134
- name: created_before
description: filter on created before (inclusive) timestamp
in: query
- schema: *ref_114
+ schema: *ref_154
- name: created_after
description: filter on created after (exclusive) timestamp
in: query
- schema: *ref_115
- - name: created_or_started_before
- description: >-
- filter on created_at for non non started job and started_at
- otherwise before (inclusive) timestamp
+ schema: *ref_155
+ - name: completed_before
+ description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_116
+ schema: *ref_156
+ - name: completed_after
+ description: filter on started after (exclusive) timestamp
+ in: query
+ schema: *ref_157
+ - name: created_before_queue
+ description: filter on jobs created before X for jobs in the queue only
+ in: query
+ schema: *ref_158
+ - name: created_after_queue
+ description: filter on jobs created after X for jobs in the queue only
+ in: query
+ schema: *ref_159
- name: running
description: filter on running jobs
in: query
- schema: *ref_101
+ schema: *ref_135
- name: scheduled_for_before_now
description: filter on jobs scheduled_for before now (hence waitinf for a worker)
in: query
- schema: *ref_102
- - name: created_or_started_after
- description: >-
- filter on created_at for non non started job and started_at
- otherwise after (exclusive) timestamp
- in: query
- schema: *ref_117
- - name: created_or_started_after_completed_jobs
- description: >-
- filter on created_at for non non started job and started_at
- otherwise after (exclusive) timestamp but only for the completed
- jobs
- in: query
- schema: *ref_118
+ schema: *ref_136
- name: job_kinds
description: >-
filter on job kind (values 'preview', 'script', 'dependencies',
'flow') separated by,
in: query
- schema: *ref_103
+ schema: *ref_137
- name: suspended
description: filter on suspended jobs
in: query
- schema: *ref_104
+ schema: *ref_138
- name: args
description: >-
filter on jobs containing those args as a json subset (@> in
postgres)
in: query
- schema: *ref_105
+ schema: *ref_139
- name: tag
description: filter on jobs with a given tag/worker group
in: query
- schema: *ref_106
+ schema: *ref_140
- name: result
description: >-
filter on jobs containing those result as a json subset (@> in
postgres)
in: query
- schema: *ref_107
+ schema: *ref_141
- name: allow_wildcards
description: allow wildcards (*) in the filter of label, tag, worker
in: query
- schema: *ref_109
- - name: page
- description: which page to return (start at 1, default 1)
- in: query
- schema: *ref_5
+ schema: *ref_143
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
+ - name: trigger_kind
+ description: trigger kind (schedule, http, websocket...)
+ in: query
+ schema: *ref_160
- name: is_skipped
description: is the job skipped
in: query
@@ -11574,11 +16700,11 @@ paths:
schema:
type: array
items:
- oneOf: &ref_124
+ oneOf: &ref_165
- allOf:
- type: object
- properties: *ref_119
- required: *ref_120
+ properties: *ref_161
+ required: *ref_162
- type: object
properties:
type:
@@ -11587,15 +16713,15 @@ paths:
- CompletedJob
- allOf:
- type: object
- properties: *ref_121
- required: *ref_122
+ properties: *ref_163
+ required: *ref_164
- type: object
properties:
type:
type: string
enum:
- QueuedJob
- discriminator: &ref_125
+ discriminator: &ref_166
propertyName: type
/jobs/db_clock:
get:
@@ -11658,11 +16784,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: no_logs
in: query
schema:
@@ -11677,8 +16803,8 @@ paths:
content:
application/json:
schema:
- oneOf: *ref_124
- discriminator: *ref_125
+ oneOf: *ref_165
+ discriminator: *ref_166
/w/{workspace}/jobs_u/get_root_job_id/{id}:
get:
summary: get root job id
@@ -11689,11 +16815,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
responses:
'200':
description: get root job id
@@ -11711,11 +16837,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
+ - name: remove_ansi_warnings
+ in: query
+ schema:
+ type: boolean
responses:
'200':
description: job details
@@ -11723,6 +16853,28 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/jobs_u/get_completed_logs_tail/{id}:
+ get:
+ summary: get completed job logs tail
+ operationId: getCompletedJobLogsTail
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: id
+ in: path
+ required: true
+ schema: *ref_144
+ responses:
+ '200':
+ description: completed job logs tail
+ content:
+ text/plain:
+ schema:
+ type: string
/w/{workspace}/jobs_u/get_args/{id}:
get:
summary: get job args
@@ -11733,17 +16885,47 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
responses:
'200':
description: job args
content:
application/json:
schema: {}
+ /w/{workspace}/jobs_u/queue/get_started_at_by_ids:
+ post:
+ summary: get started at by ids
+ operationId: getStartedAtByIds
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: ids
+ required: true
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ '200':
+ description: started at by ids
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
+ format: date-time
/w/{workspace}/jobs_u/getupdate/{id}:
get:
summary: get job updates
@@ -11754,11 +16936,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: running
in: query
schema:
@@ -11805,11 +16987,11 @@ paths:
type: string
flow_status:
type: object
- properties: *ref_111
- required: *ref_112
+ properties: *ref_147
+ required: *ref_148
workflow_as_code_status:
type: object
- properties: *ref_113
+ properties: *ref_149
/w/{workspace}/jobs_u/getupdate_sse/{id}:
get:
summary: get job updates via server-sent events
@@ -11820,11 +17002,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: running
in: query
schema:
@@ -11866,7 +17048,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
@@ -11889,11 +17071,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
responses:
'200':
description: flow debug info details
@@ -11910,11 +17092,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
responses:
'200':
description: job details
@@ -11922,8 +17104,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_119
- required: *ref_120
+ properties: *ref_161
+ required: *ref_162
/w/{workspace}/jobs_u/completed/get_result/{id}:
get:
summary: get completed job result
@@ -11934,11 +17116,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: suspended_job
in: query
schema:
@@ -11971,14 +17153,14 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: get_started
in: query
- schema: &ref_214
+ schema: &ref_274
type: boolean
responses:
'200':
@@ -11998,6 +17180,39 @@ paths:
required:
- completed
- result
+ /w/{workspace}/jobs_u/completed/get_timing/{id}:
+ get:
+ summary: get completed job timing
+ operationId: getCompletedJobTiming
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: id
+ in: path
+ required: true
+ schema: *ref_144
+ responses:
+ '200':
+ description: job timing details
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ created_at:
+ type: string
+ format: date-time
+ started_at:
+ type: string
+ format: date-time
+ duration_ms:
+ type: integer
+ required:
+ - created_at
/w/{workspace}/jobs/completed/delete/{id}:
post:
summary: delete completed job (erase content but keep run id)
@@ -12008,11 +17223,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
responses:
'200':
description: job details
@@ -12020,8 +17235,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_119
- required: *ref_120
+ properties: *ref_161
+ required: *ref_162
/w/{workspace}/jobs_u/queue/cancel/{id}:
post:
summary: cancel queued or running job
@@ -12032,11 +17247,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
requestBody:
description: reason
required: true
@@ -12064,11 +17279,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: reason
required: true
@@ -12096,11 +17311,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
requestBody:
description: reason
required: true
@@ -12118,6 +17333,58 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/jobs/queue/position/{scheduled_for}:
+ get:
+ summary: get queue position for a job
+ operationId: getQueuePosition
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: scheduled_for
+ in: path
+ required: true
+ schema:
+ type: integer
+ description: The scheduled for timestamp in milliseconds
+ responses:
+ '200':
+ description: queue position information
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ position:
+ type: integer
+ description: >-
+ The position in queue (1-based), null if not in queue or
+ already running
+ /w/{workspace}/jobs/queue/scheduled_for/{id}:
+ get:
+ summary: get scheduled for timestamp for a job
+ operationId: getScheduledFor
+ tags:
+ - job
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: id
+ in: path
+ required: true
+ schema: *ref_144
+ responses:
+ '200':
+ description: scheduled for timestamp
+ content:
+ application/json:
+ schema:
+ type: integer
/w/{workspace}/jobs/job_signature/{id}/{resume_id}:
get:
summary: create an HMac signature given a job id and a resume id
@@ -12128,11 +17395,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: resume_id
in: path
required: true
@@ -12159,11 +17426,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: resume_id
in: path
required: true
@@ -12173,6 +17440,14 @@ paths:
in: query
schema:
type: string
+ - name: flow_level
+ in: query
+ description: >-
+ If true, generate resume URLs for the parent flow instead of the
+ specific step. This allows pre-approvals that can be consumed by any
+ later suspend step in the same flow.
+ schema:
+ type: boolean
responses:
'200':
description: url endpoints
@@ -12201,11 +17476,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: approver
in: query
schema:
@@ -12252,11 +17527,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: approver
in: query
schema:
@@ -12303,11 +17578,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: payload
description: >
The base64 encoded payload that has been encoded as a JSON. e.g how
@@ -12315,7 +17590,7 @@ paths:
`encodeURIComponent(btoa(JSON.stringify({a: 2})))`
in: query
- schema: *ref_126
+ schema: *ref_95
- name: resume_id
in: path
required: true
@@ -12346,11 +17621,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: resume_id
in: path
required: true
@@ -12388,11 +17663,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: key
in: path
required: true
@@ -12420,11 +17695,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: key
in: path
required: true
@@ -12446,11 +17721,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
requestBody:
required: true
content:
@@ -12474,11 +17749,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: resume_id
in: path
required: true
@@ -12509,11 +17784,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: resume_id
in: path
required: true
@@ -12551,11 +17826,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
- name: resume_id
in: path
required: true
@@ -12579,8 +17854,8 @@ paths:
type: object
properties:
job:
- oneOf: *ref_124
- discriminator: *ref_125
+ oneOf: *ref_165
+ discriminator: *ref_166
approvers:
type: array
items:
@@ -12647,7 +17922,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new schedule
required: true
@@ -12655,110 +17930,155 @@ paths:
application/json:
schema:
type: object
- properties: &ref_275
+ properties: &ref_381
path:
type: string
- description: The path where the schedule will be created
+ description: The unique path identifier for this schedule
schedule:
type: string
description: >-
- The cron schedule to trigger the script or flow. Should
- include seconds.
+ Cron expression with 6 fields (seconds, minutes, hours, day
+ of month, month, day of week). Example '0 0 12 * * *' for
+ daily at noon
timezone:
type: string
- description: The timezone to use for the cron schedule
+ description: >-
+ IANA timezone for the schedule (e.g., 'UTC', 'Europe/Paris',
+ 'America/New_York')
script_path:
type: string
- description: The path to the script or flow to trigger
+ description: Path to the script or flow to execute when triggered
is_flow:
type: boolean
- description: Whether the schedule is for a flow
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
args:
- description: The arguments to pass to the script or flow
type: object
- additionalProperties: *ref_22
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
enabled:
type: boolean
- description: Whether the schedule is enabled
+ description: >-
+ Whether the schedule is currently active and will trigger
+ jobs
on_failure:
type: string
- description: The path to the script or flow to trigger on failure
+ description: Path to a script or flow to run when the scheduled job fails
on_failure_times:
type: number
- description: The number of times to retry on failure
+ description: >-
+ Number of consecutive failures before the on_failure handler
+ is triggered (default 1)
on_failure_exact:
type: boolean
- description: Whether the schedule should only run on the exact time
+ description: >-
+ If true, trigger on_failure handler only on exactly N
+ failures, not on every failure after N
on_failure_extra_args:
- description: The arguments to pass to the script or flow
type: object
- additionalProperties: *ref_22
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
on_recovery:
type: string
- description: The path to the script or flow to trigger on recovery
+ description: >-
+ Path to a script or flow to run when the schedule recovers
+ after failures
on_recovery_times:
type: number
- description: The number of times to retry on recovery
+ description: >-
+ Number of consecutive successes before the on_recovery
+ handler is triggered (default 1)
on_recovery_extra_args:
- description: The arguments to pass to the script or flow
type: object
- additionalProperties: *ref_22
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
on_success:
type: string
- description: The path to the script or flow to trigger on success
+ description: >-
+ Path to a script or flow to run after each successful
+ execution
on_success_extra_args:
- description: The arguments to pass to the script or flow
type: object
- additionalProperties: *ref_22
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
ws_error_handler_muted:
type: boolean
- description: Whether the WebSocket error handler is muted
+ description: >-
+ If true, the workspace-level error handler will not be
+ triggered for this schedule's failures
retry:
- description: The retry configuration for the schedule
type: object
- properties: &ref_127
+ description: Retry configuration for failed module executions
+ properties: &ref_169
constant:
type: object
+ description: Retry with constant delay between attempts
properties:
attempts:
type: integer
+ description: Number of retry attempts
seconds:
type: integer
+ description: Seconds to wait between retries
exponential:
type: object
+ description: Retry with exponential backoff (delay doubles each time)
properties:
attempts:
type: integer
+ description: Number of retry attempts
multiplier:
type: integer
+ description: Multiplier for exponential backoff
seconds:
type: integer
+ minimum: 1
+ description: Initial delay in seconds
random_factor:
type: integer
minimum: 0
maximum: 100
+ description: >-
+ Random jitter percentage (0-100) to avoid thundering
+ herd
+ retry_if:
+ type: object
+ description: Conditional retry based on error or result
+ properties: *ref_167
+ required: *ref_168
no_flow_overlap:
type: boolean
description: >-
- Whether the schedule should not run if a flow is already
- running
+ If true, skip this schedule's execution if the previous run
+ is still in progress (prevents concurrent runs)
summary:
type: string
- description: The summary of the schedule
+ description: Short summary describing the purpose of this schedule
description:
type: string
- description: The description of the schedule
+ description: Detailed description of what this schedule does
tag:
type: string
- description: The tag of the schedule
+ description: Worker tag to route jobs to specific worker groups
paused_until:
type: string
- description: The date and time the schedule will be paused until
format: date-time
+ description: >-
+ ISO 8601 datetime until which the schedule is paused.
+ Schedule resumes automatically after this time
cron_version:
type: string
- description: The version of the cron schedule to use (last is v2)
- required: &ref_276
+ description: >-
+ Cron parser version. Use 'v2' for extended syntax with
+ additional features
+ dynamic_skip:
+ type: string
+ description: >-
+ Path to a script that validates scheduled datetimes.
+ Receives scheduled_for datetime and returns boolean to skip
+ (true) or run (false)
+ required: &ref_382
- path
- schedule
- timezone
@@ -12790,11 +18110,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated schedule
required: true
@@ -12802,78 +18122,103 @@ paths:
application/json:
schema:
type: object
- properties: &ref_277
+ properties: &ref_383
schedule:
type: string
description: >-
- The cron schedule to trigger the script or flow. Should
- include seconds.
+ Cron expression with 6 fields (seconds, minutes, hours, day
+ of month, month, day of week). Example '0 0 12 * * *' for
+ daily at noon
timezone:
type: string
- description: The timezone to use for the cron schedule
+ description: >-
+ IANA timezone for the schedule (e.g., 'UTC', 'Europe/Paris',
+ 'America/New_York')
args:
- description: The arguments to pass to the script or flow
type: object
- additionalProperties: *ref_22
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
on_failure:
type: string
- description: The path to the script or flow to trigger on failure
+ description: Path to a script or flow to run when the scheduled job fails
on_failure_times:
type: number
- description: The number of times to retry on failure
+ description: >-
+ Number of consecutive failures before the on_failure handler
+ is triggered (default 1)
on_failure_exact:
type: boolean
- description: Whether the schedule should only run on the exact time
+ description: >-
+ If true, trigger on_failure handler only on exactly N
+ failures, not on every failure after N
on_failure_extra_args:
- description: The arguments to pass to the script or flow
type: object
- additionalProperties: *ref_22
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
on_recovery:
type: string
- description: The path to the script or flow to trigger on recovery
+ description: >-
+ Path to a script or flow to run when the schedule recovers
+ after failures
on_recovery_times:
type: number
- description: The number of times to retry on recovery
+ description: >-
+ Number of consecutive successes before the on_recovery
+ handler is triggered (default 1)
on_recovery_extra_args:
- description: The arguments to pass to the script or flow
type: object
- additionalProperties: *ref_22
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
on_success:
type: string
- description: The path to the script or flow to trigger on success
+ description: >-
+ Path to a script or flow to run after each successful
+ execution
on_success_extra_args:
- description: The arguments to pass to the script or flow
type: object
- additionalProperties: *ref_22
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
ws_error_handler_muted:
type: boolean
- description: Whether the WebSocket error handler is muted
+ description: >-
+ If true, the workspace-level error handler will not be
+ triggered for this schedule's failures
retry:
- description: The retry configuration for the schedule
type: object
- properties: *ref_127
+ description: Retry configuration for failed module executions
+ properties: *ref_169
no_flow_overlap:
type: boolean
description: >-
- Whether the schedule should not run if a flow is already
- running
+ If true, skip this schedule's execution if the previous run
+ is still in progress (prevents concurrent runs)
summary:
type: string
- description: The summary of the schedule
+ description: Short summary describing the purpose of this schedule
description:
type: string
- description: The description of the schedule
+ description: Detailed description of what this schedule does
tag:
type: string
- description: The tag of the schedule
+ description: Worker tag to route jobs to specific worker groups
paused_until:
type: string
- description: The date and time the schedule will be paused until
format: date-time
+ description: >-
+ ISO 8601 datetime until which the schedule is paused.
+ Schedule resumes automatically after this time
cron_version:
type: string
- description: The version of the cron schedule to use (last is v2)
- required: &ref_278
+ description: >-
+ Cron parser version. Use 'v2' for extended syntax with
+ additional features
+ dynamic_skip:
+ type: string
+ description: >-
+ Path to a script that validates scheduled datetimes.
+ Receives scheduled_for datetime and returns boolean to skip
+ (true) or run (false)
+ required: &ref_384
- schedule
- timezone
- args
@@ -12894,11 +18239,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated schedule enable
required: true
@@ -12929,11 +18274,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: schedule deleted
@@ -12952,11 +18297,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: schedule deleted
@@ -12964,79 +18309,141 @@ paths:
application/json:
schema:
type: object
- properties: &ref_128
+ properties: &ref_170
path:
type: string
+ description: The unique path identifier for this schedule
edited_by:
type: string
+ description: Username of the last person who edited this schedule
edited_at:
type: string
format: date-time
+ description: Timestamp of the last edit
schedule:
type: string
+ description: >-
+ Cron expression with 6 fields (seconds, minutes, hours,
+ day of month, month, day of week). Example '0 0 12 * * *'
+ for daily at noon
timezone:
type: string
+ description: >-
+ IANA timezone for the schedule (e.g., 'UTC',
+ 'Europe/Paris', 'America/New_York')
enabled:
type: boolean
+ description: >-
+ Whether the schedule is currently active and will trigger
+ jobs
script_path:
type: string
+ description: Path to the script or flow to execute when triggered
is_flow:
type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points
+ to a script
args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
extra_perms:
type: object
additionalProperties:
type: boolean
+ description: Additional permissions for this schedule
email:
type: string
+ description: >-
+ Email of the user who owns this schedule, used for
+ permissioned_as
error:
type: string
+ description: Last error message if the schedule failed to trigger
on_failure:
type: string
+ description: >-
+ Path to a script or flow to run when the scheduled job
+ fails
on_failure_times:
type: number
+ description: >-
+ Number of consecutive failures before the on_failure
+ handler is triggered (default 1)
on_failure_exact:
type: boolean
+ description: >-
+ If true, trigger on_failure handler only on exactly N
+ failures, not on every failure after N
on_failure_extra_args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
on_recovery:
type: string
+ description: >-
+ Path to a script or flow to run when the schedule recovers
+ after failures
on_recovery_times:
type: number
+ description: >-
+ Number of consecutive successes before the on_recovery
+ handler is triggered (default 1)
on_recovery_extra_args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
on_success:
type: string
+ description: >-
+ Path to a script or flow to run after each successful
+ execution
on_success_extra_args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
ws_error_handler_muted:
type: boolean
+ description: >-
+ If true, the workspace-level error handler will not be
+ triggered for this schedule's failures
retry:
type: object
- properties: *ref_127
+ description: Retry configuration for failed module executions
+ properties: *ref_169
summary:
type: string
+ description: Short summary describing the purpose of this schedule
description:
type: string
+ description: Detailed description of what this schedule does
no_flow_overlap:
type: boolean
+ description: >-
+ If true, skip this schedule's execution if the previous
+ run is still in progress (prevents concurrent runs)
tag:
type: string
+ description: Worker tag to route jobs to specific worker groups
paused_until:
type: string
format: date-time
+ description: >-
+ ISO 8601 datetime until which the schedule is paused.
+ Schedule resumes automatically after this time
cron_version:
type: string
- required: &ref_129
+ description: >-
+ Cron parser version. Use 'v2' for extended syntax with
+ additional features
+ dynamic_skip:
+ type: string
+ description: >-
+ Path to a script that validates scheduled datetimes.
+ Receives scheduled_for datetime and returns boolean to
+ skip (true) or run (false)
+ required: &ref_171
- path
- edited_by
- edited_at
@@ -13057,11 +18464,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: schedule exists
@@ -13080,21 +18487,21 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: args
description: >-
filter on jobs containing those args as a json subset (@> in
postgres)
in: query
- schema: *ref_105
+ schema: *ref_139
- name: path
description: filter by path
in: query
@@ -13119,8 +18526,8 @@ paths:
type: array
items:
type: object
- properties: *ref_128
- required: *ref_129
+ properties: *ref_170
+ required: *ref_171
/w/{workspace}/schedules/list_with_jobs:
get:
summary: list schedules with last 20 jobs
@@ -13131,15 +18538,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
responses:
'200':
description: schedule list
@@ -13148,10 +18555,10 @@ paths:
schema:
type: array
items:
- allOf: &ref_274
+ allOf: &ref_380
- type: object
- properties: *ref_128
- required: *ref_129
+ properties: *ref_170
+ required: *ref_171
- type: object
properties:
jobs:
@@ -13179,7 +18586,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: Handler description
required: true
@@ -13222,17 +18629,17 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: openapi spec info and url
content:
application/json:
schema:
type: object
- properties: &ref_130
+ properties: &ref_173
info:
type: object
- properties: &ref_285
+ properties: &ref_390
title:
type: string
version:
@@ -13261,28 +18668,28 @@ paths:
type: string
required:
- name
- required: &ref_286
+ required: &ref_391
- title
- version
url:
type: string
openapi_spec_format:
type: string
- enum: &ref_280
+ enum: &ref_385
- yaml
- json
http_route_filters:
type: array
items:
type: object
- properties: &ref_281
+ properties: &ref_386
folder_regex:
type: string
path_regex:
type: string
route_path_regex:
type: string
- required: &ref_282
+ required: &ref_387
- folder_regex
- path_regex
- route_path_regex
@@ -13290,7 +18697,7 @@ paths:
type: array
items:
type: object
- properties: &ref_283
+ properties: &ref_388
user_or_folder_regex:
type: string
enum:
@@ -13303,10 +18710,8 @@ paths:
type: string
runnable_kind:
type: string
- enum: &ref_279
- - script
- - flow
- required: &ref_284
+ enum: *ref_172
+ required: &ref_389
- user_or_folder_regex
- user_or_folder_regex_value
- path
@@ -13328,14 +18733,14 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: openapi spec info and url
content:
application/json:
schema:
type: object
- properties: *ref_130
+ properties: *ref_173
responses:
'200':
description: Downloaded OpenAPI spec
@@ -13354,7 +18759,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new http trigger
required: true
@@ -13364,35 +18769,55 @@ paths:
type: array
items:
type: object
- properties: &ref_131
+ properties: &ref_174
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: Path to the script or flow to execute when triggered
route_path:
type: string
+ description: >-
+ The URL route path that will trigger this endpoint (e.g.,
+ 'api/myendpoint'). Must NOT start with a /.
workspaced_route:
type: boolean
+ description: If true, the route includes the workspace ID in the path
summary:
type: string
+ description: Short summary describing the purpose of this trigger
description:
type: string
+ description: Detailed description of what this trigger does
static_asset_config:
type: object
+ description: >-
+ Configuration for serving static assets (s3 bucket,
+ storage path, filename)
properties:
s3:
type: string
+ description: S3 bucket path for static assets
storage:
type: string
+ description: Storage path for static assets
filename:
type: string
+ description: Filename for the static asset
required:
- s3
is_flow:
type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points
+ to a script
http_method:
+ description: >-
+ HTTP method (get, post, put, delete, patch) that triggers
+ this endpoint
type: string
- enum: &ref_133
+ enum: &ref_176
- get
- post
- put
@@ -13400,11 +18825,30 @@ paths:
- patch
authentication_resource_path:
type: string
+ description: >-
+ Path to the resource containing authentication
+ configuration (for api_key, basic_http, custom_script,
+ signature methods)
is_async:
type: boolean
- authentication_method:
+ description: Deprecated, use request_type instead
+ request_type:
+ description: >-
+ How the request is handled - 'sync' waits for result,
+ 'async' returns job ID immediately, 'sync_sse' streams
+ results via Server-Sent Events
type: string
- enum: &ref_134
+ enum: &ref_177
+ - sync
+ - async
+ - sync_sse
+ authentication_method:
+ description: >-
+ How requests are authenticated - 'none' (public),
+ 'windmill' (Windmill token), 'api_key', 'basic_http',
+ 'custom_script', 'signature'
+ type: string
+ enum: &ref_178
- none
- windmill
- api_key
@@ -13413,25 +18857,42 @@ paths:
- signature
is_static_website:
type: boolean
+ description: >-
+ If true, serves static files from S3/storage instead of
+ running a script
wrap_body:
type: boolean
+ description: If true, wraps the request body in a 'body' parameter
+ mode:
+ description: job trigger mode
+ type: string
+ enum: &ref_179
+ - enabled
+ - disabled
+ - suspended
raw_string:
type: boolean
+ description: >-
+ If true, passes the request body as a raw string instead
+ of parsing as JSON
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_132
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_175
- path
- script_path
- route_path
- is_flow
- - is_async
- authentication_method
- http_method
- is_static_website
@@ -13452,7 +18913,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new http trigger
required: true
@@ -13460,8 +18921,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_131
- required: *ref_132
+ properties: *ref_174
+ required: *ref_175
responses:
'201':
description: http trigger created
@@ -13479,11 +18940,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated trigger
required: true
@@ -13491,63 +18952,106 @@ paths:
application/json:
schema:
type: object
- properties: &ref_287
+ properties: &ref_392
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: Path to the script or flow to execute when triggered
route_path:
type: string
+ description: >-
+ The URL route path that will trigger this endpoint (e.g.,
+ 'api/myendpoint'). Must NOT start with a /.
summary:
type: string
+ description: Short summary describing the purpose of this trigger
description:
type: string
+ description: Detailed description of what this trigger does
workspaced_route:
type: boolean
+ description: If true, the route includes the workspace ID in the path
static_asset_config:
type: object
+ description: >-
+ Configuration for serving static assets (s3 bucket, storage
+ path, filename)
properties:
s3:
type: string
+ description: S3 bucket path for static assets
storage:
type: string
+ description: Storage path for static assets
filename:
type: string
+ description: Filename for the static asset
required:
- s3
authentication_resource_path:
type: string
+ description: >-
+ Path to the resource containing authentication configuration
+ (for api_key, basic_http, custom_script, signature methods)
is_flow:
type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
http_method:
+ description: >-
+ HTTP method (get, post, put, delete, patch) that triggers
+ this endpoint
type: string
- enum: *ref_133
+ enum: *ref_176
is_async:
type: boolean
- authentication_method:
+ description: Deprecated, use request_type instead
+ request_type:
+ description: >-
+ How the request is handled - 'sync' waits for result,
+ 'async' returns job ID immediately, 'sync_sse' streams
+ results via Server-Sent Events
type: string
- enum: *ref_134
+ enum: *ref_177
+ authentication_method:
+ description: >-
+ How requests are authenticated - 'none' (public), 'windmill'
+ (Windmill token), 'api_key', 'basic_http', 'custom_script',
+ 'signature'
+ type: string
+ enum: *ref_178
is_static_website:
type: boolean
+ description: >-
+ If true, serves static files from S3/storage instead of
+ running a script
wrap_body:
type: boolean
+ description: If true, wraps the request body in a 'body' parameter
raw_string:
type: boolean
+ description: >-
+ If true, passes the request body as a raw string instead of
+ parsing as JSON
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_288
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_393
- path
- script_path
- is_flow
- kind
- - is_async
- authentication_method
- http_method
- is_static_website
@@ -13568,11 +19072,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: http trigger deleted
@@ -13590,40 +19094,56 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: http trigger deleted
content:
application/json:
schema:
- allOf: &ref_135
+ allOf: &ref_180
- type: object
- properties: &ref_139
+ properties: &ref_184
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: Path to the script or flow to execute when triggered
email:
type: string
+ description: >-
+ Email of the user who owns this trigger, used for
+ permissioned_as
extra_perms:
type: object
+ description: Additional permissions for this trigger
additionalProperties:
type: boolean
workspace_id:
type: string
+ description: The workspace this trigger belongs to
edited_by:
type: string
+ description: Username of the last person who edited this trigger
edited_at:
type: string
format: date-time
+ description: Timestamp of the last edit
is_flow:
type: boolean
- required: &ref_140
+ description: >-
+ True if script_path points to a flow, false if it
+ points to a script
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
+ required: &ref_185
- path
- script_path
- email
@@ -13632,55 +19152,95 @@ paths:
- edited_by
- edited_at
- is_flow
+ - mode
type: object
- properties: &ref_136
+ properties: &ref_181
route_path:
type: string
+ description: >-
+ The URL route path that will trigger this endpoint (e.g.,
+ 'api/myendpoint'). Must NOT start with a /.
static_asset_config:
type: object
+ description: >-
+ Configuration for serving static assets (s3 bucket,
+ storage path, filename)
properties:
s3:
type: string
+ description: S3 bucket path for static assets
storage:
type: string
+ description: Storage path for static assets
filename:
type: string
+ description: Filename for the static asset
required:
- s3
http_method:
+ description: >-
+ HTTP method (get, post, put, delete, patch) that triggers
+ this endpoint
type: string
- enum: *ref_133
+ enum: *ref_176
authentication_resource_path:
type: string
+ description: >-
+ Path to the resource containing authentication
+ configuration (for api_key, basic_http, custom_script,
+ signature methods)
summary:
type: string
+ description: Short summary describing the purpose of this trigger
description:
type: string
- is_async:
- type: boolean
- authentication_method:
+ description: Detailed description of what this trigger does
+ request_type:
+ description: >-
+ How the request is handled - 'sync' waits for result,
+ 'async' returns job ID immediately, 'sync_sse' streams
+ results via Server-Sent Events
type: string
- enum: *ref_134
+ enum: *ref_177
+ authentication_method:
+ description: >-
+ How requests are authenticated - 'none' (public),
+ 'windmill' (Windmill token), 'api_key', 'basic_http',
+ 'custom_script', 'signature'
+ type: string
+ enum: *ref_178
is_static_website:
type: boolean
+ description: >-
+ If true, serves static files from S3/storage instead of
+ running a script
workspaced_route:
type: boolean
+ description: If true, the route includes the workspace ID in the path
wrap_body:
type: boolean
+ description: If true, wraps the request body in a 'body' parameter
raw_string:
type: boolean
+ description: >-
+ If true, passes the request body as a raw string instead
+ of parsing as JSON
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_137
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_182
- route_path
- - is_async
+ - request_type
- authentication_method
- http_method
- is_static_website
@@ -13697,15 +19257,15 @@ paths:
- required: true
name: workspace
in: path
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: path
description: filter by path
in: query
@@ -13727,10 +19287,10 @@ paths:
schema:
type: array
items:
- allOf: *ref_135
+ allOf: *ref_180
type: object
- properties: *ref_136
- required: *ref_137
+ properties: *ref_181
+ required: *ref_182
/w/{workspace}/http_triggers/exists/{path}:
get:
summary: does http trigger exists
@@ -13741,11 +19301,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: http trigger exists
@@ -13763,7 +19323,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: route exists request
required: true
@@ -13776,7 +19336,7 @@ paths:
type: string
http_method:
type: string
- enum: *ref_133
+ enum: *ref_176
trigger_path:
type: string
workspaced_route:
@@ -13791,6 +19351,41 @@ paths:
application/json:
schema:
type: boolean
+ /w/{workspace}/http_triggers/setmode/{path}:
+ post:
+ summary: enable/disable http trigger
+ operationId: setHttpTriggerMode
+ tags:
+ - http_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_48
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
+ required:
+ - mode
+ responses:
+ '200':
+ description: http trigger enable/disable
+ content:
+ text/plain:
+ schema:
+ type: string
/w/{workspace}/websocket_triggers/create:
post:
summary: create websocket trigger
@@ -13801,7 +19396,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new websocket trigger
required: true
@@ -13809,19 +19404,34 @@ paths:
application/json:
schema:
type: object
- properties: &ref_289
+ properties: &ref_394
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
url:
type: string
- enabled:
- type: boolean
+ description: >-
+ The WebSocket URL to connect to (can be a static URL or
+ computed by a runnable)
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
filters:
type: array
+ description: >-
+ Array of key-value filters to match incoming messages (only
+ matching messages trigger the script)
items:
type: object
properties:
@@ -13833,8 +19443,11 @@ paths:
- value
initial_messages:
type: array
+ description: >-
+ Messages to send immediately after connecting (can be raw
+ strings or computed by runnables)
items:
- anyOf: &ref_138
+ anyOf: &ref_183
- type: object
properties:
raw_message:
@@ -13851,7 +19464,7 @@ paths:
args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
is_flow:
type: boolean
required:
@@ -13861,27 +19474,36 @@ paths:
required:
- runnable_result
url_runnable_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ type: object
+ additionalProperties: true
can_return_message:
type: boolean
+ description: >-
+ If true, the script can return a message to send back
+ through the WebSocket
+ can_return_error_result:
+ type: boolean
+ description: If true, error results are sent back through the WebSocket
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_290
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_395
- path
- script_path
- url
- is_flow
- filters
- can_return_message
+ - can_return_error_result
responses:
'201':
description: websocket trigger created
@@ -13899,11 +19521,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated trigger
required: true
@@ -13911,17 +19533,30 @@ paths:
application/json:
schema:
type: object
- properties: &ref_291
+ properties: &ref_396
url:
type: string
+ description: >-
+ The WebSocket URL to connect to (can be a static URL or
+ computed by a runnable)
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
filters:
type: array
+ description: >-
+ Array of key-value filters to match incoming messages (only
+ matching messages trigger the script)
items:
type: object
properties:
@@ -13933,30 +19568,42 @@ paths:
- value
initial_messages:
type: array
+ description: >-
+ Messages to send immediately after connecting (can be raw
+ strings or computed by runnables)
items:
- anyOf: *ref_138
+ anyOf: *ref_183
url_runnable_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ type: object
+ additionalProperties: true
can_return_message:
type: boolean
+ description: >-
+ If true, the script can return a message to send back
+ through the WebSocket
+ can_return_error_result:
+ type: boolean
+ description: If true, error results are sent back through the WebSocket
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_292
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_397
- path
- script_path
- url
- is_flow
- filters
- can_return_message
+ - can_return_error_result
responses:
'200':
description: websocket trigger updated
@@ -13974,11 +19621,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: websocket trigger deleted
@@ -13996,36 +19643,45 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: websocket trigger deleted
content:
application/json:
schema:
- allOf: &ref_141
+ allOf: &ref_186
- type: object
- properties: *ref_139
- required: *ref_140
+ properties: *ref_184
+ required: *ref_185
type: object
- properties: &ref_142
+ properties: &ref_187
url:
type: string
+ description: >-
+ The WebSocket URL to connect to (can be a static URL or
+ computed by a runnable)
server_id:
type: string
+ description: >-
+ ID of the server currently handling this trigger
+ (internal)
last_server_ping:
type: string
format: date-time
+ description: Timestamp of last server heartbeat (internal)
error:
type: string
- enabled:
- type: boolean
+ description: Last error message if the trigger failed
filters:
type: array
+ description: >-
+ Array of key-value filters to match incoming messages
+ (only matching messages trigger the script)
items:
type: object
properties:
@@ -14037,28 +19693,41 @@ paths:
- value
initial_messages:
type: array
+ description: >-
+ Messages to send immediately after connecting (can be raw
+ strings or computed by runnables)
items:
- anyOf: *ref_138
+ anyOf: *ref_183
url_runnable_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ type: object
+ additionalProperties: true
can_return_message:
type: boolean
+ description: >-
+ If true, the script can return a message to send back
+ through the WebSocket
+ can_return_error_result:
+ type: boolean
+ description: If true, error results are sent back through the WebSocket
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_143
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_188
- url
- - enabled
- filters
- can_return_message
+ - can_return_error_result
/w/{workspace}/websocket_triggers/list:
get:
summary: list websocket triggers
@@ -14069,15 +19738,15 @@ paths:
- required: true
name: workspace
in: path
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: path
description: filter by path
in: query
@@ -14099,10 +19768,10 @@ paths:
schema:
type: array
items:
- allOf: *ref_141
+ allOf: *ref_186
type: object
- properties: *ref_142
- required: *ref_143
+ properties: *ref_187
+ required: *ref_188
/w/{workspace}/websocket_triggers/exists/{path}:
get:
summary: does websocket trigger exists
@@ -14113,11 +19782,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: websocket trigger exists
@@ -14125,21 +19794,21 @@ paths:
application/json:
schema:
type: boolean
- /w/{workspace}/websocket_triggers/setenabled/{path}:
+ /w/{workspace}/websocket_triggers/setmode/{path}:
post:
summary: set enabled websocket trigger
- operationId: setWebsocketTriggerEnabled
+ operationId: setWebsocketTriggerMode
tags:
- websocket_trigger
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated websocket trigger enable
required: true
@@ -14148,10 +19817,12 @@ paths:
schema:
type: object
properties:
- enabled:
- type: boolean
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
required:
- - enabled
+ - mode
responses:
'200':
description: websocket trigger enabled set
@@ -14169,7 +19840,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: test websocket connection
required: true
@@ -14183,7 +19854,7 @@ paths:
url_runnable_args:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
can_return_message:
type: boolean
required:
@@ -14206,7 +19877,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new kafka trigger
required: true
@@ -14214,39 +19885,67 @@ paths:
application/json:
schema:
type: object
- properties: &ref_315
+ properties: &ref_421
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
kafka_resource_path:
type: string
+ description: >-
+ Path to the Kafka resource containing connection
+ configuration
group_id:
type: string
+ description: Kafka consumer group ID for this trigger
topics:
type: array
items:
type: string
- enabled:
- type: boolean
+ description: Array of Kafka topic names to subscribe to
+ filters:
+ type: array
+ items:
+ type: object
+ properties:
+ key:
+ type: string
+ value: {}
+ required:
+ - key
+ - value
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_316
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_422
- path
- script_path
- is_flow
- kafka_resource_path
- group_id
- topics
+ - filters
responses:
'201':
description: kafka trigger created
@@ -14264,11 +19963,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated trigger
required: true
@@ -14276,36 +19975,62 @@ paths:
application/json:
schema:
type: object
- properties: &ref_317
+ properties: &ref_423
kafka_resource_path:
type: string
+ description: >-
+ Path to the Kafka resource containing connection
+ configuration
group_id:
type: string
+ description: Kafka consumer group ID for this trigger
topics:
type: array
items:
type: string
+ description: Array of Kafka topic names to subscribe to
+ filters:
+ type: array
+ items:
+ type: object
+ properties:
+ key:
+ type: string
+ value: {}
+ required:
+ - key
+ - value
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_318
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_424
- path
- script_path
- kafka_resource_path
- group_id
- topics
+ - filters
- is_flow
responses:
'200':
@@ -14324,11 +20049,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: kafka trigger deleted
@@ -14346,54 +20071,77 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: kafka trigger deleted
content:
application/json:
schema:
- allOf: &ref_144
+ allOf: &ref_189
- type: object
- properties: *ref_139
- required: *ref_140
+ properties: *ref_184
+ required: *ref_185
type: object
- properties: &ref_145
+ properties: &ref_190
kafka_resource_path:
type: string
+ description: >-
+ Path to the Kafka resource containing connection
+ configuration
group_id:
type: string
+ description: Kafka consumer group ID for this trigger
topics:
type: array
items:
type: string
+ description: Array of Kafka topic names to subscribe to
+ filters:
+ type: array
+ items:
+ type: object
+ properties:
+ key:
+ type: string
+ value: {}
+ required:
+ - key
+ - value
server_id:
type: string
+ description: >-
+ ID of the server currently handling this trigger
+ (internal)
last_server_ping:
type: string
format: date-time
+ description: Timestamp of last server heartbeat (internal)
error:
type: string
- enabled:
- type: boolean
+ description: Last error message if the trigger failed
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_146
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_191
- kafka_resource_path
- group_id
- topics
- - enabled
+ - filters
/w/{workspace}/kafka_triggers/list:
get:
summary: list kafka triggers
@@ -14404,15 +20152,15 @@ paths:
- required: true
name: workspace
in: path
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: path
description: filter by path
in: query
@@ -14434,10 +20182,10 @@ paths:
schema:
type: array
items:
- allOf: *ref_144
+ allOf: *ref_189
type: object
- properties: *ref_145
- required: *ref_146
+ properties: *ref_190
+ required: *ref_191
/w/{workspace}/kafka_triggers/exists/{path}:
get:
summary: does kafka trigger exists
@@ -14448,11 +20196,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: kafka trigger exists
@@ -14460,21 +20208,21 @@ paths:
application/json:
schema:
type: boolean
- /w/{workspace}/kafka_triggers/setenabled/{path}:
+ /w/{workspace}/kafka_triggers/setmode/{path}:
post:
summary: set enabled kafka trigger
- operationId: setKafkaTriggerEnabled
+ operationId: setKafkaTriggerMode
tags:
- kafka_trigger
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated kafka trigger enable
required: true
@@ -14483,10 +20231,12 @@ paths:
schema:
type: object
properties:
- enabled:
- type: boolean
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
required:
- - enabled
+ - mode
responses:
'200':
description: kafka trigger enabled set
@@ -14504,7 +20254,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: test kafka connection
required: true
@@ -14534,7 +20284,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new nats trigger
required: true
@@ -14542,37 +20292,57 @@ paths:
application/json:
schema:
type: object
- properties: &ref_319
+ properties: &ref_425
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
nats_resource_path:
type: string
+ description: >-
+ Path to the NATS resource containing connection
+ configuration
use_jetstream:
type: boolean
+ description: If true, uses NATS JetStream for durable message delivery
stream_name:
type: string
+ description: JetStream stream name (required when use_jetstream is true)
consumer_name:
type: string
+ description: >-
+ JetStream consumer name (required when use_jetstream is
+ true)
subjects:
type: array
items:
type: string
- enabled:
- type: boolean
+ description: Array of NATS subjects to subscribe to
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_320
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_426
- path
- script_path
- is_flow
@@ -14596,11 +20366,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated trigger
required: true
@@ -14608,35 +20378,53 @@ paths:
application/json:
schema:
type: object
- properties: &ref_321
+ properties: &ref_427
nats_resource_path:
type: string
+ description: >-
+ Path to the NATS resource containing connection
+ configuration
use_jetstream:
type: boolean
+ description: If true, uses NATS JetStream for durable message delivery
stream_name:
type: string
+ description: JetStream stream name (required when use_jetstream is true)
consumer_name:
type: string
+ description: >-
+ JetStream consumer name (required when use_jetstream is
+ true)
subjects:
type: array
items:
type: string
+ description: Array of NATS subjects to subscribe to
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_322
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_428
- path
- script_path
- nats_resource_path
@@ -14660,11 +20448,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: nats trigger deleted
@@ -14682,58 +20470,75 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: nats trigger deleted
content:
application/json:
schema:
- allOf: &ref_147
+ allOf: &ref_192
- type: object
- properties: *ref_139
- required: *ref_140
+ properties: *ref_184
+ required: *ref_185
type: object
- properties: &ref_148
+ properties: &ref_193
nats_resource_path:
type: string
+ description: >-
+ Path to the NATS resource containing connection
+ configuration
use_jetstream:
type: boolean
+ description: If true, uses NATS JetStream for durable message delivery
stream_name:
type: string
+ description: >-
+ JetStream stream name (required when use_jetstream is
+ true)
consumer_name:
type: string
+ description: >-
+ JetStream consumer name (required when use_jetstream is
+ true)
subjects:
type: array
items:
type: string
+ description: Array of NATS subjects to subscribe to
server_id:
type: string
+ description: >-
+ ID of the server currently handling this trigger
+ (internal)
last_server_ping:
type: string
format: date-time
+ description: Timestamp of last server heartbeat (internal)
error:
type: string
- enabled:
- type: boolean
+ description: Last error message if the trigger failed
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_149
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_194
- nats_resource_path
- use_jetstream
- subjects
- - enabled
/w/{workspace}/nats_triggers/list:
get:
summary: list nats triggers
@@ -14744,15 +20549,15 @@ paths:
- required: true
name: workspace
in: path
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: path
description: filter by path
in: query
@@ -14774,10 +20579,10 @@ paths:
schema:
type: array
items:
- allOf: *ref_147
+ allOf: *ref_192
type: object
- properties: *ref_148
- required: *ref_149
+ properties: *ref_193
+ required: *ref_194
/w/{workspace}/nats_triggers/exists/{path}:
get:
summary: does nats trigger exists
@@ -14788,11 +20593,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: nats trigger exists
@@ -14800,21 +20605,21 @@ paths:
application/json:
schema:
type: boolean
- /w/{workspace}/nats_triggers/setenabled/{path}:
+ /w/{workspace}/nats_triggers/setmode/{path}:
post:
summary: set enabled nats trigger
- operationId: setNatsTriggerEnabled
+ operationId: setNatsTriggerMode
tags:
- nats_trigger
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated nats trigger enable
required: true
@@ -14823,10 +20628,12 @@ paths:
schema:
type: object
properties:
- enabled:
- type: boolean
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
required:
- - enabled
+ - mode
responses:
'200':
description: nats trigger enabled set
@@ -14844,7 +20651,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: test nats connection
required: true
@@ -14874,7 +20681,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new sqs trigger
required: true
@@ -14882,38 +20689,59 @@ paths:
application/json:
schema:
type: object
- properties: &ref_302
+ properties: &ref_408
queue_url:
type: string
+ description: The full URL of the AWS SQS queue to poll for messages
aws_auth_resource_type:
+ description: >-
+ Authentication type - 'credentials' for access key/secret,
+ 'oidc' for OpenID Connect
type: string
- enum: &ref_150
+ enum: &ref_195
- oidc
- credentials
aws_resource_path:
type: string
+ description: >-
+ Path to the AWS resource containing credentials or OIDC
+ configuration
message_attributes:
type: array
items:
type: string
+ description: >-
+ Array of SQS message attribute names to include with each
+ message
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
- enabled:
- type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_303
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_409
- queue_url
- aws_resource_path
- path
@@ -14937,11 +20765,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated trigger
required: true
@@ -14949,36 +20777,57 @@ paths:
application/json:
schema:
type: object
- properties: &ref_304
+ properties: &ref_410
queue_url:
type: string
+ description: The full URL of the AWS SQS queue to poll for messages
aws_auth_resource_type:
+ description: >-
+ Authentication type - 'credentials' for access key/secret,
+ 'oidc' for OpenID Connect
type: string
- enum: *ref_150
+ enum: *ref_195
aws_resource_path:
type: string
+ description: >-
+ Path to the AWS resource containing credentials or OIDC
+ configuration
message_attributes:
type: array
items:
type: string
+ description: >-
+ Array of SQS message attribute names to include with each
+ message
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
- enabled:
- type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_305
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_411
- queue_url
- aws_resource_path
- path
@@ -15003,11 +20852,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: sqs trigger deleted
@@ -15025,56 +20874,72 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: sqs trigger deleted
content:
application/json:
schema:
- allOf: &ref_151
+ allOf: &ref_196
- type: object
- properties: *ref_139
- required: *ref_140
+ properties: *ref_184
+ required: *ref_185
type: object
- properties: &ref_152
+ properties: &ref_197
queue_url:
type: string
+ description: The full URL of the AWS SQS queue to poll for messages
aws_auth_resource_type:
+ description: >-
+ Authentication type - 'credentials' for access key/secret,
+ 'oidc' for OpenID Connect
type: string
- enum: *ref_150
+ enum: *ref_195
aws_resource_path:
type: string
+ description: >-
+ Path to the AWS resource containing credentials or OIDC
+ configuration
message_attributes:
type: array
items:
type: string
+ description: >-
+ Array of SQS message attribute names to include with each
+ message
server_id:
type: string
+ description: >-
+ ID of the server currently handling this trigger
+ (internal)
last_server_ping:
type: string
format: date-time
+ description: Timestamp of last server heartbeat (internal)
error:
type: string
- enabled:
- type: boolean
+ description: Last error message if the trigger failed
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_153
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_198
- queue_url
- aws_resource_path
- - enabled
- aws_auth_resource_type
/w/{workspace}/sqs_triggers/list:
get:
@@ -15086,15 +20951,15 @@ paths:
- required: true
name: workspace
in: path
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: path
description: filter by path
in: query
@@ -15116,10 +20981,10 @@ paths:
schema:
type: array
items:
- allOf: *ref_151
+ allOf: *ref_196
type: object
- properties: *ref_152
- required: *ref_153
+ properties: *ref_197
+ required: *ref_198
/w/{workspace}/sqs_triggers/exists/{path}:
get:
summary: does sqs trigger exists
@@ -15130,11 +20995,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: sqs trigger exists
@@ -15142,21 +21007,21 @@ paths:
application/json:
schema:
type: boolean
- /w/{workspace}/sqs_triggers/setenabled/{path}:
+ /w/{workspace}/sqs_triggers/setmode/{path}:
post:
summary: set enabled sqs trigger
- operationId: setSqsTriggerEnabled
+ operationId: setSqsTriggerMode
tags:
- sqs_trigger
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated sqs trigger enable
required: true
@@ -15165,10 +21030,12 @@ paths:
schema:
type: object
properties:
- enabled:
- type: boolean
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
required:
- - enabled
+ - mode
responses:
'200':
description: sqs trigger enabled set
@@ -15186,7 +21053,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: test sqs connection
required: true
@@ -15206,6 +21073,648 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/native_triggers/integrations/list:
+ get:
+ summary: list available native trigger services
+ operationId: listNativeTriggerServices
+ tags:
+ - workspace_integration
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: native trigger services list
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties: &ref_506
+ service_name:
+ type: string
+ enum: &ref_199
+ - nextcloud
+ oauth_data:
+ nullable: true
+ type: object
+ properties: &ref_200
+ client_id:
+ type: string
+ description: The OAuth client ID for the workspace
+ client_secret:
+ type: string
+ description: The OAuth client secret for the workspace
+ base_url:
+ type: string
+ format: uri
+ description: The base URL of the workspace
+ redirect_uri:
+ type: string
+ format: uri
+ description: The OAuth redirect URI
+ required: &ref_201
+ - client_id
+ - client_secret
+ - base_url
+ - redirect_uri
+ required: &ref_507
+ - service_name
+ /w/{workspace}/native_triggers/integrations/{service_name}/exists:
+ get:
+ summary: check if integrations for a particular service exists
+ operationId: checkIfNativeTriggersServiceExists
+ tags:
+ - workspace_integration
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ responses:
+ '200':
+ description: integration exists
+ content:
+ application/json:
+ schema:
+ type: boolean
+ /w/{workspace}/native_triggers/integrations/{service_name}/create:
+ post:
+ summary: create native trigger service
+ operationId: createNativeTriggerService
+ tags:
+ - workspace_integration
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ requestBody:
+ description: new native trigger service
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_200
+ required: *ref_201
+ responses:
+ '201':
+ description: native trigger service created
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/native_triggers/integrations/{service_name}/generate_connect_url:
+ post:
+ summary: generate connect url for native trigger service
+ operationId: generateNativeTriggerServiceConnectUrl
+ tags:
+ - workspace_integration
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ requestBody:
+ description: redirect_uri
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: &ref_202
+ redirect_uri:
+ type: string
+ required: &ref_203
+ - redirect_uri
+ responses:
+ '200':
+ description: native trigger service connect url
+ content:
+ application/json:
+ schema:
+ type: string
+ /w/{workspace}/native_triggers/integrations/{service_name}/delete:
+ delete:
+ summary: delete native trigger service
+ operationId: deleteNativeTriggerService
+ tags:
+ - workspace_integration
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ responses:
+ '200':
+ description: native trigger service deleted
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/native_triggers/integrations/{service_name}/callback/{code}/{state}:
+ post:
+ summary: native trigger service oauth callback
+ operationId: nativeTriggerServiceCallback
+ tags:
+ - workspace_integration
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ - name: code
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: state
+ in: path
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: redirect_uri
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_202
+ required: *ref_203
+ responses:
+ '200':
+ description: native trigger service oauth completed
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/native_triggers/{service_name}/create:
+ post:
+ summary: create native trigger
+ description: >
+ Creates a new native trigger for the specified service.
+
+ Requires write access to the script or flow that the trigger will be
+ associated with.
+ operationId: createNativeTrigger
+ tags:
+ - native_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ requestBody:
+ description: new native trigger configuration
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ description: Data for creating or updating a native trigger
+ properties: &ref_204
+ script_path:
+ type: string
+ description: The path to the script or flow that will be triggered
+ is_flow:
+ type: boolean
+ description: >-
+ Whether the trigger targets a flow (true) or a script
+ (false)
+ service_config:
+ type: object
+ description: Service-specific configuration (e.g., event types, filters)
+ additionalProperties: true
+ required: &ref_205
+ - script_path
+ - is_flow
+ - service_config
+ responses:
+ '201':
+ description: native trigger created
+ content:
+ application/json:
+ schema:
+ type: object
+ description: Response returned when a native trigger is created
+ properties: &ref_509
+ external_id:
+ type: string
+ description: >-
+ The external ID of the created trigger from the external
+ service
+ required: &ref_510
+ - external_id
+ /w/{workspace}/native_triggers/{service_name}/update/{external_id}:
+ post:
+ summary: update native trigger
+ description: >
+ Updates an existing native trigger.
+
+ Requires write access to the script or flow that the trigger is
+ associated with.
+ operationId: updateNativeTrigger
+ tags:
+ - native_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ - name: external_id
+ in: path
+ required: true
+ description: The external ID of the trigger from the external service
+ schema:
+ type: string
+ requestBody:
+ description: updated native trigger configuration
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ description: Data for creating or updating a native trigger
+ properties: *ref_204
+ required: *ref_205
+ responses:
+ '200':
+ description: native trigger updated
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/native_triggers/{service_name}/get/{external_id}:
+ get:
+ summary: get native trigger
+ description: >
+ Retrieves a native trigger by its external ID.
+
+ Requires write access to the script or flow that the trigger is
+ associated with.
+ operationId: getNativeTrigger
+ tags:
+ - native_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ - name: external_id
+ in: path
+ required: true
+ description: The external ID of the trigger from the external service
+ schema:
+ type: string
+ responses:
+ '200':
+ description: native trigger with external configuration
+ content:
+ application/json:
+ schema:
+ type: object
+ description: >-
+ Full trigger response containing both Windmill data and
+ external service data
+ properties: &ref_504
+ external_id:
+ type: string
+ description: The unique identifier from the external service
+ workspace_id:
+ type: string
+ description: The workspace this trigger belongs to
+ service_name:
+ type: string
+ enum: *ref_199
+ script_path:
+ type: string
+ description: The path to the script or flow that will be triggered
+ is_flow:
+ type: boolean
+ description: >-
+ Whether the trigger targets a flow (true) or a script
+ (false)
+ service_config:
+ type: object
+ description: >-
+ Configuration for the trigger including event_type and
+ service_config
+ additionalProperties: true
+ error:
+ type: string
+ nullable: true
+ description: Error message if the trigger is in an error state
+ external_data:
+ type: object
+ description: Configuration data from the external service
+ additionalProperties: true
+ required: &ref_505
+ - external_id
+ - workspace_id
+ - service_name
+ - script_path
+ - is_flow
+ - service_config
+ - external_data
+ /w/{workspace}/native_triggers/{service_name}/delete/{external_id}:
+ delete:
+ summary: delete native trigger
+ description: >
+ Deletes a native trigger by its external ID.
+
+ Requires write access to the script or flow that the trigger is
+ associated with.
+ operationId: deleteNativeTrigger
+ tags:
+ - native_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ - name: external_id
+ in: path
+ required: true
+ description: The external ID of the trigger from the external service
+ schema:
+ type: string
+ responses:
+ '200':
+ description: native trigger deleted
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/native_triggers/{service_name}/list:
+ get:
+ summary: list native triggers
+ description: Lists all native triggers for the specified service in the workspace.
+ operationId: listNativeTriggers
+ tags:
+ - native_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ - name: page
+ description: which page to return (start at 1, default 1)
+ in: query
+ schema: *ref_13
+ - name: per_page
+ description: number of items to return for a given page (default 30, max 100)
+ in: query
+ schema: *ref_14
+ - name: path
+ description: filter by script path
+ in: query
+ schema:
+ type: string
+ - name: is_flow
+ description: filter by is_flow
+ in: query
+ schema:
+ type: boolean
+ responses:
+ '200':
+ description: native triggers list
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ description: A native trigger stored in Windmill
+ properties: &ref_502
+ external_id:
+ type: string
+ description: The unique identifier from the external service
+ workspace_id:
+ type: string
+ description: The workspace this trigger belongs to
+ service_name:
+ type: string
+ enum: *ref_199
+ script_path:
+ type: string
+ description: The path to the script or flow that will be triggered
+ is_flow:
+ type: boolean
+ description: >-
+ Whether the trigger targets a flow (true) or a script
+ (false)
+ service_config:
+ type: object
+ description: >-
+ Configuration for the trigger including event_type and
+ service_config
+ additionalProperties: true
+ error:
+ type: string
+ nullable: true
+ description: Error message if the trigger is in an error state
+ required: &ref_503
+ - external_id
+ - workspace_id
+ - service_name
+ - script_path
+ - is_flow
+ - service_config
+ /w/{workspace}/native_triggers/{service_name}/exists/{external_id}:
+ get:
+ summary: check if native trigger exists
+ description: Checks if a native trigger with the given external ID exists.
+ operationId: existsNativeTrigger
+ tags:
+ - native_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ - name: external_id
+ in: path
+ required: true
+ description: The external ID of the trigger from the external service
+ schema:
+ type: string
+ responses:
+ '200':
+ description: whether the native trigger exists
+ content:
+ application/json:
+ schema:
+ type: boolean
+ /w/{workspace}/native_triggers/{service_name}/sync:
+ post:
+ summary: sync native triggers with external service
+ operationId: syncNativeTriggers
+ tags:
+ - native_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ responses:
+ '200':
+ description: sync completed successfully
+ /w/{workspace}/native_triggers/nextcloud/events:
+ get:
+ summary: list available NextCloud events
+ operationId: listNextCloudEvents
+ tags:
+ - native_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: list of available NextCloud events
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties: &ref_511
+ id:
+ type: string
+ name:
+ type: string
+ description:
+ type: string
+ category:
+ type: string
+ path:
+ type: string
+ required: &ref_512
+ - id
+ - name
+ - path
+ /native_triggers/{service_name}/w/{workspace_id}/webhook/{internal_id}:
+ post:
+ summary: receive webhook from external native trigger service
+ operationId: nativeTriggerWebhook
+ tags:
+ - native_trigger
+ parameters:
+ - name: service_name
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: *ref_199
+ - name: workspace_id
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: internal_id
+ in: path
+ required: true
+ schema:
+ type: integer
+ format: int64
+ description: The internal database ID of the trigger
+ requestBody:
+ description: webhook payload from external service
+ required: false
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties: true
+ text/plain:
+ schema:
+ type: string
+ responses:
+ '200':
+ description: webhook received successfully
+ content:
+ text/plain:
+ schema:
+ type: string
/w/{workspace}/mqtt_triggers/create:
post:
summary: create mqtt trigger
@@ -15216,7 +21725,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new mqtt trigger
required: true
@@ -15224,35 +21733,46 @@ paths:
application/json:
schema:
type: object
- properties: &ref_294
+ properties: &ref_399
mqtt_resource_path:
type: string
+ description: >-
+ Path to the MQTT resource containing broker connection
+ configuration
subscribe_topics:
type: array
items:
type: object
- properties: &ref_154
+ properties: &ref_206
qos:
type: string
- enum: &ref_293
+ enum: &ref_398
- qos0
- qos1
- qos2
topic:
type: string
- required: &ref_155
+ required: &ref_207
- qos
- topic
+ description: >-
+ Array of MQTT topics to subscribe to, each with topic name
+ and QoS level
client_id:
type: string
+ description: MQTT client ID for this connection
v3_config:
+ description: MQTT v3 specific configuration (clean_session)
type: object
- properties: &ref_156
+ properties: &ref_208
clean_session:
type: boolean
v5_config:
+ description: >-
+ MQTT v5 specific configuration (clean_start,
+ topic_alias_maximum, session_expiry_interval)
type: object
- properties: &ref_157
+ properties: &ref_209
clean_start:
type: boolean
topic_alias_maximum:
@@ -15260,28 +21780,40 @@ paths:
session_expiry_interval:
type: number
client_version:
+ description: MQTT protocol version ('v3' or 'v5')
type: string
- enum: &ref_158
+ enum: &ref_210
- v3
- v5
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
- enabled:
- type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_295
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_400
- path
- script_path
- is_flow
@@ -15304,11 +21836,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated trigger
required: true
@@ -15316,44 +21848,67 @@ paths:
application/json:
schema:
type: object
- properties: &ref_296
+ properties: &ref_401
mqtt_resource_path:
type: string
+ description: >-
+ Path to the MQTT resource containing broker connection
+ configuration
subscribe_topics:
type: array
items:
type: object
- properties: *ref_154
- required: *ref_155
+ properties: *ref_206
+ required: *ref_207
+ description: >-
+ Array of MQTT topics to subscribe to, each with topic name
+ and QoS level
client_id:
type: string
+ description: MQTT client ID for this connection
v3_config:
+ description: MQTT v3 specific configuration (clean_session)
type: object
- properties: *ref_156
+ properties: *ref_208
v5_config:
+ description: >-
+ MQTT v5 specific configuration (clean_start,
+ topic_alias_maximum, session_expiry_interval)
type: object
- properties: *ref_157
+ properties: *ref_209
client_version:
+ description: MQTT protocol version ('v3' or 'v5')
type: string
- enum: *ref_158
+ enum: *ref_210
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received
is_flow:
type: boolean
- enabled:
- type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_297
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_402
- path
- script_path
- is_flow
@@ -15377,11 +21932,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: mqtt trigger deleted
@@ -15399,62 +21954,80 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: mqtt trigger deleted
content:
application/json:
schema:
- allOf: &ref_159
+ allOf: &ref_211
- type: object
- properties: *ref_139
- required: *ref_140
+ properties: *ref_184
+ required: *ref_185
type: object
- properties: &ref_160
+ properties: &ref_212
mqtt_resource_path:
type: string
+ description: >-
+ Path to the MQTT resource containing broker connection
+ configuration
subscribe_topics:
type: array
items:
type: object
- properties: *ref_154
- required: *ref_155
+ properties: *ref_206
+ required: *ref_207
+ description: >-
+ Array of MQTT topics to subscribe to, each with topic name
+ and QoS level
v3_config:
+ description: MQTT v3 specific configuration (clean_session)
type: object
- properties: *ref_156
+ properties: *ref_208
v5_config:
+ description: >-
+ MQTT v5 specific configuration (clean_start,
+ topic_alias_maximum, session_expiry_interval)
type: object
- properties: *ref_157
+ properties: *ref_209
client_id:
type: string
+ description: MQTT client ID for this connection
client_version:
+ description: MQTT protocol version ('v3' or 'v5')
type: string
- enum: *ref_158
+ enum: *ref_210
server_id:
type: string
+ description: >-
+ ID of the server currently handling this trigger
+ (internal)
last_server_ping:
type: string
format: date-time
+ description: Timestamp of last server heartbeat (internal)
error:
type: string
- enabled:
- type: boolean
+ description: Last error message if the trigger failed
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_161
- - enabled
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_213
- subscribe_topics
- mqtt_resource_path
/w/{workspace}/mqtt_triggers/list:
@@ -15467,15 +22040,15 @@ paths:
- required: true
name: workspace
in: path
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: path
description: filter by path
in: query
@@ -15497,10 +22070,10 @@ paths:
schema:
type: array
items:
- allOf: *ref_159
+ allOf: *ref_211
type: object
- properties: *ref_160
- required: *ref_161
+ properties: *ref_212
+ required: *ref_213
/w/{workspace}/mqtt_triggers/exists/{path}:
get:
summary: does mqtt trigger exists
@@ -15511,11 +22084,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: mqtt trigger exists
@@ -15523,21 +22096,21 @@ paths:
application/json:
schema:
type: boolean
- /w/{workspace}/mqtt_triggers/setenabled/{path}:
+ /w/{workspace}/mqtt_triggers/setmode/{path}:
post:
summary: set enabled mqtt trigger
- operationId: setMqttTriggerEnabled
+ operationId: setMqttTriggerMode
tags:
- mqtt_trigger
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated mqtt trigger enable
required: true
@@ -15546,10 +22119,12 @@ paths:
schema:
type: object
properties:
- enabled:
- type: boolean
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
required:
- - enabled
+ - mode
responses:
'200':
description: mqtt trigger enabled set
@@ -15567,7 +22142,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: test mqtt connection
required: true
@@ -15597,7 +22172,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new gcp trigger
required: true
@@ -15605,12 +22180,16 @@ paths:
application/json:
schema:
type: object
- properties: &ref_162
+ description: Data for creating or updating a Google Cloud Pub/Sub trigger.
+ properties: &ref_214
gcp_resource_path:
type: string
+ description: >-
+ Path to the GCP resource containing service account
+ credentials for authentication.
subscription_mode:
type: string
- enum: &ref_167
+ enum: &ref_219
- existing
- create_update
description: >-
@@ -15619,45 +22198,84 @@ paths:
updating a new subscription.
topic_id:
type: string
+ description: Google Cloud Pub/Sub topic ID to subscribe to.
subscription_id:
type: string
+ description: Google Cloud Pub/Sub subscription ID.
base_endpoint:
type: string
+ description: Base URL for push delivery endpoint.
delivery_type:
type: string
- enum: &ref_164
+ enum: &ref_216
- push
- pull
+ description: >-
+ Delivery mode for messages. 'push' for HTTP push delivery
+ where messages are sent to a webhook endpoint, 'pull' for
+ polling where the trigger actively fetches messages.
delivery_config:
type: object
- properties: &ref_165
+ description: Configuration for push delivery mode.
+ properties: &ref_217
audience:
type: string
+ description: >-
+ The audience claim for OIDC tokens used in push
+ authentication.
authenticate:
type: boolean
- required: &ref_166
+ description: >-
+ If true, push messages will include OIDC authentication
+ tokens.
+ required: &ref_218
- authenticate
- base_endpoint
path:
type: string
+ description: The unique path identifier for this trigger.
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when a message is
+ received.
is_flow:
type: boolean
- enabled:
- type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script.
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
auto_acknowledge_msg:
type: boolean
+ description: >-
+ If true, automatically acknowledge messages after
+ processing.
+ ack_deadline:
+ type: integer
+ format: int32
+ minimum: 10
+ maximum: 600
+ description: >-
+ Time in seconds within which the message must be
+ acknowledged. If not provided, defaults to the
+ subscription's acknowledgment deadline (600 seconds).
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails.
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_163
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_215
- path
- script_path
- is_flow
@@ -15681,11 +22299,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated trigger
required: true
@@ -15693,8 +22311,9 @@ paths:
application/json:
schema:
type: object
- properties: *ref_162
- required: *ref_163
+ description: Data for creating or updating a Google Cloud Pub/Sub trigger.
+ properties: *ref_214
+ required: *ref_215
responses:
'200':
description: gcp trigger updated
@@ -15712,11 +22331,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: gcp trigger deleted
@@ -15734,41 +22353,57 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: gcp trigger deleted
content:
application/json:
schema:
- allOf: &ref_168
+ allOf: &ref_220
- type: object
- properties: *ref_139
- required: *ref_140
+ properties: *ref_184
+ required: *ref_185
type: object
- properties: &ref_169
+ description: >-
+ A Google Cloud Pub/Sub trigger that executes a script or flow
+ when messages are received.
+ properties: &ref_221
gcp_resource_path:
type: string
+ description: >-
+ Path to the GCP resource containing service account
+ credentials for authentication.
topic_id:
type: string
+ description: Google Cloud Pub/Sub topic ID to subscribe to.
subscription_id:
type: string
+ description: Google Cloud Pub/Sub subscription ID.
server_id:
type: string
+ description: >-
+ ID of the server currently handling this trigger (internal
+ use).
delivery_type:
type: string
- enum: *ref_164
+ enum: *ref_216
+ description: >-
+ Delivery mode for messages. 'push' for HTTP push delivery
+ where messages are sent to a webhook endpoint, 'pull' for
+ polling where the trigger actively fetches messages.
delivery_config:
type: object
- properties: *ref_165
- required: *ref_166
+ description: Configuration for push delivery mode.
+ properties: *ref_217
+ required: *ref_218
subscription_mode:
type: string
- enum: *ref_167
+ enum: *ref_219
description: >-
The mode of subscription. 'existing' means using an
existing GCP subscription, while 'create_update' involves
@@ -15776,24 +22411,27 @@ paths:
last_server_ping:
type: string
format: date-time
+ description: Timestamp of last server heartbeat (internal use).
error:
type: string
- enabled:
- type: boolean
+ description: Last error message if the trigger failed.
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails.
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_170
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_222
- gcp_resource_path
- topic_id
- subscription_id
- - enabled
- delivery_type
- subscription_mode
/w/{workspace}/gcp_triggers/list:
@@ -15806,15 +22444,15 @@ paths:
- required: true
name: workspace
in: path
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: path
description: filter by path
in: query
@@ -15836,10 +22474,13 @@ paths:
schema:
type: array
items:
- allOf: *ref_168
+ allOf: *ref_220
type: object
- properties: *ref_169
- required: *ref_170
+ description: >-
+ A Google Cloud Pub/Sub trigger that executes a script or
+ flow when messages are received.
+ properties: *ref_221
+ required: *ref_222
/w/{workspace}/gcp_triggers/exists/{path}:
get:
summary: does gcp trigger exists
@@ -15850,11 +22491,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: gcp trigger exists
@@ -15862,21 +22503,21 @@ paths:
application/json:
schema:
type: boolean
- /w/{workspace}/gcp_triggers/setenabled/{path}:
+ /w/{workspace}/gcp_triggers/setmode/{path}:
post:
summary: set enabled gcp trigger
- operationId: setGcpTriggerEnabled
+ operationId: setGcpTriggerMode
tags:
- gcp_trigger
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated gcp trigger enable
required: true
@@ -15885,10 +22526,12 @@ paths:
schema:
type: object
properties:
- enabled:
- type: boolean
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
required:
- - enabled
+ - mode
responses:
'200':
description: gcp trigger enabled set
@@ -15906,7 +22549,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: test gcp connection
required: true
@@ -15936,11 +22579,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: args to delete subscription from google cloud
required: true
@@ -15948,10 +22591,10 @@ paths:
application/json:
schema:
type: object
- properties: &ref_300
+ properties: &ref_405
subscription_id:
type: string
- required: &ref_301
+ required: &ref_406
- subscription_id
responses:
'200':
@@ -15970,11 +22613,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: get all google topics
@@ -15994,11 +22637,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: args to get subscription's topic from google cloud
required: true
@@ -16006,10 +22649,10 @@ paths:
application/json:
schema:
type: object
- properties: &ref_298
+ properties: &ref_403
topic_id:
type: string
- required: &ref_299
+ required: &ref_404
- topic_id
responses:
'200':
@@ -16030,11 +22673,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: postgres version
@@ -16052,11 +22695,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: boolean that indicates if postgres is set to logical level or not
@@ -16074,7 +22717,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: template script
required: true
@@ -16082,19 +22725,19 @@ paths:
application/json:
schema:
type: object
- properties: &ref_309
+ properties: &ref_415
postgres_resource_path:
type: string
relations:
type: array
items:
type: object
- properties: &ref_172
+ properties: &ref_224
schema_name:
type: string
table_to_track:
type: array
- items: &ref_307
+ items: &ref_413
type: object
properties:
table_name:
@@ -16107,14 +22750,14 @@ paths:
type: string
required:
- table_name
- required: &ref_173
+ required: &ref_225
- schema_name
- table_to_track
language:
type: string
- enum: &ref_308
+ enum: &ref_414
- Typescript
- required: &ref_310
+ required: &ref_416
- postgres_resource_path
- relations
- language
@@ -16135,11 +22778,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: &ref_205
+ schema: &ref_265
type: string
responses:
'200':
@@ -16158,11 +22801,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: list postgres slot
@@ -16172,7 +22815,7 @@ paths:
type: array
items:
type: object
- properties: &ref_306
+ properties: &ref_412
slot_name:
type: string
active:
@@ -16187,11 +22830,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: new slot for postgres
required: true
@@ -16199,7 +22842,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_171
+ properties: &ref_223
name:
type: string
responses:
@@ -16219,11 +22862,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: replication slot of postgres
required: true
@@ -16231,7 +22874,7 @@ paths:
application/json:
schema:
type: object
- properties: *ref_171
+ properties: *ref_223
responses:
'200':
description: postgres replication slot deleted
@@ -16249,11 +22892,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: database publication list
@@ -16273,16 +22916,16 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: publication
in: path
required: true
description: The name of the publication
- schema: &ref_174
+ schema: &ref_226
type: string
responses:
'200':
@@ -16291,18 +22934,18 @@ paths:
application/json:
schema:
type: object
- properties: &ref_175
+ properties: &ref_227
table_to_track:
type: array
items:
type: object
- properties: *ref_172
- required: *ref_173
+ properties: *ref_224
+ required: *ref_225
transaction_to_track:
type: array
items:
type: string
- required: &ref_176
+ required: &ref_228
- transaction_to_track
/w/{workspace}/postgres_triggers/publication/create/{publication}/{path}:
post:
@@ -16314,16 +22957,16 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: publication
in: path
required: true
description: The name of the publication
- schema: *ref_174
+ schema: *ref_226
requestBody:
description: new publication for postgres
required: true
@@ -16331,8 +22974,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_175
- required: *ref_176
+ properties: *ref_227
+ required: *ref_228
responses:
'201':
description: publication created
@@ -16350,16 +22993,16 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: publication
in: path
required: true
description: The name of the publication
- schema: *ref_174
+ schema: *ref_226
requestBody:
description: update publication for postgres
required: true
@@ -16367,8 +23010,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_175
- required: *ref_176
+ properties: *ref_227
+ required: *ref_228
responses:
'201':
description: publication updated
@@ -16386,16 +23029,16 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: publication
in: path
required: true
description: The name of the publication
- schema: *ref_174
+ schema: *ref_226
responses:
'200':
description: postgres publication deleted
@@ -16413,7 +23056,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: new postgres trigger
required: true
@@ -16421,35 +23064,56 @@ paths:
application/json:
schema:
type: object
- properties: &ref_311
+ properties: &ref_417
replication_slot_name:
type: string
+ description: Name of the PostgreSQL logical replication slot to use
publication_name:
type: string
+ description: >-
+ Name of the PostgreSQL publication to subscribe to for
+ change data capture
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when database changes
+ are detected
is_flow:
type: boolean
- enabled:
- type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
postgres_resource_path:
type: string
+ description: >-
+ Path to the PostgreSQL resource containing connection
+ configuration
publication:
+ description: >-
+ Configuration for creating/managing the publication (tables,
+ operations)
type: object
- properties: *ref_175
- required: *ref_176
+ properties: *ref_227
+ required: *ref_228
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_312
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_418
- path
- script_path
- is_flow
@@ -16472,11 +23136,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated trigger
required: true
@@ -16484,35 +23148,56 @@ paths:
application/json:
schema:
type: object
- properties: &ref_313
+ properties: &ref_419
replication_slot_name:
type: string
+ description: Name of the PostgreSQL logical replication slot to use
publication_name:
type: string
+ description: >-
+ Name of the PostgreSQL publication to subscribe to for
+ change data capture
path:
type: string
+ description: The unique path identifier for this trigger
script_path:
type: string
+ description: >-
+ Path to the script or flow to execute when database changes
+ are detected
is_flow:
type: boolean
- enabled:
- type: boolean
+ description: >-
+ True if script_path points to a flow, false if it points to
+ a script
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
postgres_resource_path:
type: string
+ description: >-
+ Path to the PostgreSQL resource containing connection
+ configuration
publication:
+ description: >-
+ Configuration for creating/managing the publication (tables,
+ operations)
type: object
- properties: *ref_175
- required: *ref_176
+ properties: *ref_227
+ required: *ref_228
error_handler_path:
type: string
+ description: Path to a script or flow to run when the triggered job fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_314
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_420
- path
- script_path
- is_flow
@@ -16537,11 +23222,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: postgres trigger deleted
@@ -16559,49 +23244,62 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: get postgres trigger
content:
application/json:
schema:
- allOf: &ref_177
+ allOf: &ref_229
- type: object
- properties: *ref_139
- required: *ref_140
+ properties: *ref_184
+ required: *ref_185
type: object
- properties: &ref_178
- enabled:
- type: boolean
+ properties: &ref_230
postgres_resource_path:
type: string
+ description: >-
+ Path to the PostgreSQL resource containing connection
+ configuration
publication_name:
type: string
+ description: >-
+ Name of the PostgreSQL publication to subscribe to for
+ change data capture
server_id:
type: string
+ description: >-
+ ID of the server currently handling this trigger
+ (internal)
replication_slot_name:
type: string
+ description: Name of the PostgreSQL logical replication slot to use
error:
type: string
+ description: Last error message if the trigger failed
last_server_ping:
type: string
format: date-time
+ description: Timestamp of last server heartbeat (internal)
error_handler_path:
type: string
+ description: >-
+ Path to a script or flow to run when the triggered job
+ fails
error_handler_args:
- type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
- retry:
type: object
- properties: *ref_127
- required: &ref_179
- - enabled
+ additionalProperties: true
+ retry:
+ description: Retry configuration for failed module executions
+ type: object
+ properties: *ref_169
+ required: &ref_231
- postgres_resource_path
- replication_slot_name
- publication_name
@@ -16615,15 +23313,15 @@ paths:
- required: true
name: workspace
in: path
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: path
description: filter by path
in: query
@@ -16645,10 +23343,10 @@ paths:
schema:
type: array
items:
- allOf: *ref_177
+ allOf: *ref_229
type: object
- properties: *ref_178
- required: *ref_179
+ properties: *ref_230
+ required: *ref_231
/w/{workspace}/postgres_triggers/exists/{path}:
get:
summary: does postgres trigger exists
@@ -16659,11 +23357,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: postgres trigger exists
@@ -16671,21 +23369,21 @@ paths:
application/json:
schema:
type: boolean
- /w/{workspace}/postgres_triggers/setenabled/{path}:
+ /w/{workspace}/postgres_triggers/setmode/{path}:
post:
summary: set enabled postgres trigger
- operationId: setPostgresTriggerEnabled
+ operationId: setPostgresTriggerMode
tags:
- postgres_trigger
parameters:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: updated postgres trigger enable
required: true
@@ -16694,10 +23392,12 @@ paths:
schema:
type: object
properties:
- enabled:
- type: boolean
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
required:
- - enabled
+ - mode
responses:
'200':
description: postgres trigger enabled set
@@ -16715,7 +23415,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: test postgres connection
required: true
@@ -16735,6 +23435,315 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/email_triggers/create:
+ post:
+ summary: create email trigger
+ operationId: createEmailTrigger
+ tags:
+ - email_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: new email trigger
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: &ref_429
+ path:
+ type: string
+ script_path:
+ type: string
+ local_part:
+ type: string
+ workspaced_local_part:
+ type: boolean
+ is_flow:
+ type: boolean
+ error_handler_path:
+ type: string
+ error_handler_args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ retry:
+ type: object
+ description: Retry configuration for failed module executions
+ properties: *ref_169
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
+ required: &ref_430
+ - path
+ - script_path
+ - local_part
+ - is_flow
+ responses:
+ '201':
+ description: email trigger created
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/email_triggers/update/{path}:
+ post:
+ summary: update email trigger
+ operationId: updateEmailTrigger
+ tags:
+ - email_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_48
+ requestBody:
+ description: updated trigger
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: &ref_431
+ path:
+ type: string
+ script_path:
+ type: string
+ local_part:
+ type: string
+ workspaced_local_part:
+ type: boolean
+ is_flow:
+ type: boolean
+ error_handler_path:
+ type: string
+ error_handler_args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ retry:
+ type: object
+ description: Retry configuration for failed module executions
+ properties: *ref_169
+ required: &ref_432
+ - path
+ - script_path
+ - is_flow
+ responses:
+ '200':
+ description: email trigger updated
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/email_triggers/delete/{path}:
+ delete:
+ summary: delete email trigger
+ operationId: deleteEmailTrigger
+ tags:
+ - email_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_48
+ responses:
+ '200':
+ description: email trigger deleted
+ content:
+ text/plain:
+ schema:
+ type: string
+ /w/{workspace}/email_triggers/get/{path}:
+ get:
+ summary: get email trigger
+ operationId: getEmailTrigger
+ tags:
+ - email_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_48
+ responses:
+ '200':
+ description: email trigger retrieved
+ content:
+ application/json:
+ schema:
+ allOf: &ref_232
+ - type: object
+ properties: *ref_184
+ required: *ref_185
+ type: object
+ properties: &ref_233
+ local_part:
+ type: string
+ workspaced_local_part:
+ type: boolean
+ error_handler_path:
+ type: string
+ error_handler_args:
+ type: object
+ description: The arguments to pass to the script or flow
+ additionalProperties: true
+ retry:
+ type: object
+ description: Retry configuration for failed module executions
+ properties: *ref_169
+ required: &ref_234
+ - local_part
+ /w/{workspace}/email_triggers/list:
+ get:
+ summary: list email triggers
+ operationId: listEmailTriggers
+ tags:
+ - email_trigger
+ parameters:
+ - required: true
+ name: workspace
+ in: path
+ schema: *ref_4
+ - name: page
+ description: which page to return (start at 1, default 1)
+ in: query
+ schema: *ref_13
+ - name: per_page
+ description: number of items to return for a given page (default 30, max 100)
+ in: query
+ schema: *ref_14
+ - name: path
+ description: filter by path
+ in: query
+ schema:
+ type: string
+ - name: is_flow
+ in: query
+ schema:
+ type: boolean
+ - name: path_start
+ in: query
+ schema:
+ type: string
+ responses:
+ '200':
+ description: email trigger list
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ allOf: *ref_232
+ type: object
+ properties: *ref_233
+ required: *ref_234
+ /w/{workspace}/email_triggers/exists/{path}:
+ get:
+ summary: does email trigger exists
+ operationId: existsEmailTrigger
+ tags:
+ - email_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_48
+ responses:
+ '200':
+ description: email trigger exists
+ content:
+ application/json:
+ schema:
+ type: boolean
+ /w/{workspace}/email_triggers/local_part_exists:
+ post:
+ summary: does email local part exists
+ operationId: existsEmailLocalPart
+ tags:
+ - email_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ requestBody:
+ description: email local part exists request
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ local_part:
+ type: string
+ workspaced_local_part:
+ type: boolean
+ trigger_path:
+ type: string
+ required:
+ - local_part
+ responses:
+ '200':
+ description: email local part exists
+ content:
+ application/json:
+ schema:
+ type: boolean
+ /w/{workspace}/email_triggers/setmode/{path}:
+ post:
+ summary: enable/disable email trigger
+ operationId: setEmailTriggerMode
+ tags:
+ - email_trigger
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: path
+ in: path
+ required: true
+ schema: *ref_48
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ mode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
+ required:
+ - mode
+ responses:
+ '200':
+ description: email trigger enable/disable
+ content:
+ text/plain:
+ schema:
+ type: string
/groups/list:
get:
summary: list instance groups
@@ -16750,7 +23759,9 @@ paths:
type: array
items:
type: object
- properties: &ref_181
+ required: &ref_236
+ - name
+ properties: &ref_237
name:
type: string
summary:
@@ -16759,8 +23770,45 @@ paths:
type: array
items:
type: string
- required: &ref_182
+ /groups/list_with_workspaces:
+ get:
+ summary: list instance groups with workspace information
+ operationId: listInstanceGroupsWithWorkspaces
+ tags:
+ - group
+ responses:
+ '200':
+ description: instance group list with workspaces
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ required: &ref_433
- name
+ properties: &ref_434
+ name:
+ type: string
+ summary:
+ type: string
+ emails:
+ type: array
+ items:
+ type: string
+ workspaces:
+ type: array
+ items:
+ type: object
+ properties: &ref_435
+ workspace_id:
+ type: string
+ workspace_name:
+ type: string
+ role:
+ type: string
+ required: &ref_436
+ - name
/groups/get/{name}:
get:
summary: get instance group
@@ -16771,7 +23819,7 @@ paths:
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: instance group
@@ -16779,8 +23827,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_181
- required: *ref_182
+ required: *ref_236
+ properties: *ref_237
/groups/create:
post:
summary: create instance group
@@ -16818,7 +23866,7 @@ paths:
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: update instance group
required: true
@@ -16848,7 +23896,7 @@ paths:
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: instance group deleted
@@ -16866,7 +23914,7 @@ paths:
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: user to add to instance group
required: true
@@ -16896,7 +23944,7 @@ paths:
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: user to remove from instance group
required: true
@@ -16931,7 +23979,7 @@ paths:
type: array
items:
type: object
- properties: &ref_183
+ properties: &ref_238
name:
type: string
summary:
@@ -16946,7 +23994,7 @@ paths:
type: string
external_id:
type: string
- required: &ref_184
+ required: &ref_239
- name
/groups/overwrite:
post:
@@ -16963,8 +24011,8 @@ paths:
type: array
items:
type: object
- properties: *ref_183
- required: *ref_184
+ properties: *ref_238
+ required: *ref_239
responses:
'200':
description: success message
@@ -16982,15 +24030,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
responses:
'200':
description: group list
@@ -17000,7 +24048,7 @@ paths:
type: array
items:
type: object
- properties: &ref_185
+ properties: &ref_240
name:
type: string
summary:
@@ -17013,7 +24061,7 @@ paths:
type: object
additionalProperties:
type: boolean
- required: &ref_186
+ required: &ref_241
- name
/w/{workspace}/groups/listnames:
get:
@@ -17025,7 +24073,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: only_member_of
in: query
description: only list the groups the user is member of (default false)
@@ -17050,7 +24098,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: create group
required: true
@@ -17082,11 +24130,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: updated group
required: true
@@ -17114,11 +24162,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: group deleted
@@ -17136,11 +24184,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: group
@@ -17148,8 +24196,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_185
- required: *ref_186
+ properties: *ref_240
+ required: *ref_241
/w/{workspace}/groups/adduser/{name}:
post:
summary: add user to group
@@ -17160,11 +24208,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: added user to group
required: true
@@ -17192,11 +24240,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: added user to group
required: true
@@ -17214,6 +24262,51 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/groups_history/get/{name}:
+ get:
+ summary: get group permission history
+ operationId: getGroupPermissionHistory
+ tags:
+ - group
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: name
+ in: path
+ required: true
+ schema: *ref_235
+ - name: page
+ description: which page to return (start at 1, default 1)
+ in: query
+ schema: *ref_13
+ - name: per_page
+ description: number of items to return for a given page (default 30, max 100)
+ in: query
+ schema: *ref_14
+ responses:
+ '200':
+ description: group permission history
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ id:
+ type: integer
+ changed_by:
+ type: string
+ changed_at:
+ type: string
+ format: date-time
+ change_type:
+ type: string
+ member_affected:
+ type: string
+ nullable: true
/w/{workspace}/folders/list:
get:
summary: list folders
@@ -17224,15 +24317,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
responses:
'200':
description: folder list
@@ -17242,7 +24335,7 @@ paths:
type: array
items:
type: object
- properties: &ref_187
+ properties: &ref_242
name:
type: string
owners:
@@ -17260,7 +24353,7 @@ paths:
edited_at:
type: string
format: date-time
- required: &ref_188
+ required: &ref_243
- name
- owners
- extra_perms
@@ -17274,7 +24367,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: only_member_of
in: query
description: only list the folders the user is member of (default false)
@@ -17299,7 +24392,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: create folder
required: true
@@ -17338,11 +24431,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: update folder
required: true
@@ -17377,11 +24470,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: folder deleted
@@ -17399,11 +24492,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: folder
@@ -17411,8 +24504,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_187
- required: *ref_188
+ properties: *ref_242
+ required: *ref_243
/w/{workspace}/folders/exists/{name}:
get:
summary: exists folder
@@ -17423,11 +24516,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: folder exists
@@ -17445,11 +24538,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: folder
@@ -17487,11 +24580,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: owner user to folder
required: true
@@ -17521,11 +24614,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: added owner to folder
required: true
@@ -17547,6 +24640,51 @@ paths:
text/plain:
schema:
type: string
+ /w/{workspace}/folders_history/get/{name}:
+ get:
+ summary: get folder permission history
+ operationId: getFolderPermissionHistory
+ tags:
+ - folder
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: name
+ in: path
+ required: true
+ schema: *ref_235
+ - name: page
+ description: which page to return (start at 1, default 1)
+ in: query
+ schema: *ref_13
+ - name: per_page
+ description: number of items to return for a given page (default 30, max 100)
+ in: query
+ schema: *ref_14
+ responses:
+ '200':
+ description: folder permission history
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ id:
+ type: integer
+ changed_by:
+ type: string
+ changed_at:
+ type: string
+ format: date-time
+ change_type:
+ type: string
+ affected:
+ type: string
+ nullable: true
/workers/list:
get:
summary: list workers
@@ -17558,11 +24696,11 @@ paths:
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: ping_since
in: query
required: false
@@ -17580,7 +24718,7 @@ paths:
type: array
items:
type: object
- properties: &ref_323
+ properties: &ref_437
worker:
type: string
worker_instance:
@@ -17622,7 +24760,9 @@ paths:
type: number
wm_memory_usage:
type: number
- required: &ref_324
+ job_isolation:
+ type: string
+ required: &ref_438
- worker
- worker_instance
- ping_at
@@ -17631,25 +24771,36 @@ paths:
- jobs_executed
- worker_group
- wm_version
- /workers/exists_worker_with_tag:
+ /workers/exists_workers_with_tags:
get:
- summary: exists worker with tag
- operationId: existsWorkerWithTag
+ summary: exists workers with tags
+ operationId: existsWorkersWithTags
tags:
- worker
parameters:
- - name: tag
+ - name: tags
in: query
required: true
+ description: comma separated list of tags
+ schema:
+ type: string
+ - name: workspace
+ in: query
+ required: false
+ description: >-
+ workspace to filter tags visibility (required when
+ TAGS_ARE_SENSITIVE is enabled for non-superadmins)
schema:
type: string
responses:
'200':
- description: whether a worker with the tag exists
+ description: map of tags to whether at least one worker with the tag exists
content:
application/json:
schema:
- type: boolean
+ type: object
+ additionalProperties:
+ type: boolean
/workers/queue_metrics:
get:
summary: get queue metrics
@@ -17698,6 +24849,21 @@ paths:
type: object
additionalProperties:
type: integer
+ /workers/queue_running_counts:
+ get:
+ summary: get counts of currently running jobs per tag
+ operationId: getCountsOfRunningJobsPerTag
+ tags:
+ - worker
+ responses:
+ '200':
+ description: queue running counts
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
/configs/list_worker_groups:
get:
summary: list worker groups
@@ -17730,7 +24896,7 @@ paths:
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: a config
@@ -17739,12 +24905,12 @@ paths:
schema:
type: object
nullable: true
- properties: &ref_242
+ properties: &ref_344
alerts:
type: array
items:
type: object
- properties: &ref_240
+ properties: &ref_342
name:
type: string
tags_to_monitor:
@@ -17757,7 +24923,7 @@ paths:
type: integer
alert_time_threshold_seconds:
type: integer
- required: &ref_241
+ required: &ref_343
- name
- tags_to_monitor
- jobs_num_threshold
@@ -17773,7 +24939,7 @@ paths:
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
requestBody:
description: worker group
required: true
@@ -17796,7 +24962,7 @@ paths:
- name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
responses:
'200':
description: Delete config
@@ -17819,12 +24985,12 @@ paths:
type: array
items:
type: object
- properties: &ref_365
+ properties: &ref_483
name:
type: string
config:
type: object
- required: &ref_366
+ required: &ref_484
- name
/configs/list_autoscaling_events/{worker_group}:
get:
@@ -17838,6 +25004,14 @@ paths:
required: true
schema:
type: string
+ - name: page
+ description: which page to return (start at 1, default 1)
+ in: query
+ schema: *ref_13
+ - name: per_page
+ description: number of items to return for a given page (default 30, max 100)
+ in: query
+ schema: *ref_14
responses:
'200':
description: List of autoscaling events
@@ -17847,7 +25021,7 @@ paths:
type: array
items:
type: object
- properties: &ref_369
+ properties: &ref_487
id:
type: integer
format: int64
@@ -17862,6 +25036,21 @@ paths:
applied_at:
type: string
format: date-time
+ /configs/native_kubernetes_autoscaling_healthcheck:
+ get:
+ summary: Check Kubernetes autoscaling health for a worker group
+ operationId: nativeKubernetesAutoscalingHealthcheck
+ tags:
+ - config
+ responses:
+ '200':
+ description: Kubernetes autoscaling is healthy
+ '400':
+ description: Error
+ content:
+ text/plain:
+ schema:
+ type: string
/configs/list_available_python_versions:
get:
summary: Get currently available python versions provided by UV.
@@ -18000,6 +25189,20 @@ paths:
- expires_at
- blacklisted_at
- blacklisted_by
+ /agent_workers/get_min_version:
+ get:
+ summary: get minimum worker version across all workers
+ operationId: getMinVersion
+ tags:
+ - agent_workers
+ responses:
+ '200':
+ description: minimum worker version
+ content:
+ application/json:
+ schema:
+ type: string
+ description: Minimum semantic version across all workers (e.g. "1.583.0")
/w/{workspace}/acls/get/{kind}/{path}:
get:
summary: get granular acls
@@ -18010,11 +25213,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: kind
in: path
required: true
@@ -18038,6 +25241,7 @@ paths:
- mqtt_trigger
- gcp_trigger
- sqs_trigger
+ - email_trigger
responses:
'200':
description: acls
@@ -18057,11 +25261,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: kind
in: path
required: true
@@ -18085,6 +25289,7 @@ paths:
- mqtt_trigger
- gcp_trigger
- sqs_trigger
+ - email_trigger
requestBody:
description: acl to add
required: true
@@ -18116,11 +25321,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: kind
in: path
required: true
@@ -18144,6 +25349,7 @@ paths:
- mqtt_trigger
- gcp_trigger
- sqs_trigger
+ - email_trigger
requestBody:
description: acl to add
required: true
@@ -18173,7 +25379,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: capture config
required: true
@@ -18184,17 +25390,18 @@ paths:
properties:
trigger_kind:
type: string
- enum: &ref_189
+ enum: &ref_244
- webhook
- http
- websocket
- kafka
- - email
+ - default_email
- nats
- postgres
- sqs
- mqtt
- gcp
+ - email
path:
type: string
is_flow:
@@ -18222,21 +25429,21 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: trigger_kind
in: path
required: true
schema:
type: string
- enum: *ref_189
+ enum: *ref_244
- name: runnable_kind
in: path
required: true
- schema: *ref_80
+ schema: *ref_110
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: capture config pinged
@@ -18250,15 +25457,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: runnable_kind
in: path
required: true
- schema: *ref_80
+ schema: *ref_110
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: capture configs for a script or flow
@@ -18268,17 +25475,17 @@ paths:
type: array
items:
type: object
- properties: &ref_370
+ properties: &ref_488
trigger_config: {}
trigger_kind:
type: string
- enum: *ref_189
+ enum: *ref_244
error:
type: string
last_server_ping:
type: string
format: date-time
- required: &ref_371
+ required: &ref_489
- trigger_kind
/w/{workspace}/capture/list/{runnable_kind}/{path}:
get:
@@ -18290,28 +25497,28 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: runnable_kind
in: path
required: true
- schema: *ref_80
+ schema: *ref_110
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: trigger_kind
in: query
schema:
type: string
- enum: *ref_189
+ enum: *ref_244
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
responses:
'200':
description: list of captures for a script or flow
@@ -18321,10 +25528,10 @@ paths:
type: array
items:
type: object
- properties: &ref_190
+ properties: &ref_245
trigger_kind:
type: string
- enum: *ref_189
+ enum: *ref_244
main_args: {}
preprocessor_args: {}
id:
@@ -18332,7 +25539,7 @@ paths:
created_at:
type: string
format: date-time
- required: &ref_191
+ required: &ref_246
- trigger_kind
- main_args
- preprocessor_args
@@ -18348,15 +25555,15 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: runnable_kind
in: path
required: true
- schema: *ref_80
+ schema: *ref_110
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
requestBody:
description: move captures and configs to a new path
required: true
@@ -18384,7 +25591,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
@@ -18397,8 +25604,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_190
- required: *ref_191
+ properties: *ref_245
+ required: *ref_246
delete:
summary: delete a capture
operationId: deleteCapture
@@ -18408,7 +25615,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
@@ -18427,7 +25634,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
content:
application/json:
@@ -18443,6 +25650,7 @@ paths:
- app
- script
- raw_app
+ - asset
responses:
'200':
description: star item
@@ -18456,7 +25664,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
content:
application/json:
@@ -18472,6 +25680,7 @@ paths:
- app
- script
- raw_app
+ - asset
responses:
'200':
description: unstar item
@@ -18485,33 +25694,33 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: runnable_id
in: query
- schema: &ref_192
+ schema: &ref_247
type: string
- name: runnable_type
in: query
- schema: &ref_193
+ schema: &ref_248
type: string
- enum: &ref_248
+ enum: &ref_352
- ScriptHash
- ScriptPath
- FlowPath
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
- name: args
description: >-
filter on jobs containing those args as a json subset (@> in
postgres)
in: query
- schema: *ref_105
+ schema: *ref_139
- name: include_preview
in: query
schema:
@@ -18525,7 +25734,7 @@ paths:
type: array
items:
type: object
- properties: &ref_194
+ properties: &ref_249
id:
type: string
name:
@@ -18539,7 +25748,7 @@ paths:
type: boolean
success:
type: boolean
- required: &ref_195
+ required: &ref_250
- id
- name
- args
@@ -18556,7 +25765,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: jobOrInputId
in: path
required: true
@@ -18586,21 +25795,21 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: runnable_id
in: query
- schema: *ref_192
+ schema: *ref_247
- name: runnable_type
in: query
- schema: *ref_193
+ schema: *ref_248
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
responses:
'200':
description: Saved Inputs for a Runnable
@@ -18610,8 +25819,8 @@ paths:
type: array
items:
type: object
- properties: *ref_194
- required: *ref_195
+ properties: *ref_249
+ required: *ref_250
/w/{workspace}/inputs/create:
post:
summary: Create an Input for future use in a script or flow
@@ -18622,13 +25831,13 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: runnable_id
in: query
- schema: *ref_192
+ schema: *ref_247
- name: runnable_type
in: query
- schema: *ref_193
+ schema: *ref_248
requestBody:
description: Input
required: true
@@ -18636,12 +25845,12 @@ paths:
application/json:
schema:
type: object
- properties: &ref_244
+ properties: &ref_348
name:
type: string
args:
type: object
- required: &ref_245
+ required: &ref_349
- name
- args
- created_by
@@ -18663,7 +25872,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: UpdateInput
required: true
@@ -18671,14 +25880,14 @@ paths:
application/json:
schema:
type: object
- properties: &ref_246
+ properties: &ref_350
id:
type: string
name:
type: string
is_public:
type: boolean
- required: &ref_247
+ required: &ref_351
- id
- name
- is_public
@@ -18700,11 +25909,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: input
in: path
required: true
- schema: &ref_213
+ schema: &ref_273
type: string
responses:
'200':
@@ -18726,7 +25935,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: S3 resource to connect to
required: true
@@ -18737,7 +25946,7 @@ paths:
properties:
s3_resource:
type: object
- properties: &ref_196
+ properties: &ref_251
bucket:
type: string
region:
@@ -18752,7 +25961,7 @@ paths:
type: string
pathStyle:
type: boolean
- required: &ref_197
+ required: &ref_252
- bucket
- region
- endPoint
@@ -18780,7 +25989,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: >-
S3 resource path to use to generate the connection settings. If empty,
@@ -18819,7 +26028,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: S3 resource to connect to
required: true
@@ -18830,8 +26039,8 @@ paths:
properties:
s3_resource:
type: object
- properties: *ref_196
- required: *ref_197
+ properties: *ref_251
+ required: *ref_252
responses:
'200':
description: Connection settings
@@ -18852,10 +26061,10 @@ paths:
type: boolean
client_kwargs:
type: object
- properties: &ref_198
+ properties: &ref_253
region_name:
type: string
- required: &ref_199
+ required: &ref_254
- region_name
required:
- endpoint_url
@@ -18874,7 +26083,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: >-
S3 resource path to use to generate the connection settings. If empty,
@@ -18910,8 +26119,8 @@ paths:
type: boolean
client_kwargs:
type: object
- properties: *ref_198
- required: *ref_199
+ properties: *ref_253
+ required: *ref_254
required:
- endpoint_url
- use_ssl
@@ -18949,7 +26158,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: >-
S3 resource path to use. If empty, the S3 resource defined in the
@@ -18969,8 +26178,8 @@ paths:
application/json:
schema:
type: object
- properties: *ref_196
- required: *ref_197
+ properties: *ref_251
+ required: *ref_252
/w/{workspace}/job_helpers/test_connection:
get:
summary: Test connection to the workspace object storage
@@ -18981,7 +26190,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: storage
in: query
schema:
@@ -19002,7 +26211,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: max_keys
in: query
required: true
@@ -19034,10 +26243,10 @@ paths:
type: array
items:
type: object
- properties: &ref_344
+ properties: &ref_255
s3:
type: string
- required: &ref_345
+ required: &ref_256
- s3
restricted_access:
type: boolean
@@ -19053,7 +26262,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: file_key
in: query
required: true
@@ -19070,7 +26279,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_346
+ properties: &ref_259
mime_type:
type: string
size_in_bytes:
@@ -19093,7 +26302,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: file_key
in: query
required: true
@@ -19134,7 +26343,7 @@ paths:
application/json:
schema:
type: object
- properties: &ref_347
+ properties: &ref_257
msg:
type: string
content:
@@ -19146,8 +26355,183 @@ paths:
- Csv
- Parquet
- Unknown
- required: &ref_348
+ required: &ref_258
- content_type
+ /w/{workspace}/job_helpers/list_git_repo_files:
+ get:
+ summary: >-
+ List the file keys available in instance object storage with
+ resource-based access control
+ operationId: listGitRepoFiles
+ tags:
+ - helpers
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: max_keys
+ in: query
+ required: true
+ schema:
+ type: integer
+ - name: marker
+ in: query
+ schema:
+ type: string
+ - name: prefix
+ in: query
+ required: false
+ schema:
+ type: string
+ description: Must follow format gitrepos/{workspace_id}/{resource_path}/...
+ - name: storage
+ in: query
+ schema:
+ type: string
+ responses:
+ '200':
+ description: List of file keys
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ next_marker:
+ type: string
+ windmill_large_files:
+ type: array
+ items:
+ type: object
+ properties: *ref_255
+ required: *ref_256
+ restricted_access:
+ type: boolean
+ required:
+ - windmill_large_files
+ /w/{workspace}/job_helpers/load_git_repo_file_preview:
+ get:
+ summary: >-
+ Load a preview of a file from instance storage with resource-based
+ access control
+ operationId: loadGitRepoFilePreview
+ tags:
+ - helpers
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: file_key
+ in: query
+ required: true
+ schema:
+ type: string
+ description: Must follow format gitrepos/{workspace_id}/{resource_path}/...
+ - name: file_size_in_bytes
+ in: query
+ schema:
+ type: integer
+ - name: file_mime_type
+ in: query
+ schema:
+ type: string
+ - name: csv_separator
+ in: query
+ schema:
+ type: string
+ - name: csv_has_header
+ in: query
+ schema:
+ type: boolean
+ - name: read_bytes_from
+ in: query
+ schema:
+ type: integer
+ - name: read_bytes_length
+ in: query
+ schema:
+ type: integer
+ - name: storage
+ in: query
+ schema:
+ type: string
+ responses:
+ '200':
+ description: FilePreview
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_257
+ required: *ref_258
+ /w/{workspace}/job_helpers/load_git_repo_file_metadata:
+ get:
+ summary: >-
+ Load file metadata from instance storage with resource-based access
+ control
+ operationId: loadGitRepoFileMetadata
+ tags:
+ - helpers
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: file_key
+ in: query
+ required: true
+ schema:
+ type: string
+ description: Must follow format gitrepos/{workspace_id}/{resource_path}/...
+ - name: storage
+ in: query
+ schema:
+ type: string
+ responses:
+ '200':
+ description: FileMetadata
+ content:
+ application/json:
+ schema:
+ type: object
+ properties: *ref_259
+ /w/{workspace}/job_helpers/check_s3_folder_exists:
+ get:
+ summary: Check if S3 path exists and is a folder
+ operationId: checkS3FolderExists
+ tags:
+ - helpers
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ - name: file_key
+ description: >-
+ S3 file key to check (e.g.,
+ gitrepos/{workspace_id}/u/user/resource/{commit_hash})
+ in: query
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: S3 folder existence check result
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ exists:
+ type: boolean
+ description: Whether the path exists
+ is_folder:
+ type: boolean
+ description: Whether the path is a folder (true) or file (false)
+ required:
+ - exists
+ - is_folder
/w/{workspace}/job_helpers/load_parquet_preview/{path}:
get:
summary: Load a preview of a parquet file
@@ -19158,11 +26542,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: offset
in: query
schema:
@@ -19206,11 +26590,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: search_col
in: query
schema:
@@ -19243,11 +26627,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
- name: offset
in: query
schema:
@@ -19295,7 +26679,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: file_key
in: query
required: true
@@ -19321,7 +26705,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: src_file_key
in: query
required: true
@@ -19352,7 +26736,70 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
+ - name: file_key
+ in: query
+ required: false
+ schema:
+ type: string
+ - name: file_extension
+ in: query
+ required: false
+ schema:
+ type: string
+ - name: s3_resource_path
+ in: query
+ required: false
+ schema:
+ type: string
+ - name: resource_type
+ in: query
+ required: false
+ schema:
+ type: string
+ - name: storage
+ in: query
+ schema:
+ type: string
+ - name: content_type
+ in: query
+ schema:
+ type: string
+ - name: content_disposition
+ in: query
+ schema:
+ type: string
+ requestBody:
+ description: File content
+ required: true
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ '200':
+ description: File upload status
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ file_key:
+ type: string
+ required:
+ - file_key
+ /w/{workspace}/job_helpers/upload_git_repo_file_to_instance_storage:
+ post:
+ summary: Upload a file to the instance storage gitrepos section for viewing
+ operationId: gitRepoViewerFileUpload
+ tags:
+ - helpers
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
- name: file_key
in: query
required: false
@@ -19415,7 +26862,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: file_key
in: query
required: true
@@ -19453,7 +26900,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: file_key
in: query
required: true
@@ -19486,11 +26933,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
requestBody:
description: parameters for statistics retrieval
required: true
@@ -19519,46 +26966,46 @@ paths:
type: array
items:
type: object
- properties: &ref_349
+ properties: &ref_467
id:
type: string
name:
type: string
- required: &ref_350
+ required: &ref_468
- id
scalar_metrics:
type: array
items:
type: object
- properties: &ref_351
+ properties: &ref_469
metric_id:
type: string
value:
type: number
- required: &ref_352
+ required: &ref_470
- id
- value
timeseries_metrics:
type: array
items:
type: object
- properties: &ref_353
+ properties: &ref_471
metric_id:
type: string
values:
type: array
items:
type: object
- properties: &ref_355
+ properties: &ref_473
timestamp:
type: string
format: date-time
value:
type: number
- required: &ref_356
+ required: &ref_474
- timestamp
- value
- required: &ref_354
+ required: &ref_472
- id
- values
/w/{workspace}/job_metrics/set_progress/{id}:
@@ -19571,11 +27018,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
requestBody:
description: parameters for statistics retrieval
required: true
@@ -19605,11 +27052,11 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
responses:
'200':
description: job progress between 0 and 99
@@ -19627,11 +27074,11 @@ paths:
- name: before
description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_200
+ schema: *ref_260
- name: after
description: filter on created after (exclusive) timestamp
in: query
- schema: *ref_201
+ schema: *ref_261
- name: with_error
in: query
required: false
@@ -19680,7 +27127,7 @@ paths:
- name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
responses:
'200':
description: log stream
@@ -19703,12 +27150,12 @@ paths:
type: array
items:
type: object
- properties: &ref_359
+ properties: &ref_477
concurrency_key:
type: string
total_running:
type: number
- required: &ref_360
+ required: &ref_478
- concurrency_key
- total_running
/concurrency_groups/prune/{concurrency_id}:
@@ -19721,7 +27168,7 @@ paths:
- name: concurrency_id
in: path
required: true
- schema: &ref_215
+ schema: &ref_275
type: string
responses:
'200':
@@ -19741,7 +27188,7 @@ paths:
- name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
responses:
'200':
description: concurrency key for given job
@@ -19770,109 +27217,110 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
- name: label
description: >-
mask to filter exact matching job's label (job labels are completed
jobs with as a result an object containing a string in the array at
key 'wm_labels')
in: query
- schema: *ref_110
+ schema: *ref_146
- name: parent_job
description: >-
The parent job that is at the origin and responsible for the
execution of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
- name: script_path_exact
description: mask to filter exact matching path
in: query
- schema: *ref_95
+ schema: *ref_129
- name: script_path_start
description: mask to filter matching starting path
in: query
- schema: *ref_96
+ schema: *ref_130
- name: schedule_path
description: mask to filter by schedule path
in: query
- schema: *ref_97
+ schema: *ref_131
- name: script_hash
description: mask to filter exact matching path
in: query
- schema: *ref_98
+ schema: *ref_132
- name: started_before
description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_99
+ schema: *ref_133
- name: started_after
description: filter on started after (exclusive) timestamp
in: query
- schema: *ref_100
- - name: created_or_started_before
- description: >-
- filter on created_at for non non started job and started_at
- otherwise before (inclusive) timestamp
- in: query
- schema: *ref_116
+ schema: *ref_134
- name: running
description: filter on running jobs
in: query
- schema: *ref_101
+ schema: *ref_135
- name: scheduled_for_before_now
description: filter on jobs scheduled_for before now (hence waitinf for a worker)
in: query
- schema: *ref_102
- - name: created_or_started_after
- description: >-
- filter on created_at for non non started job and started_at
- otherwise after (exclusive) timestamp
+ schema: *ref_136
+ - name: completed_before
+ description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_117
- - name: created_or_started_after_completed_jobs
- description: >-
- filter on created_at for non non started job and started_at
- otherwise after (exclusive) timestamp but only for the completed
- jobs
+ schema: *ref_156
+ - name: completed_after
+ description: filter on started after (exclusive) timestamp
in: query
- schema: *ref_118
+ schema: *ref_157
+ - name: created_before_queue
+ description: filter on jobs created before X for jobs in the queue only
+ in: query
+ schema: *ref_158
+ - name: created_after_queue
+ description: filter on jobs created after X for jobs in the queue only
+ in: query
+ schema: *ref_159
- name: job_kinds
description: >-
filter on job kind (values 'preview', 'script', 'dependencies',
'flow') separated by,
in: query
- schema: *ref_103
+ schema: *ref_137
- name: args
description: >-
filter on jobs containing those args as a json subset (@> in
postgres)
in: query
- schema: *ref_105
+ schema: *ref_139
- name: tag
description: filter on jobs with a given tag/worker group
in: query
- schema: *ref_106
+ schema: *ref_140
- name: result
description: >-
filter on jobs containing those result as a json subset (@> in
postgres)
in: query
- schema: *ref_107
+ schema: *ref_141
- name: allow_wildcards
description: allow wildcards (*) in the filter of label, tag, worker
in: query
- schema: *ref_109
+ schema: *ref_143
- name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
- name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
+ - name: trigger_kind
+ description: trigger kind (schedule, http, websocket...)
+ in: query
+ schema: *ref_160
- name: is_skipped
description: is the job skipped
in: query
@@ -19912,17 +27360,17 @@ paths:
application/json:
schema:
type: object
- properties: &ref_361
+ properties: &ref_479
jobs:
type: array
items:
- oneOf: *ref_124
- discriminator: *ref_125
+ oneOf: *ref_165
+ discriminator: *ref_166
obscured_jobs:
type: array
items:
type: object
- properties: &ref_249
+ properties: &ref_353
typ:
type: string
started_at:
@@ -19935,7 +27383,7 @@ paths:
Obscured jobs omitted for security because of too specific
filtering
type: boolean
- required: &ref_362
+ required: &ref_480
- jobs
- obscured_jobs
/srch/w/{workspace}/index/search/job:
@@ -19948,7 +27396,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
- name: search_query
in: query
required: true
@@ -19979,7 +27427,7 @@ paths:
type: array
items:
type: object
- properties: &ref_367
+ properties: &ref_485
dancer:
type: string
hit_count:
@@ -20055,7 +27503,7 @@ paths:
type: array
items:
type: object
- properties: &ref_368
+ properties: &ref_486
dancer:
type: string
/srch/index/search/count_service_logs:
@@ -20124,7 +27572,7 @@ paths:
type: string
/w/{workspace}/assets/list:
get:
- summary: List all assets in the workspace
+ summary: List all assets in the workspace with cursor pagination
operationId: listAssets
tags:
- asset
@@ -20132,52 +27580,136 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
+ - name: per_page
+ in: query
+ description: Number of items per page (max 1000, default 50)
+ schema:
+ type: integer
+ default: 50
+ minimum: 1
+ maximum: 1000
+ - name: cursor_created_at
+ in: query
+ description: >-
+ Cursor timestamp for pagination (created_at of last item from
+ previous page)
+ schema:
+ type: string
+ format: date-time
+ - name: cursor_id
+ in: query
+ description: Cursor ID for pagination (id of last item from previous page)
+ schema:
+ type: integer
+ format: int64
+ - name: asset_path
+ in: query
+ description: Filter by asset path (case-insensitive partial match)
+ schema:
+ type: string
+ - name: usage_path
+ in: query
+ description: Filter by usage path (case-insensitive partial match)
+ schema:
+ type: string
+ - name: asset_kinds
+ in: query
+ description: Filter by asset kinds (multiple values allowed)
+ schema:
+ type: string
responses:
'200':
- description: all assets in the workspace
+ description: paginated assets in the workspace
content:
application/json:
schema:
- type: array
- items:
- type: object
- required:
- - path
- - kind
- - usages
- properties:
- path:
- type: string
- kind:
- type: string
- enum: *ref_202
- usages:
- type: array
- items:
- type: object
- required:
- - path
- - kind
- properties:
- path:
- type: string
- kind:
- type: string
- enum: &ref_203
- - script
- - flow
- access_type:
- type: string
- enum: &ref_204
- - r
- - w
- - rw
- metadata:
+ type: object
+ required:
+ - assets
+ properties:
+ assets:
+ type: array
+ items:
type: object
+ required:
+ - path
+ - kind
+ - usages
properties:
- resource_type:
+ path:
type: string
+ kind:
+ type: string
+ enum: *ref_262
+ usages:
+ type: array
+ items:
+ type: object
+ required:
+ - path
+ - kind
+ properties:
+ path:
+ type: string
+ kind:
+ type: string
+ enum: &ref_264
+ - script
+ - flow
+ - job
+ access_type:
+ type: string
+ enum: &ref_263
+ - r
+ - w
+ - rw
+ nullable: true
+ columns:
+ type: object
+ description: The columns used (for tables)
+ additionalProperties:
+ type: string
+ enum: *ref_263
+ nullable: true
+ created_at:
+ type: string
+ format: date-time
+ description: When the asset was detected
+ metadata:
+ type: object
+ properties:
+ runnable_path:
+ type: string
+ description: >-
+ The path of the script/flow that was run
+ (only present when kind is 'job')
+ job_kind:
+ type: string
+ description: >-
+ The kind of job (script, flow, preview,
+ etc.) (only present when kind is 'job')
+ metadata:
+ type: object
+ properties:
+ resource_type:
+ type: string
+ description: >-
+ The type of the resource (only present when kind
+ is 'resource')
+ next_cursor:
+ type: object
+ description: Cursor for the next page (null if no more pages)
+ nullable: true
+ properties:
+ created_at:
+ type: string
+ format: date-time
+ description: Timestamp to use for next page
+ id:
+ type: integer
+ format: int64
+ description: ID to use for next page
/w/{workspace}/assets/list_by_usages:
post:
summary: List all assets used by given usages paths
@@ -20188,7 +27720,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
requestBody:
description: list assets by usages
required: true
@@ -20211,7 +27743,7 @@ paths:
type: string
kind:
type: string
- enum: *ref_203
+ enum: *ref_264
responses:
'200':
description: all assets used by the given usage paths, in the same order
@@ -20231,10 +27763,37 @@ paths:
type: string
kind:
type: string
- enum: *ref_202
+ enum: *ref_262
access_type:
type: string
- enum: *ref_204
+ enum: *ref_263
+ nullable: true
+ /w/{workspace}/assets/list_favorites:
+ get:
+ summary: List all favorite assets for the authenticated user
+ operationId: listFavoriteAssets
+ tags:
+ - asset
+ parameters:
+ - name: workspace
+ in: path
+ required: true
+ schema: *ref_4
+ responses:
+ '200':
+ description: list of favorite assets
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ required:
+ - path
+ properties:
+ path:
+ type: string
+ description: The asset path
/mcp/w/{workspace}/list_tools:
get:
summary: list available MCP tools
@@ -20245,7 +27804,7 @@ paths:
- name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
responses:
'200':
description: list of MCP tools available for the workspace
@@ -20255,13 +27814,13 @@ paths:
type: array
items:
type: object
- required: &ref_235
+ required: &ref_337
- name
- description
- instructions
- path
- method
- properties: &ref_236
+ properties: &ref_338
name:
type: string
description: The tool name/operation ID
@@ -20289,6 +27848,101 @@ paths:
type: object
description: JSON schema for request body
nullable: true
+ /mcp/oauth/discover:
+ post:
+ summary: discover MCP server OAuth metadata
+ operationId: discoverMcpOAuth
+ tags:
+ - mcp_oauth
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - mcp_server_url
+ properties:
+ mcp_server_url:
+ type: string
+ description: URL of the MCP server to discover OAuth metadata from
+ responses:
+ '200':
+ description: OAuth metadata from MCP server
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ scopes_supported:
+ type: array
+ items:
+ type: string
+ authorization_endpoint:
+ type: string
+ token_endpoint:
+ type: string
+ registration_endpoint:
+ type: string
+ supports_dynamic_registration:
+ type: boolean
+ /mcp/oauth/start:
+ get:
+ summary: start MCP OAuth popup flow
+ description: >-
+ Opens in a popup, discovers OAuth metadata, registers client, and
+ redirects to OAuth provider
+ operationId: startMcpOAuthPopup
+ tags:
+ - mcp_oauth
+ parameters:
+ - name: mcp_server_url
+ in: query
+ required: true
+ schema:
+ type: string
+ description: URL of the MCP server to connect to
+ - name: scopes
+ in: query
+ required: false
+ schema:
+ type: string
+ description: Comma-separated list of OAuth scopes to request
+ responses:
+ '302':
+ description: Redirect to OAuth provider authorization URL
+ /mcp/oauth/callback:
+ get:
+ security: []
+ summary: MCP OAuth callback
+ description: >-
+ Handles OAuth callback, exchanges code for tokens, returns HTML that
+ posts message to opener
+ operationId: mcpOAuthCallback
+ tags:
+ - mcp_oauth
+ parameters:
+ - name: code
+ in: query
+ required: true
+ schema:
+ type: string
+ description: OAuth authorization code
+ - name: state
+ in: query
+ required: true
+ schema:
+ type: string
+ description: CSRF state token
+ responses:
+ '200':
+ description: >-
+ HTML page with JavaScript that posts tokens to opener window and
+ closes
+ content:
+ text/html:
+ schema:
+ type: string
components:
securitySchemes:
bearerAuth:
@@ -20303,103 +27957,109 @@ components:
name: id
in: path
required: true
- schema: *ref_205
+ schema: *ref_265
Key:
name: key
in: path
required: true
- schema: *ref_9
+ schema: *ref_21
WorkspaceId:
name: workspace
in: path
required: true
- schema: *ref_0
+ schema: *ref_4
PublicationName:
name: publication
in: path
required: true
description: The name of the publication
- schema: *ref_174
+ schema: *ref_226
VersionId:
name: version
in: path
required: true
- schema: *ref_206
+ schema:
+ type: number
Token:
name: token
in: path
required: true
- schema: *ref_207
+ schema: *ref_266
AccountId:
name: id
in: path
required: true
- schema: *ref_38
+ schema: *ref_58
ClientName:
name: client_name
in: path
required: true
- schema: *ref_35
+ schema: *ref_55
ScriptPath:
name: path
in: path
required: true
- schema: *ref_48
+ schema: *ref_74
ScriptHash:
name: hash
in: path
required: true
- schema: *ref_53
+ schema: *ref_81
JobId:
name: id
in: path
required: true
- schema: *ref_123
+ schema: *ref_144
Path:
name: path
in: path
required: true
- schema: *ref_31
+ schema: *ref_48
CustomPath:
name: custom_path
in: path
required: true
- schema: *ref_81
+ schema: *ref_111
PathId:
name: id
in: path
required: true
- schema: *ref_41
+ schema: *ref_61
PathVersion:
name: version
in: path
required: true
- schema: *ref_208
+ schema: *ref_267
Name:
name: name
in: path
required: true
- schema: *ref_180
+ schema: *ref_235
Page:
name: page
description: which page to return (start at 1, default 1)
in: query
- schema: *ref_5
+ schema: *ref_13
PerPage:
name: per_page
description: number of items to return for a given page (default 30, max 100)
in: query
- schema: *ref_6
+ schema: *ref_14
+ JobTriggerKind:
+ name: trigger_kind
+ description: trigger kind (schedule, http, websocket...)
+ in: query
+ schema: *ref_160
OrderDesc:
name: order_desc
description: order by desc order (default true)
in: query
- schema: *ref_66
+ schema: *ref_96
CreatedBy:
name: created_by
description: mask to filter exact matching user creator
in: query
- schema: *ref_67
+ schema: *ref_97
Label:
name: label
description: >-
@@ -20407,31 +28067,31 @@ components:
with as a result an object containing a string in the array at key
'wm_labels')
in: query
- schema: *ref_110
+ schema: *ref_146
Worker:
name: worker
description: worker this job was ran on
in: query
- schema: *ref_94
+ schema: *ref_128
ParentJob:
name: parent_job
description: >-
The parent job that is at the origin and responsible for the execution
of this script if any
in: query
- schema: *ref_60
+ schema: *ref_88
WorkerTag:
name: tag
description: Override the tag to use
in: query
- schema: *ref_62
+ schema: *ref_89
CacheTtl:
name: cache_ttl
description: >-
Override the cache time to live (in seconds). Can not be used to disable
caching, only override with a new cache ttl
in: query
- schema: *ref_63
+ schema: *ref_90
NewJobId:
name: job_id
description: >-
@@ -20439,7 +28099,7 @@ components:
randomly using the ULID scheme. If a job id already exists in the queue
or as a completed job, the request to create one will fail (Bad Request)
in: query
- schema: *ref_61
+ schema: *ref_91
IncludeHeader:
name: include_header
description: >
@@ -20449,14 +28109,19 @@ components:
Header's key lowercased and '-'' replaced to '_' such that
'Content-Type' becomes the 'content_type' arg key
in: query
- schema: *ref_64
+ schema: *ref_92
QueueLimit:
name: queue_limit
description: >
The maximum size of the queue for which the request would get rejected
if that job would push it above that limit
in: query
- schema: *ref_65
+ schema: *ref_93
+ SkipPreprocessor:
+ name: skip_preprocessor
+ description: skip the preprocessor
+ in: query
+ schema: *ref_94
Payload:
name: payload
description: >
@@ -20465,287 +28130,368 @@ components:
`encodeURIComponent(btoa(JSON.stringify({a: 2})))`
in: query
- schema: *ref_126
+ schema: *ref_95
ScriptStartPath:
name: script_path_start
description: mask to filter matching starting path
in: query
- schema: *ref_96
+ schema: *ref_130
SchedulePath:
name: schedule_path
description: mask to filter by schedule path
in: query
- schema: *ref_97
+ schema: *ref_131
+ TriggerPath:
+ name: trigger_path
+ description: mask to filter by trigger path
+ in: query
+ schema: *ref_268
ScriptExactPath:
name: script_path_exact
description: mask to filter exact matching path
in: query
- schema: *ref_95
+ schema: *ref_129
ScriptExactHash:
name: script_hash
description: mask to filter exact matching path
in: query
- schema: *ref_98
+ schema: *ref_132
CreatedBefore:
name: created_before
description: filter on created before (inclusive) timestamp
in: query
- schema: *ref_114
+ schema: *ref_154
CreatedAfter:
name: created_after
description: filter on created after (exclusive) timestamp
in: query
- schema: *ref_115
+ schema: *ref_155
StartedBefore:
name: started_before
description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_99
+ schema: *ref_133
StartedAfter:
name: started_after
description: filter on started after (exclusive) timestamp
in: query
- schema: *ref_100
+ schema: *ref_134
Before:
name: before
description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_200
- CreatedOrStartedAfter:
- name: created_or_started_after
- description: >-
- filter on created_at for non non started job and started_at otherwise
- after (exclusive) timestamp
+ schema: *ref_260
+ CompletedBefore:
+ name: completed_before
+ description: filter on started before (inclusive) timestamp
in: query
- schema: *ref_117
- CreatedOrStartedAfterCompletedJob:
- name: created_or_started_after_completed_jobs
- description: >-
- filter on created_at for non non started job and started_at otherwise
- after (exclusive) timestamp but only for the completed jobs
+ schema: *ref_156
+ CompletedAfter:
+ name: completed_after
+ description: filter on started after (exclusive) timestamp
in: query
- schema: *ref_118
- CreatedOrStartedBefore:
- name: created_or_started_before
- description: >-
- filter on created_at for non non started job and started_at otherwise
- before (inclusive) timestamp
+ schema: *ref_157
+ CreatedAfterQueue:
+ name: created_after_queue
+ description: filter on jobs created after X for jobs in the queue only
in: query
- schema: *ref_116
+ schema: *ref_159
+ CreatedBeforeQueue:
+ name: created_before_queue
+ description: filter on jobs created before X for jobs in the queue only
+ in: query
+ schema: *ref_158
Success:
name: success
description: filter on successful jobs
in: query
- schema: *ref_108
+ schema: *ref_142
ScheduledForBeforeNow:
name: scheduled_for_before_now
description: filter on jobs scheduled_for before now (hence waitinf for a worker)
in: query
- schema: *ref_102
+ schema: *ref_136
Suspended:
name: suspended
description: filter on suspended jobs
in: query
- schema: *ref_104
+ schema: *ref_138
Running:
name: running
description: filter on running jobs
in: query
- schema: *ref_101
+ schema: *ref_135
AllowWildcards:
name: allow_wildcards
description: allow wildcards (*) in the filter of label, tag, worker
in: query
- schema: *ref_109
+ schema: *ref_143
ArgsFilter:
name: args
description: filter on jobs containing those args as a json subset (@> in postgres)
in: query
- schema: *ref_105
+ schema: *ref_139
Tag:
name: tag
description: filter on jobs with a given tag/worker group
in: query
- schema: *ref_106
+ schema: *ref_140
ResultFilter:
name: result
description: filter on jobs containing those result as a json subset (@> in postgres)
in: query
- schema: *ref_107
+ schema: *ref_141
After:
name: after
description: filter on created after (exclusive) timestamp
in: query
- schema: *ref_201
+ schema: *ref_261
Username:
name: username
description: filter on exact username of user
in: query
- schema: *ref_209
+ schema: *ref_269
Operation:
name: operation
description: filter on exact or prefix name of operation
in: query
- schema: *ref_210
+ schema: *ref_270
ResourceName:
name: resource
description: filter on exact or prefix name of resource
in: query
- schema: *ref_211
+ schema: *ref_271
ActionKind:
name: action_kind
description: filter on type of operation
in: query
- schema: *ref_212
+ schema: *ref_272
JobKinds:
name: job_kinds
description: >-
filter on job kind (values 'preview', 'script', 'dependencies', 'flow')
separated by,
in: query
- schema: *ref_103
+ schema: *ref_137
RunnableId:
name: runnable_id
in: query
- schema: *ref_192
+ schema: *ref_247
RunnableTypeQuery:
name: runnable_type
in: query
- schema: *ref_193
+ schema: *ref_248
InputId:
name: input
in: path
required: true
- schema: *ref_213
+ schema: *ref_273
GetStarted:
name: get_started
in: query
- schema: *ref_214
+ schema: *ref_274
ConcurrencyId:
name: concurrency_id
in: path
required: true
- schema: *ref_215
+ schema: *ref_275
RunnableKind:
name: runnable_kind
in: path
required: true
- schema: *ref_80
+ schema: *ref_110
schemas:
OpenFlow:
type: object
- properties: *ref_68
- required: *ref_69
+ description: >-
+ Top-level flow definition containing metadata, configuration, and the
+ flow structure
+ properties: *ref_98
+ required: *ref_99
FlowValue:
type: object
- properties: *ref_92
- required: *ref_93
+ description: >-
+ The flow structure containing modules and optional preprocessor/failure
+ handlers
+ properties: *ref_126
+ required: *ref_127
Retry:
type: object
- properties: *ref_127
+ description: Retry configuration for failed module executions
+ properties: *ref_169
StopAfterIf:
type: object
+ description: Early termination condition for a module
properties:
skip_if_stopped:
type: boolean
+ description: If true, following steps are skipped when this condition triggers
expr:
type: string
+ description: >-
+ JavaScript expression evaluated after the module runs. Can use
+ 'result' (step's result) or 'flow_input'. Return true to stop
error_message:
type: string
+ description: Custom error message shown when stopping
required:
- expr
FlowModule:
type: object
+ description: A single step in a flow. Can be a script, subflow, loop, or branch
properties:
id:
type: string
+ description: >-
+ Unique identifier for this step. Used to reference results via
+ 'results.step_id'. Must be a valid identifier (alphanumeric,
+ underscore, hyphen)
value:
- oneOf: *ref_216
- discriminator: *ref_217
+ description: >-
+ The actual implementation of a flow step. Can be a script (inline or
+ referenced), subflow, loop, branch, or special module type
+ oneOf: *ref_70
+ discriminator: *ref_71
stop_after_if:
+ description: Early termination condition for a module
type: object
- properties: *ref_46
- required: *ref_47
+ properties: *ref_72
+ required: *ref_73
stop_after_all_iters_if:
+ description: Early termination condition for a module
type: object
- properties: *ref_46
- required: *ref_47
+ properties: *ref_72
+ required: *ref_73
skip_if:
type: object
+ description: >-
+ Conditionally skip this step based on previous results or flow
+ inputs
properties:
expr:
type: string
+ description: >-
+ JavaScript expression that returns true to skip. Can use
+ 'flow_input' or 'results.'
required:
- expr
sleep:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or flow
+ inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
cache_ttl:
type: number
+ description: Cache duration in seconds for this step's results
+ cache_ignore_s3_path:
+ type: boolean
timeout:
- type: number
+ description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or flow
+ inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
delete_after_use:
type: boolean
+ description: If true, this step's result is deleted after use to save memory
summary:
type: string
+ description: Short description of what this step does
mock:
type: object
+ description: Mock configuration for testing without executing the actual step
properties:
enabled:
type: boolean
- return_value: {}
+ description: If true, return mock value instead of executing
+ return_value:
+ description: Value to return when mocked
suspend:
type: object
+ description: Configuration for approval/resume steps that wait for user input
properties:
required_events:
type: integer
+ description: Number of approvals required before continuing
timeout:
type: integer
+ description: Timeout in seconds before auto-continuing or canceling
resume_form:
type: object
+ description: Form schema for collecting input when resuming
properties:
schema:
type: object
+ description: JSON Schema for the resume form
user_auth_required:
type: boolean
+ description: If true, only authenticated users can approve
user_groups_required:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or flow
+ inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
self_approval_disabled:
type: boolean
+ description: If true, the user who started the flow cannot approve
hide_cancel:
type: boolean
+ description: If true, hide the cancel button on the approval form
continue_on_disapprove_timeout:
type: boolean
+ description: If true, continue flow on timeout instead of canceling
priority:
type: number
+ description: Execution priority for this step (higher numbers run first)
continue_on_error:
type: boolean
+ description: If true, flow continues even if this step fails
retry:
+ description: Retry configuration for failed module executions
type: object
- properties: *ref_218
+ properties: *ref_276
required:
- value
- id
InputTransform:
- oneOf: *ref_88
- discriminator: *ref_89
+ description: >-
+ Maps input parameters for a step. Can be a static value or a JavaScript
+ expression that references previous results or flow inputs
+ oneOf: *ref_116
+ discriminator: *ref_117
StaticTransform:
type: object
+ description: >-
+ Static value passed directly to the step. Use for hardcoded values or
+ resource references like '$res:path/to/resource'
properties:
- value: {}
+ value:
+ description: The static value. For resources, use format '$res:path/to/resource'
type:
type: string
enum:
- static
required:
- - value
- type
JavascriptTransform:
type: object
+ description: >-
+ JavaScript expression evaluated at runtime. Can reference previous step
+ results via 'results.step_id' or flow inputs via 'flow_input.property'.
+ Inside loops, use 'flow_input.iter.value' for the current iteration
+ value
properties:
expr:
type: string
+ description: >-
+ JavaScript expression returning the value. Available variables -
+ results (object with all previous step results), flow_input (flow
+ inputs), flow_input.iter (in loops)
type:
type: string
enum:
@@ -20753,32 +28499,129 @@ components:
required:
- expr
- type
- FlowModuleValue:
+ AiTransform:
+ type: object
+ description: >-
+ Value resolved by the AI runtime for this input. The AI engine decides
+ how to satisfy the parameter.
+ properties:
+ type:
+ type: string
+ enum:
+ - ai
+ required:
+ - type
+ ProviderConfig:
+ type: object
+ description: >-
+ Complete AI provider configuration with resource reference and model
+ selection
+ properties:
+ kind:
+ type: string
+ description: Supported AI provider types
+ enum: *ref_277
+ resource:
+ type: string
+ description: >-
+ Resource reference in format '$res:{resource_path}' pointing to
+ provider credentials
+ model:
+ type: string
+ description: >-
+ Model identifier (e.g., 'gpt-4', 'claude-3-opus-20240229',
+ 'gemini-pro')
+ required:
+ - kind
+ - resource
+ - model
+ MemoryConfig:
+ description: Conversation memory configuration
oneOf:
- type: object
- properties: *ref_219
- required: *ref_220
+ description: No conversation memory/context
+ properties: *ref_278
+ required: *ref_279
- type: object
- properties: *ref_221
- required: *ref_222
+ description: Automatic context management
+ properties: *ref_280
+ required: *ref_281
- type: object
- properties: *ref_223
- required: *ref_224
+ description: Explicit message history
+ properties: *ref_282
+ required: *ref_283
+ discriminator:
+ propertyName: kind
+ mapping:
+ 'off': '#/components/schemas/MemoryOff'
+ auto: '#/components/schemas/MemoryAuto'
+ manual: '#/components/schemas/MemoryManual'
+ FlowModuleValue:
+ description: >-
+ The actual implementation of a flow step. Can be a script (inline or
+ referenced), subflow, loop, branch, or special module type
+ oneOf:
- type: object
- properties: *ref_225
- required: *ref_226
+ description: >-
+ Inline script with code defined directly in the flow. Use 'bun' as
+ default language if unspecified. The script receives arguments from
+ input_transforms
+ properties: *ref_284
+ required: *ref_285
- type: object
- properties: *ref_227
- required: *ref_228
+ description: >-
+ Reference to an existing script by path. Use this when calling a
+ previously saved script instead of writing inline code
+ properties: *ref_286
+ required: *ref_287
- type: object
- properties: *ref_229
- required: *ref_230
+ description: >-
+ Reference to an existing flow by path. Use this to call another flow
+ as a subflow
+ properties: *ref_288
+ required: *ref_289
- type: object
- properties: *ref_231
- required: *ref_232
+ description: >-
+ Executes nested modules in a loop over an iterator. Inside the loop,
+ use 'flow_input.iter.value' to access the current iteration value,
+ and 'flow_input.iter.index' for the index. Supports parallel
+ execution for better performance on I/O-bound operations
+ properties: *ref_290
+ required: *ref_291
- type: object
- properties: *ref_233
- required: *ref_234
+ description: >-
+ Executes nested modules repeatedly while a condition is true. The
+ loop checks the condition after each iteration. Use stop_after_if on
+ modules to control loop termination
+ properties: *ref_292
+ required: *ref_293
+ - type: object
+ description: >-
+ Conditional branching where only the first matching branch executes.
+ Branches are evaluated in order, and the first one with a true
+ expression runs. If no branches match, the default branch executes
+ properties: *ref_294
+ required: *ref_295
+ - type: object
+ description: >-
+ Parallel branching where all branches execute simultaneously. Unlike
+ BranchOne, all branches run regardless of conditions. Useful for
+ executing independent tasks concurrently
+ properties: *ref_296
+ required: *ref_297
+ - type: object
+ description: >-
+ Pass-through module that returns its input unchanged. Useful for
+ flow structure or as a placeholder
+ properties: *ref_298
+ required: *ref_299
+ - type: object
+ description: >-
+ AI agent step that can use tools to accomplish tasks. The agent
+ receives inputs and can call any of its configured tools to complete
+ the task
+ properties: *ref_300
+ required: *ref_301
discriminator:
propertyName: type
mapping:
@@ -20790,18 +28633,32 @@ components:
branchone: '#/components/schemas/schemas-BranchOne'
branchall: '#/components/schemas/schemas-BranchAll'
identity: '#/components/schemas/schemas-Identity'
+ aiagent: '#/components/schemas/schemas-AiAgent'
RawScript:
type: object
+ description: >-
+ Inline script with code defined directly in the flow. Use 'bun' as
+ default language if unspecified. The script receives arguments from
+ input_transforms
properties:
input_transforms:
type: object
+ description: >-
+ Map of parameter names to their values (static or JavaScript
+ expressions). These become the script's input arguments
additionalProperties:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or flow
+ inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
content:
type: string
+ description: The script source code. Should export a 'main' function
language:
type: string
+ description: Programming language for this script
enum:
- deno
- bun
@@ -20818,26 +28675,43 @@ components:
- graphql
- nativets
- php
+ - rust
+ - ansible
+ - csharp
+ - nu
+ - java
+ - ruby
+ - duckdb
path:
type: string
+ description: Optional path for saving this script
lock:
type: string
+ description: Lock file content for dependencies
type:
type: string
enum:
- rawscript
tag:
type: string
+ description: Worker group tag for execution routing
concurrent_limit:
type: number
+ description: Maximum concurrent executions of this script
concurrency_time_window_s:
type: number
+ description: Time window for concurrent_limit
custom_concurrency_key:
type: string
+ description: Custom key for grouping concurrent executions
is_trigger:
type: boolean
+ description: If true, this script is a trigger that can start the flow
assets:
type: array
+ description: >-
+ External resources this script accesses (S3 objects, resources,
+ etc.)
items:
type: object
required:
@@ -20846,20 +28720,27 @@ components:
properties:
path:
type: string
+ description: Path to the asset
kind:
type: string
+ description: Type of asset
enum:
- s3object
- resource
- ducklake
+ - datatable
access_type:
type: string
+ nullable: true
+ description: Access level for this asset
enum:
- r
- w
- rw
alt_access_type:
type: string
+ nullable: true
+ description: Alternative access level
enum:
- r
- w
@@ -20871,38 +28752,63 @@ components:
- input_transforms
PathScript:
type: object
+ description: >-
+ Reference to an existing script by path. Use this when calling a
+ previously saved script instead of writing inline code
properties:
input_transforms:
type: object
+ description: >-
+ Map of parameter names to their values (static or JavaScript
+ expressions). These become the script's input arguments
additionalProperties:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or flow
+ inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
path:
type: string
+ description: Path to the script in the workspace (e.g., 'f/scripts/send_email')
hash:
type: string
+ description: Optional specific version hash of the script to use
type:
type: string
enum:
- script
tag_override:
type: string
+ description: Override the script's default worker group tag
is_trigger:
type: boolean
+ description: If true, this script is a trigger that can start the flow
required:
- type
- path
- input_transforms
PathFlow:
type: object
+ description: >-
+ Reference to an existing flow by path. Use this to call another flow as
+ a subflow
properties:
input_transforms:
type: object
+ description: >-
+ Map of parameter names to their values (static or JavaScript
+ expressions). These become the subflow's input arguments
additionalProperties:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or flow
+ inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
path:
type: string
+ description: Path to the flow in the workspace (e.g., 'f/flows/process_user')
type:
type: string
enum:
@@ -20913,26 +28819,52 @@ components:
- input_transforms
ForloopFlow:
type: object
+ description: >-
+ Executes nested modules in a loop over an iterator. Inside the loop, use
+ 'flow_input.iter.value' to access the current iteration value, and
+ 'flow_input.iter.index' for the index. Supports parallel execution for
+ better performance on I/O-bound operations
properties:
modules:
type: array
+ description: >-
+ Steps to execute for each iteration. These can reference the
+ iteration value via 'flow_input.iter.value'
items:
type: object
- properties: *ref_44
- required: *ref_45
+ description: A single step in a flow. Can be a script, subflow, loop, or branch
+ properties: *ref_64
+ required: *ref_65
iterator:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or flow
+ inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
skip_failures:
type: boolean
+ description: >-
+ If true, iteration failures don't stop the loop. Failed iterations
+ return null
type:
type: string
enum:
- forloopflow
parallel:
type: boolean
+ description: >-
+ If true, iterations run concurrently (faster for I/O-bound
+ operations). Use with parallelism to control concurrency
parallelism:
- type: integer
+ description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or flow
+ inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ squash:
+ type: boolean
required:
- modules
- iterator
@@ -20940,56 +28872,92 @@ components:
- type
WhileloopFlow:
type: object
+ description: >-
+ Executes nested modules repeatedly while a condition is true. The loop
+ checks the condition after each iteration. Use stop_after_if on modules
+ to control loop termination
properties:
modules:
type: array
+ description: >-
+ Steps to execute in each iteration. Use stop_after_if to control
+ when the loop ends
items:
type: object
- properties: *ref_44
- required: *ref_45
+ description: A single step in a flow. Can be a script, subflow, loop, or branch
+ properties: *ref_64
+ required: *ref_65
skip_failures:
type: boolean
+ description: >-
+ If true, iteration failures don't stop the loop. Failed iterations
+ return null
type:
type: string
enum:
- whileloopflow
parallel:
type: boolean
+ description: >-
+ If true, iterations run concurrently (use with caution in while
+ loops)
parallelism:
- type: integer
+ description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or flow
+ inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ squash:
+ type: boolean
required:
- modules
- skip_failures
- type
BranchOne:
type: object
+ description: >-
+ Conditional branching where only the first matching branch executes.
+ Branches are evaluated in order, and the first one with a true
+ expression runs. If no branches match, the default branch executes
properties:
branches:
type: array
+ description: >-
+ Array of branches to evaluate in order. The first branch with expr
+ evaluating to true executes
items:
type: object
properties:
summary:
type: string
+ description: Short description of this branch condition
expr:
type: string
+ description: >-
+ JavaScript expression that returns boolean. Can use
+ 'results.step_id' or 'flow_input'. First true expr wins
modules:
type: array
+ description: Steps to execute if this branch's expr is true
items:
type: object
- properties: *ref_44
- required: *ref_45
+ description: >-
+ A single step in a flow. Can be a script, subflow, loop, or
+ branch
+ properties: *ref_64
+ required: *ref_65
required:
- modules
- expr
default:
type: array
+ description: Steps to execute if no branch expressions match
items:
type: object
- properties: *ref_44
- required: *ref_45
- required:
- - modules
+ description: A single step in a flow. Can be a script, subflow, loop, or branch
+ properties: *ref_64
+ required: *ref_65
type:
type: string
enum:
@@ -21000,22 +28968,35 @@ components:
- type
BranchAll:
type: object
+ description: >-
+ Parallel branching where all branches execute simultaneously. Unlike
+ BranchOne, all branches run regardless of conditions. Useful for
+ executing independent tasks concurrently
properties:
branches:
type: array
+ description: >-
+ Array of branches that all execute (either in parallel or
+ sequentially)
items:
type: object
properties:
summary:
type: string
+ description: Short description of this branch's purpose
skip_failure:
type: boolean
+ description: If true, failure in this branch doesn't fail the entire flow
modules:
type: array
+ description: Steps to execute in this branch
items:
type: object
- properties: *ref_44
- required: *ref_45
+ description: >-
+ A single step in a flow. Can be a script, subflow, loop, or
+ branch
+ properties: *ref_64
+ required: *ref_65
required:
- modules
type:
@@ -21024,11 +29005,175 @@ components:
- branchall
parallel:
type: boolean
+ description: >-
+ If true, all branches execute concurrently. If false, they execute
+ sequentially
required:
- branches
- type
+ AiAgent:
+ type: object
+ description: >-
+ AI agent step that can use tools to accomplish tasks. The agent receives
+ inputs and can call any of its configured tools to complete the task
+ properties:
+ input_transforms:
+ type: object
+ description: Input parameters for the AI agent mapped to their values
+ properties:
+ provider:
+ description: >-
+ Provider configuration - can be static (ProviderConfig),
+ JavaScript expression, or AI-determined
+ oneOf: *ref_302
+ discriminator: *ref_303
+ output_type:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or
+ flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ Output format type.
+
+ Valid values: 'text' (default) - plain text response, 'image' -
+ image generation
+ user_message:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or
+ flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >-
+ The user's prompt/message to the AI agent. Supports variable
+ interpolation with flow.input syntax.
+ system_prompt:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or
+ flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >-
+ System instructions that guide the AI's behavior, persona, and
+ response style. Optional.
+ streaming:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or
+ flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ Boolean. If true, stream the AI response incrementally.
+
+ Streaming events include: token_delta, tool_call,
+ tool_call_arguments, tool_execution, tool_result
+ memory:
+ description: >-
+ Memory configuration - can be static (MemoryConfig), JavaScript
+ expression, or AI-determined
+ oneOf: *ref_304
+ discriminator: *ref_305
+ output_schema:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or
+ flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ JSON Schema object defining structured output format. Used when
+ you need the AI to return data in a specific shape.
+
+ Supports standard JSON Schema properties: type, properties,
+ required, items, enum, pattern, minLength, maxLength, minimum,
+ maximum, etc.
+
+ Example: { type: 'object', properties: { name: { type: 'string'
+ }, age: { type: 'integer' } }, required: ['name'] }
+ user_images:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or
+ flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ Array of image references for vision-capable models.
+
+ Format: Array<{ bucket: string, key: string }> - S3 object
+ references
+
+ Example: [{ bucket: 'my-bucket', key: 'images/photo.jpg' }]
+ max_completion_tokens:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or
+ flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: >
+ Integer. Maximum number of tokens the AI will generate in its
+ response.
+
+ Range: 1 to 4,294,967,295. Typical values: 256-4096 for most use
+ cases.
+ temperature:
+ allOf:
+ - description: >-
+ Maps input parameters for a step. Can be a static value or a
+ JavaScript expression that references previous results or
+ flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
+ description: |
+ Float. Controls randomness/creativity of responses.
+ Range: 0.0 to 2.0 (provider-dependent)
+ - 0.0 = deterministic, focused responses
+ - 0.7 = balanced (common default)
+ - 1.0+ = more creative/random
+ required:
+ - provider
+ - user_message
+ - output_type
+ tools:
+ type: array
+ description: >-
+ Array of tools the agent can use. The agent decides which tools to
+ call based on the task
+ items:
+ type: object
+ description: >-
+ A tool available to an AI agent. Can be a flow module or an
+ external MCP (Model Context Protocol) tool
+ properties: *ref_306
+ required: *ref_307
+ type:
+ type: string
+ enum:
+ - aiagent
+ parallel:
+ type: boolean
+ description: If true, the agent can execute multiple tool calls in parallel
+ required:
+ - tools
+ - type
+ - input_transforms
Identity:
type: object
+ description: >-
+ Pass-through module that returns its input unchanged. Useful for flow
+ structure or as a placeholder
properties:
type:
type: string
@@ -21036,12 +29181,13 @@ components:
- identity
flow:
type: boolean
+ description: If true, marks this as a flow identity (special handling)
required:
- type
FlowStatus:
type: object
- properties: *ref_111
- required: *ref_112
+ properties: *ref_147
+ required: *ref_148
FlowStatusModule:
type: object
properties:
@@ -21071,6 +29217,8 @@ components:
itered:
type: array
items: {}
+ itered_len:
+ type: integer
args: {}
flow_jobs:
type: array
@@ -21080,6 +29228,17 @@ components:
type: array
items:
type: boolean
+ flow_jobs_duration:
+ type: object
+ properties:
+ started_at:
+ type: array
+ items:
+ type: string
+ duration_ms:
+ type: array
+ items:
+ type: integer
branch_chosen:
type: object
properties:
@@ -21121,128 +29280,385 @@ components:
format: uuid
skipped:
type: boolean
+ agent_actions:
+ type: array
+ items:
+ type: object
+ oneOf:
+ - type: object
+ properties:
+ job_id:
+ type: string
+ format: uuid
+ function_name:
+ type: string
+ type:
+ type: string
+ enum:
+ - tool_call
+ module_id:
+ type: string
+ required:
+ - job_id
+ - function_name
+ - type
+ - module_id
+ - type: object
+ properties:
+ call_id:
+ type: string
+ format: uuid
+ function_name:
+ type: string
+ resource_path:
+ type: string
+ type:
+ type: string
+ enum:
+ - mcp_tool_call
+ arguments:
+ type: object
+ required:
+ - call_id
+ - function_name
+ - resource_path
+ - type
+ - type: object
+ properties:
+ type:
+ type: string
+ enum:
+ - web_search
+ required:
+ - type
+ - type: object
+ properties:
+ type:
+ type: string
+ enum:
+ - message
+ required:
+ - content
+ - type
+ agent_actions_success:
+ type: array
+ items:
+ type: boolean
required:
- type
+ FlowNote:
+ type: object
+ description: A sticky note attached to a flow for documentation and annotation
+ properties:
+ id:
+ type: string
+ description: Unique identifier for the note
+ text:
+ type: string
+ description: Content of the note
+ position:
+ type: object
+ description: Position of the note in the flow editor
+ properties:
+ x:
+ type: number
+ description: X coordinate
+ 'y':
+ type: number
+ description: Y coordinate
+ required:
+ - x
+ - 'y'
+ size:
+ type: object
+ description: Size of the note in the flow editor
+ properties:
+ width:
+ type: number
+ description: Width in pixels
+ height:
+ type: number
+ description: Height in pixels
+ required:
+ - width
+ - height
+ color:
+ type: string
+ description: Color of the note (e.g., "yellow", "#ffff00")
+ type:
+ type: string
+ enum:
+ - free
+ - group
+ description: >-
+ Type of note - 'free' for standalone notes, 'group' for notes that
+ group other nodes
+ locked:
+ type: boolean
+ default: false
+ description: Whether the note is locked and cannot be edited or moved
+ contained_node_ids:
+ type: array
+ items:
+ type: string
+ description: For group notes, the IDs of nodes contained within this group
+ required:
+ - id
+ - text
+ - color
+ - type
+ HealthStatusResponse:
+ type: object
+ description: Health status response (cached with 5s TTL)
+ required: *ref_0
+ properties: *ref_1
+ DetailedHealthResponse:
+ type: object
+ description: Detailed health status response (always fresh, no caching)
+ required: *ref_2
+ properties: *ref_3
+ HealthChecks:
+ type: object
+ description: Detailed health checks
+ required: *ref_308
+ properties: *ref_309
+ DatabaseHealth:
+ type: object
+ description: Database health status
+ required: *ref_310
+ properties: *ref_311
+ PoolStats:
+ type: object
+ description: Database connection pool statistics
+ required: *ref_312
+ properties: *ref_313
+ WorkersHealth:
+ type: object
+ description: Workers health status
+ required: *ref_314
+ properties: *ref_315
+ QueueHealth:
+ type: object
+ description: Job queue status
+ required: *ref_316
+ properties: *ref_317
+ ReadinessHealth:
+ type: object
+ description: Server readiness status
+ required: *ref_318
+ properties: *ref_319
+ AutoInviteConfig:
+ type: object
+ description: Configuration for auto-inviting users to the workspace
+ properties: *ref_320
+ ErrorHandlerConfig:
+ type: object
+ description: Configuration for the workspace error handler
+ properties: *ref_321
+ SuccessHandlerConfig:
+ type: object
+ description: Configuration for the workspace success handler
+ properties: *ref_322
+ EditErrorHandler:
+ description: >-
+ Request body for editing the workspace error handler. Accepts both new
+ grouped format and legacy flat format for backward compatibility.
+ oneOf: *ref_323
+ EditErrorHandlerNew:
+ type: object
+ description: New grouped format for editing error handler
+ properties: *ref_324
+ EditErrorHandlerLegacy:
+ type: object
+ description: >-
+ Legacy flat format for editing error handler (deprecated, use new
+ format)
+ properties: *ref_325
+ EditSuccessHandler:
+ description: >-
+ Request body for editing the workspace success handler. Accepts both new
+ grouped format and legacy flat format for backward compatibility.
+ oneOf: *ref_326
+ EditSuccessHandlerNew:
+ type: object
+ description: New grouped format for editing success handler
+ properties: *ref_327
+ EditSuccessHandlerLegacy:
+ type: object
+ description: >-
+ Legacy flat format for editing success handler (deprecated, use new
+ format)
+ properties: *ref_328
+ VaultSettings:
+ type: object
+ required: *ref_22
+ properties: *ref_23
+ SecretMigrationFailure:
+ type: object
+ required: *ref_329
+ properties: *ref_330
+ SecretMigrationReport:
+ type: object
+ required: *ref_24
+ properties: *ref_25
+ JwksResponse:
+ type: object
+ required: *ref_331
+ properties: *ref_332
+ FlowConversation:
+ type: object
+ required: *ref_333
+ properties: *ref_334
+ FlowConversationMessage:
+ type: object
+ required: *ref_335
+ properties: *ref_336
EndpointTool:
type: object
- required: *ref_235
- properties: *ref_236
+ required: *ref_337
+ properties: *ref_338
AIProvider:
type: string
- enum: *ref_237
+ enum: *ref_339
GitSyncObjectType:
type: string
- enum: *ref_20
+ enum: *ref_36
AIProviderModel:
type: object
- properties: *ref_18
- required: *ref_19
+ properties: *ref_34
+ required: *ref_35
AIProviderConfig:
type: object
- properties: *ref_238
- required: *ref_239
+ properties: *ref_340
+ required: *ref_341
AIConfig:
type: object
- properties: *ref_21
+ properties: *ref_37
Alert:
type: object
- properties: *ref_240
- required: *ref_241
+ properties: *ref_342
+ required: *ref_343
Configs:
type: object
nullable: true
- properties: *ref_242
+ properties: *ref_344
+ WorkspaceDependencies:
+ type: object
+ properties: *ref_77
+ required: *ref_78
+ NewWorkspaceDependencies:
+ type: object
+ properties: *ref_345
+ required: *ref_346
Script:
type: object
- properties: *ref_51
- required: *ref_52
+ properties: *ref_79
+ required: *ref_80
NewScript:
type: object
- properties: *ref_56
- required: *ref_57
+ properties: *ref_84
+ required: *ref_85
NewScriptWithDraft:
- allOf: *ref_243
+ allOf: *ref_347
ScriptHistory:
type: object
- properties: *ref_58
- required: *ref_59
+ properties: *ref_86
+ required: *ref_87
ScriptArgs:
type: object
description: The arguments to pass to the script or flow
- additionalProperties: *ref_22
+ additionalProperties: true
Input:
type: object
- properties: *ref_194
- required: *ref_195
+ properties: *ref_249
+ required: *ref_250
CreateInput:
type: object
- properties: *ref_244
- required: *ref_245
+ properties: *ref_348
+ required: *ref_349
UpdateInput:
type: object
- properties: *ref_246
- required: *ref_247
+ properties: *ref_350
+ required: *ref_351
RunnableType:
type: string
- enum: *ref_248
+ enum: *ref_352
QueuedJob:
type: object
- properties: *ref_121
- required: *ref_122
+ properties: *ref_163
+ required: *ref_164
CompletedJob:
type: object
- properties: *ref_119
- required: *ref_120
+ properties: *ref_161
+ required: *ref_162
+ ExportableCompletedJob:
+ type: object
+ description: Completed job with full data for export/import operations
+ properties: *ref_150
+ required: *ref_151
+ ExportableQueuedJob:
+ type: object
+ description: Queued job with full data for export/import operations
+ properties: *ref_152
+ required: *ref_153
ObscuredJob:
type: object
- properties: *ref_249
+ properties: *ref_353
Job:
- oneOf: *ref_124
- discriminator: *ref_125
+ oneOf: *ref_165
+ discriminator: *ref_166
User:
type: object
- properties: *ref_10
- required: *ref_11
+ properties: *ref_26
+ required: *ref_27
+ UserSource:
+ type: object
+ properties: *ref_354
+ required: *ref_355
UserUsage:
type: object
- properties: *ref_250
+ properties: *ref_356
Login:
type: object
- properties: *ref_251
- required: *ref_252
+ properties: *ref_357
+ required: *ref_358
+ PasswordResetResponse:
+ type: object
+ properties: *ref_7
+ required: *ref_8
EditWorkspaceUser:
type: object
- properties: *ref_253
+ properties: *ref_359
TruncatedToken:
type: object
- properties: *ref_54
- required: *ref_55
+ properties: *ref_82
+ required: *ref_83
NewToken:
type: object
- properties: *ref_254
+ properties: *ref_360
NewTokenImpersonate:
type: object
- properties: *ref_255
- required: *ref_256
+ properties: *ref_361
+ required: *ref_362
ListableVariable:
type: object
- properties: *ref_32
- required: *ref_33
+ properties: *ref_49
+ required: *ref_50
ContextualVariable:
type: object
- properties: *ref_257
- required: *ref_258
+ properties: *ref_363
+ required: *ref_364
CreateVariable:
type: object
- properties: *ref_259
- required: *ref_260
+ properties: *ref_365
+ required: *ref_366
EditVariable:
type: object
- properties: *ref_261
+ properties: *ref_367
AuditLog:
type: object
- properties: *ref_1
- required: *ref_2
+ properties: *ref_5
+ required: *ref_6
MainArgSignature:
type: object
properties:
@@ -21375,51 +29791,55 @@ components:
- has_preprocessor
ScriptLang:
type: string
- enum: *ref_50
+ enum: *ref_76
Preview:
type: object
- properties: *ref_262
- required: *ref_263
+ properties: *ref_118
+ required: *ref_119
+ PreviewInline:
+ type: object
+ properties: *ref_368
+ required: *ref_369
WorkflowTask:
type: object
- properties: *ref_264
- required: *ref_265
+ properties: *ref_370
+ required: *ref_371
WorkflowStatusRecord:
type: object
additionalProperties:
type: object
- properties: *ref_113
+ properties: *ref_149
WorkflowStatus:
type: object
- properties: *ref_113
+ properties: *ref_149
CreateResource:
type: object
- properties: *ref_266
- required: *ref_267
+ properties: *ref_372
+ required: *ref_373
EditResource:
type: object
- properties: *ref_268
+ properties: *ref_374
Resource:
type: object
- properties: *ref_269
- required: *ref_270
+ properties: *ref_375
+ required: *ref_376
ListableResource:
type: object
- properties: *ref_271
- required: *ref_272
+ properties: *ref_377
+ required: *ref_378
ResourceType:
type: object
- properties: *ref_39
- required: *ref_40
+ properties: *ref_59
+ required: *ref_60
EditResourceType:
type: object
- properties: *ref_273
+ properties: *ref_379
Schedule:
type: object
- properties: *ref_128
- required: *ref_129
+ properties: *ref_170
+ required: *ref_171
ScheduleWJobs:
- allOf: *ref_274
+ allOf: *ref_380
ErrorHandler:
type: string
enum:
@@ -21429,300 +29849,369 @@ components:
- email
NewSchedule:
type: object
- properties: *ref_275
- required: *ref_276
+ properties: *ref_381
+ required: *ref_382
EditSchedule:
type: object
- properties: *ref_277
- required: *ref_278
+ properties: *ref_383
+ required: *ref_384
+ JobTriggerKind:
+ description: job trigger kind (schedule, http, websocket...)
+ type: string
+ enum: *ref_145
+ TriggerMode:
+ description: job trigger mode
+ type: string
+ enum: *ref_179
TriggerExtraProperty:
type: object
- properties: *ref_139
- required: *ref_140
+ properties: *ref_184
+ required: *ref_185
AuthenticationMethod:
type: string
- enum: *ref_134
+ enum: *ref_178
RunnableKind:
type: string
- enum: *ref_279
+ enum: *ref_172
OpenapiSpecFormat:
type: string
- enum: *ref_280
+ enum: *ref_385
OpenapiHttpRouteFilters:
type: object
- properties: *ref_281
- required: *ref_282
+ properties: *ref_386
+ required: *ref_387
WebhookFilters:
type: object
- properties: *ref_283
- required: *ref_284
+ properties: *ref_388
+ required: *ref_389
OpenapiV3Info:
type: object
- properties: *ref_285
- required: *ref_286
+ properties: *ref_390
+ required: *ref_391
GenerateOpenapiSpec:
type: object
- properties: *ref_130
+ properties: *ref_173
HttpMethod:
type: string
- enum: *ref_133
+ enum: *ref_176
+ HttpRequestType:
+ type: string
+ enum: *ref_177
HttpTrigger:
- allOf: *ref_135
+ allOf: *ref_180
type: object
- properties: *ref_136
- required: *ref_137
+ properties: *ref_181
+ required: *ref_182
NewHttpTrigger:
type: object
- properties: *ref_131
- required: *ref_132
+ properties: *ref_174
+ required: *ref_175
EditHttpTrigger:
type: object
- properties: *ref_287
- required: *ref_288
+ properties: *ref_392
+ required: *ref_393
TriggersCount:
type: object
- properties: *ref_73
+ properties: *ref_103
WebsocketTrigger:
- allOf: *ref_141
+ allOf: *ref_186
type: object
- properties: *ref_142
- required: *ref_143
+ properties: *ref_187
+ required: *ref_188
NewWebsocketTrigger:
type: object
- properties: *ref_289
- required: *ref_290
+ properties: *ref_394
+ required: *ref_395
EditWebsocketTrigger:
type: object
- properties: *ref_291
- required: *ref_292
+ properties: *ref_396
+ required: *ref_397
WebsocketTriggerInitialMessage:
- anyOf: *ref_138
+ anyOf: *ref_183
MqttQoS:
type: string
- enum: *ref_293
+ enum: *ref_398
MqttV3Config:
type: object
- properties: *ref_156
+ properties: *ref_208
MqttV5Config:
type: object
- properties: *ref_157
+ properties: *ref_209
MqttSubscribeTopic:
type: object
- properties: *ref_154
- required: *ref_155
+ properties: *ref_206
+ required: *ref_207
MqttClientVersion:
type: string
- enum: *ref_158
+ enum: *ref_210
MqttTrigger:
- allOf: *ref_159
+ allOf: *ref_211
type: object
- properties: *ref_160
- required: *ref_161
+ properties: *ref_212
+ required: *ref_213
NewMqttTrigger:
type: object
- properties: *ref_294
- required: *ref_295
+ properties: *ref_399
+ required: *ref_400
EditMqttTrigger:
type: object
- properties: *ref_296
- required: *ref_297
+ properties: *ref_401
+ required: *ref_402
DeliveryType:
type: string
- enum: *ref_164
+ enum: *ref_216
+ description: >-
+ Delivery mode for messages. 'push' for HTTP push delivery where messages
+ are sent to a webhook endpoint, 'pull' for polling where the trigger
+ actively fetches messages.
PushConfig:
type: object
- properties: *ref_165
- required: *ref_166
+ description: Configuration for push delivery mode.
+ properties: *ref_217
+ required: *ref_218
GcpTrigger:
- allOf: *ref_168
+ allOf: *ref_220
type: object
- properties: *ref_169
- required: *ref_170
+ description: >-
+ A Google Cloud Pub/Sub trigger that executes a script or flow when
+ messages are received.
+ properties: *ref_221
+ required: *ref_222
SubscriptionMode:
type: string
- enum: *ref_167
+ enum: *ref_219
description: >-
The mode of subscription. 'existing' means using an existing GCP
subscription, while 'create_update' involves creating or updating a new
subscription.
GcpTriggerData:
type: object
- properties: *ref_162
- required: *ref_163
+ description: Data for creating or updating a Google Cloud Pub/Sub trigger.
+ properties: *ref_214
+ required: *ref_215
GetAllTopicSubscription:
type: object
- properties: *ref_298
- required: *ref_299
+ properties: *ref_403
+ required: *ref_404
DeleteGcpSubscription:
type: object
- properties: *ref_300
- required: *ref_301
+ properties: *ref_405
+ required: *ref_406
AwsAuthResourceType:
type: string
- enum: *ref_150
+ enum: *ref_195
SqsTrigger:
- allOf: *ref_151
+ allOf: *ref_196
type: object
- properties: *ref_152
- required: *ref_153
+ properties: *ref_197
+ required: *ref_198
+ LoggedWizardStatus:
+ type: string
+ enum: *ref_17
+ CustomInstanceDbLogs:
+ type: object
+ properties: *ref_407
+ CustomInstanceDbTag:
+ type: string
+ enum: *ref_18
+ CustomInstanceDb:
+ type: object
+ required: *ref_19
+ properties: *ref_20
NewSqsTrigger:
type: object
- properties: *ref_302
- required: *ref_303
+ properties: *ref_408
+ required: *ref_409
EditSqsTrigger:
type: object
- properties: *ref_304
- required: *ref_305
+ properties: *ref_410
+ required: *ref_411
Slot:
type: object
- properties: *ref_171
+ properties: *ref_223
SlotList:
type: object
- properties: *ref_306
+ properties: *ref_412
PublicationData:
type: object
- properties: *ref_175
- required: *ref_176
+ properties: *ref_227
+ required: *ref_228
TableToTrack:
type: array
- items: *ref_307
+ items: *ref_413
Relations:
type: object
- properties: *ref_172
- required: *ref_173
+ properties: *ref_224
+ required: *ref_225
Language:
type: string
- enum: *ref_308
+ enum: *ref_414
TemplateScript:
type: object
- properties: *ref_309
- required: *ref_310
+ properties: *ref_415
+ required: *ref_416
PostgresTrigger:
- allOf: *ref_177
+ allOf: *ref_229
type: object
- properties: *ref_178
- required: *ref_179
+ properties: *ref_230
+ required: *ref_231
NewPostgresTrigger:
type: object
- properties: *ref_311
- required: *ref_312
+ properties: *ref_417
+ required: *ref_418
EditPostgresTrigger:
type: object
- properties: *ref_313
- required: *ref_314
+ properties: *ref_419
+ required: *ref_420
KafkaTrigger:
- allOf: *ref_144
+ allOf: *ref_189
type: object
- properties: *ref_145
- required: *ref_146
+ properties: *ref_190
+ required: *ref_191
NewKafkaTrigger:
type: object
- properties: *ref_315
- required: *ref_316
+ properties: *ref_421
+ required: *ref_422
EditKafkaTrigger:
type: object
- properties: *ref_317
- required: *ref_318
+ properties: *ref_423
+ required: *ref_424
NatsTrigger:
- allOf: *ref_147
+ allOf: *ref_192
type: object
- properties: *ref_148
- required: *ref_149
+ properties: *ref_193
+ required: *ref_194
NewNatsTrigger:
type: object
- properties: *ref_319
- required: *ref_320
+ properties: *ref_425
+ required: *ref_426
EditNatsTrigger:
type: object
- properties: *ref_321
- required: *ref_322
+ properties: *ref_427
+ required: *ref_428
+ EmailTrigger:
+ allOf: *ref_232
+ type: object
+ properties: *ref_233
+ required: *ref_234
+ NewEmailTrigger:
+ type: object
+ properties: *ref_429
+ required: *ref_430
+ EditEmailTrigger:
+ type: object
+ properties: *ref_431
+ required: *ref_432
Group:
type: object
- properties: *ref_185
- required: *ref_186
+ properties: *ref_240
+ required: *ref_241
InstanceGroup:
type: object
- properties: *ref_181
- required: *ref_182
+ required: *ref_236
+ properties: *ref_237
+ InstanceGroupWithWorkspaces:
+ type: object
+ required: *ref_433
+ properties: *ref_434
+ WorkspaceInfo:
+ type: object
+ properties: *ref_435
+ required: *ref_436
Folder:
type: object
- properties: *ref_187
- required: *ref_188
+ properties: *ref_242
+ required: *ref_243
WorkerPing:
type: object
- properties: *ref_323
- required: *ref_324
+ properties: *ref_437
+ required: *ref_438
UserWorkspaceList:
type: object
- properties: *ref_325
- required: *ref_326
+ properties: *ref_439
+ required: *ref_440
CreateWorkspace:
type: object
- properties: *ref_327
- required: *ref_328
+ properties: *ref_441
+ required: *ref_442
+ CreateWorkspaceFork:
+ type: object
+ properties: *ref_15
+ required: *ref_16
Workspace:
type: object
- properties: *ref_7
- required: *ref_8
+ properties: *ref_11
+ required: *ref_12
+ DependencyMap:
+ type: object
+ properties: *ref_443
+ DependencyDependent:
+ type: object
+ properties: *ref_444
+ required: *ref_445
+ DependentsAmount:
+ type: object
+ properties: *ref_446
+ required: *ref_447
WorkspaceInvite:
type: object
- properties: *ref_16
- required: *ref_17
+ properties: *ref_32
+ required: *ref_33
GlobalUserInfo:
type: object
- properties: *ref_14
- required: *ref_15
+ properties: *ref_30
+ required: *ref_31
Flow:
- allOf: *ref_72
+ allOf: *ref_102
ExtraPerms:
type: object
- additionalProperties: *ref_329
+ additionalProperties: *ref_448
FlowMetadata:
type: object
- properties: *ref_330
- required: *ref_331
+ properties: *ref_449
+ required: *ref_450
OpenFlowWPath:
- allOf: *ref_74
+ allOf: *ref_104
FlowPreview:
type: object
- properties: *ref_332
- required: *ref_333
+ properties: *ref_122
+ required: *ref_123
RestartedFrom:
type: object
- properties: *ref_334
+ properties: *ref_451
Policy:
type: object
- properties: *ref_75
+ properties: *ref_105
ListableApp:
type: object
- properties: *ref_335
- required: *ref_336
+ properties: *ref_452
+ required: *ref_453
ScopeDefinition:
type: object
- properties: *ref_337
- required: *ref_338
+ properties: *ref_454
+ required: *ref_455
ScopeDomain:
type: object
- properties: *ref_339
- required: *ref_340
+ properties: *ref_456
+ required: *ref_457
ListableRawApp:
type: object
- properties: *ref_341
- required: *ref_342
+ properties: *ref_458
+ required: *ref_459
AppWithLastVersion:
type: object
- properties: *ref_76
- required: *ref_77
+ properties: *ref_106
+ required: *ref_107
AppWithLastVersionWDraft:
- allOf: *ref_343
+ allOf: *ref_460
AppHistory:
type: object
- properties: *ref_78
- required: *ref_79
+ properties: *ref_108
+ required: *ref_109
FlowVersion:
type: object
- properties: *ref_70
- required: *ref_71
+ properties: *ref_100
+ required: *ref_101
SlackToken:
type: object
properties:
@@ -21744,143 +30233,200 @@ components:
- bot
TokenResponse:
type: object
- properties: *ref_36
- required: *ref_37
+ properties: *ref_56
+ required: *ref_57
HubScriptKind:
type: string
- enum: *ref_49
+ enum: *ref_75
PolarsClientKwargs:
type: object
- properties: *ref_198
- required: *ref_199
+ properties: *ref_253
+ required: *ref_254
LargeFileStorage:
type: object
- properties: *ref_23
+ properties: *ref_38
DucklakeSettings:
type: object
- required: *ref_24
- properties: *ref_25
+ required: *ref_39
+ properties: *ref_40
+ DataTableSettings:
+ type: object
+ required: *ref_41
+ properties: *ref_42
+ DataTableSchema:
+ type: object
+ required: *ref_461
+ properties: *ref_462
+ DynamicInputData:
+ type: object
+ properties: *ref_463
+ required: *ref_464
WindmillLargeFile:
type: object
- properties: *ref_344
- required: *ref_345
+ properties: *ref_255
+ required: *ref_256
WindmillFileMetadata:
type: object
- properties: *ref_346
+ properties: *ref_259
WindmillFilePreview:
type: object
- properties: *ref_347
- required: *ref_348
+ properties: *ref_257
+ required: *ref_258
S3Resource:
type: object
- properties: *ref_196
- required: *ref_197
+ properties: *ref_251
+ required: *ref_252
WorkspaceGitSyncSettings:
type: object
- properties: *ref_26
+ properties: *ref_43
WorkspaceDeployUISettings:
type: object
- properties: *ref_29
+ properties: *ref_46
WorkspaceDefaultScripts:
type: object
- properties: *ref_30
+ properties: *ref_47
+ S3PermissionRule:
+ type: object
+ properties: *ref_465
+ required: *ref_466
GitRepositorySettings:
type: object
- properties: *ref_27
- required: *ref_28
- UploadFilePart:
- type: object
- properties:
- part_number:
- type: integer
- tag:
- type: string
- required:
- - part_number
- - tag
+ properties: *ref_44
+ required: *ref_45
MetricMetadata:
type: object
- properties: *ref_349
- required: *ref_350
+ properties: *ref_467
+ required: *ref_468
ScalarMetric:
type: object
- properties: *ref_351
- required: *ref_352
+ properties: *ref_469
+ required: *ref_470
TimeseriesMetric:
type: object
- properties: *ref_353
- required: *ref_354
+ properties: *ref_471
+ required: *ref_472
MetricDataPoint:
type: object
- properties: *ref_355
- required: *ref_356
+ properties: *ref_473
+ required: *ref_474
RawScriptForDependencies:
type: object
- properties: *ref_357
- required: *ref_358
+ properties: *ref_475
+ required: *ref_476
ConcurrencyGroup:
type: object
- properties: *ref_359
- required: *ref_360
+ properties: *ref_477
+ required: *ref_478
ExtendedJobs:
type: object
- properties: *ref_361
- required: *ref_362
+ properties: *ref_479
+ required: *ref_480
ExportedUser:
type: object
- properties: *ref_3
- required: *ref_4
+ properties: *ref_9
+ required: *ref_10
GlobalSetting:
type: object
- properties: *ref_363
- required: *ref_364
+ properties: *ref_481
+ required: *ref_482
Config:
type: object
- properties: *ref_365
- required: *ref_366
+ properties: *ref_483
+ required: *ref_484
ExportedInstanceGroup:
type: object
- properties: *ref_183
- required: *ref_184
+ properties: *ref_238
+ required: *ref_239
JobSearchHit:
type: object
- properties: *ref_367
+ properties: *ref_485
LogSearchHit:
type: object
- properties: *ref_368
+ properties: *ref_486
AutoscalingEvent:
type: object
- properties: *ref_369
+ properties: *ref_487
CriticalAlert:
type: object
- properties: *ref_34
+ properties: *ref_51
CaptureTriggerKind:
type: string
- enum: *ref_189
+ enum: *ref_244
Capture:
type: object
- properties: *ref_190
- required: *ref_191
+ properties: *ref_245
+ required: *ref_246
CaptureConfig:
type: object
- properties: *ref_370
- required: *ref_371
+ properties: *ref_488
+ required: *ref_489
OperatorSettings:
nullable: true
type: object
- required: *ref_12
- properties: *ref_13
+ required: *ref_28
+ properties: *ref_29
+ WorkspaceComparison:
+ type: object
+ required: *ref_490
+ properties: *ref_491
+ WorkspaceItemDiff:
+ type: object
+ required: *ref_492
+ properties: *ref_493
+ CompareSummary:
+ type: object
+ required: *ref_494
+ properties: *ref_495
TeamInfo:
type: object
- required: *ref_372
- properties: *ref_373
+ required:
+ - team_id
+ - team_name
+ - channels
+ properties:
+ team_id:
+ type: string
+ description: The unique identifier of the Microsoft Teams team
+ example: 19:abc123def456@thread.tacv2
+ team_name:
+ type: string
+ description: The display name of the Microsoft Teams team
+ example: Engineering Team
+ channels:
+ type: array
+ description: List of channels within the team
+ items:
+ type: object
+ required: &ref_496
+ - channel_id
+ - channel_name
+ - tenant_id
+ - service_url
+ properties: &ref_497
+ channel_id:
+ type: string
+ description: The unique identifier of the channel
+ example: 19:channel123@thread.tacv2
+ channel_name:
+ type: string
+ description: The display name of the channel
+ example: General
+ tenant_id:
+ type: string
+ description: The Microsoft Teams tenant identifier
+ example: 12345678-1234-1234-1234-123456789012
+ service_url:
+ type: string
+ description: The service URL for the channel
+ example: >-
+ https://smba.trafficmanager.net/amer/12345678-1234-1234-1234-123456789012/
ChannelInfo:
type: object
- required: *ref_374
- properties: *ref_375
+ required: *ref_496
+ properties: *ref_497
GithubInstallations:
type: array
- items: *ref_376
+ items: *ref_498
WorkspaceGithubInstallation:
type: object
properties:
@@ -21893,8 +30439,8 @@ components:
- installation_id
S3Object:
type: object
- properties: *ref_82
- required: *ref_83
+ properties: *ref_112
+ required: *ref_113
TeamsChannel:
type: object
required:
@@ -21921,13 +30467,14 @@ components:
minLength: 1
AssetUsageKind:
type: string
- enum: *ref_203
+ enum: *ref_264
AssetUsageAccessType:
type: string
- enum: *ref_204
+ enum: *ref_263
+ nullable: true
AssetKind:
type: string
- enum: *ref_202
+ enum: *ref_262
Asset:
type: object
properties:
@@ -21935,72 +30482,337 @@ components:
type: string
kind:
type: string
- enum: *ref_202
+ enum: *ref_262
required:
- path
- kind
+ ProtectionRuleset:
+ type: object
+ description: A workspace protection rule defining restrictions and bypass permissions
+ required: *ref_499
+ properties: *ref_500
+ ProtectionRules:
+ type: array
+ description: Configuration of protection restrictions
+ items: *ref_52
+ ProtectionRuleKind:
+ type: string
+ enum: *ref_501
+ RuleBypasserGroups:
+ type: array
+ description: Groups that can bypass this ruleset
+ items: *ref_53
+ RuleBypasserUsers:
+ type: array
+ description: Users that can bypass this ruleset
+ items: *ref_54
+ NativeServiceName:
+ type: string
+ enum: *ref_199
+ NativeTrigger:
+ type: object
+ description: A native trigger stored in Windmill
+ properties: *ref_502
+ required: *ref_503
+ NativeTriggerWithExternal:
+ type: object
+ description: >-
+ Full trigger response containing both Windmill data and external service
+ data
+ properties: *ref_504
+ required: *ref_505
+ WorkspaceIntegrations:
+ type: object
+ properties: *ref_506
+ required: *ref_507
+ WorkspaceOAuthConfig:
+ type: object
+ properties: *ref_200
+ required: *ref_201
+ WebhookEvent:
+ type: object
+ properties:
+ type:
+ type: string
+ enum:
+ - webhook
+ request_type:
+ type: string
+ description: The type of webhook request (define possible values here)
+ enum: &ref_508
+ - async
+ - sync
+ required:
+ - type
+ - request_type
+ WebhookRequestType:
+ type: string
+ description: The type of webhook request (define possible values here)
+ enum: *ref_508
+ RedirectUri:
+ type: object
+ properties: *ref_202
+ required: *ref_203
+ NativeTriggerData:
+ type: object
+ description: Data for creating or updating a native trigger
+ properties: *ref_204
+ required: *ref_205
+ CreateTriggerResponse:
+ type: object
+ description: Response returned when a native trigger is created
+ properties: *ref_509
+ required: *ref_510
+ SyncResult:
+ type: object
+ properties:
+ already_in_sync:
+ type: boolean
+ added_count:
+ type: integer
+ added_triggers:
+ type: array
+ items:
+ type: string
+ total_external:
+ type: integer
+ total_windmill:
+ type: integer
+ required:
+ - already_in_sync
+ - added_count
+ - added_triggers
+ - total_external
+ - total_windmill
+ NextCloudEventType:
+ type: object
+ properties: *ref_511
+ required: *ref_512
schemas-StaticTransform:
type: object
- properties: *ref_84
- required: *ref_85
+ description: >-
+ Static value passed directly to the step. Use for hardcoded values or
+ resource references like '$res:path/to/resource'
+ properties: *ref_114
+ required: *ref_115
schemas-JavascriptTransform:
type: object
- properties: *ref_86
- required: *ref_87
+ description: >-
+ JavaScript expression evaluated at runtime. Can reference previous step
+ results via 'results.step_id' or flow inputs via 'flow_input.property'.
+ Inside loops, use 'flow_input.iter.value' for the current iteration
+ value
+ properties: *ref_66
+ required: *ref_67
+ schemas-AiTransform:
+ type: object
+ description: >-
+ Value resolved by the AI runtime for this input. The AI engine decides
+ how to satisfy the parameter.
+ properties: *ref_68
+ required: *ref_69
schemas-InputTransform:
- oneOf: *ref_42
- discriminator: *ref_43
+ description: >-
+ Maps input parameters for a step. Can be a static value or a JavaScript
+ expression that references previous results or flow inputs
+ oneOf: *ref_62
+ discriminator: *ref_63
schemas-RawScript:
type: object
- properties: *ref_219
- required: *ref_220
+ description: >-
+ Inline script with code defined directly in the flow. Use 'bun' as
+ default language if unspecified. The script receives arguments from
+ input_transforms
+ properties: *ref_284
+ required: *ref_285
schemas-PathScript:
type: object
- properties: *ref_221
- required: *ref_222
+ description: >-
+ Reference to an existing script by path. Use this when calling a
+ previously saved script instead of writing inline code
+ properties: *ref_286
+ required: *ref_287
schemas-PathFlow:
type: object
- properties: *ref_223
- required: *ref_224
+ description: >-
+ Reference to an existing flow by path. Use this to call another flow as
+ a subflow
+ properties: *ref_288
+ required: *ref_289
schemas-FlowModule:
type: object
- properties: *ref_44
- required: *ref_45
+ description: A single step in a flow. Can be a script, subflow, loop, or branch
+ properties: *ref_64
+ required: *ref_65
schemas-ForloopFlow:
type: object
- properties: *ref_225
- required: *ref_226
+ description: >-
+ Executes nested modules in a loop over an iterator. Inside the loop, use
+ 'flow_input.iter.value' to access the current iteration value, and
+ 'flow_input.iter.index' for the index. Supports parallel execution for
+ better performance on I/O-bound operations
+ properties: *ref_290
+ required: *ref_291
schemas-WhileloopFlow:
type: object
- properties: *ref_227
- required: *ref_228
+ description: >-
+ Executes nested modules repeatedly while a condition is true. The loop
+ checks the condition after each iteration. Use stop_after_if on modules
+ to control loop termination
+ properties: *ref_292
+ required: *ref_293
schemas-BranchOne:
type: object
- properties: *ref_229
- required: *ref_230
+ description: >-
+ Conditional branching where only the first matching branch executes.
+ Branches are evaluated in order, and the first one with a true
+ expression runs. If no branches match, the default branch executes
+ properties: *ref_294
+ required: *ref_295
schemas-BranchAll:
type: object
- properties: *ref_231
- required: *ref_232
+ description: >-
+ Parallel branching where all branches execute simultaneously. Unlike
+ BranchOne, all branches run regardless of conditions. Useful for
+ executing independent tasks concurrently
+ properties: *ref_296
+ required: *ref_297
schemas-Identity:
type: object
- properties: *ref_233
- required: *ref_234
+ description: >-
+ Pass-through module that returns its input unchanged. Useful for flow
+ structure or as a placeholder
+ properties: *ref_298
+ required: *ref_299
+ AIProviderKind:
+ type: string
+ description: Supported AI provider types
+ enum: *ref_277
+ schemas-ProviderConfig:
+ type: object
+ description: >-
+ Complete AI provider configuration with resource reference and model
+ selection
+ properties: *ref_513
+ required: *ref_514
+ StaticProviderTransform:
+ type: object
+ description: Static provider configuration passed directly to the AI agent
+ properties: *ref_515
+ required: *ref_516
+ ProviderTransform:
+ description: >-
+ Provider configuration - can be static (ProviderConfig), JavaScript
+ expression, or AI-determined
+ oneOf: *ref_302
+ discriminator: *ref_303
+ MemoryOff:
+ type: object
+ description: No conversation memory/context
+ properties: *ref_278
+ required: *ref_279
+ MemoryAuto:
+ type: object
+ description: Automatic context management
+ properties: *ref_280
+ required: *ref_281
+ MemoryMessage:
+ type: object
+ description: A single message in conversation history
+ properties: *ref_517
+ required: *ref_518
+ MemoryManual:
+ type: object
+ description: Explicit message history
+ properties: *ref_282
+ required: *ref_283
+ schemas-MemoryConfig:
+ description: Conversation memory configuration
+ oneOf: *ref_519
+ discriminator: *ref_520
+ StaticMemoryTransform:
+ type: object
+ description: Static memory configuration passed directly to the AI agent
+ properties: *ref_521
+ required: *ref_522
+ MemoryTransform:
+ description: >-
+ Memory configuration - can be static (MemoryConfig), JavaScript
+ expression, or AI-determined
+ oneOf: *ref_304
+ discriminator: *ref_305
schemas-FlowModuleValue:
- oneOf: *ref_216
- discriminator: *ref_217
+ description: >-
+ The actual implementation of a flow step. Can be a script (inline or
+ referenced), subflow, loop, branch, or special module type
+ oneOf: *ref_70
+ discriminator: *ref_71
+ FlowModuleTool:
+ description: >-
+ A tool implemented as a flow module (script, flow, etc.). The AI can
+ call this like any other flow module
+ allOf: *ref_523
+ McpToolValue:
+ type: object
+ description: >-
+ Reference to an external MCP (Model Context Protocol) tool. The AI can
+ call tools from MCP servers
+ properties: *ref_524
+ required: *ref_525
+ WebsearchToolValue:
+ type: object
+ description: >-
+ A tool implemented as a websearch tool. The AI can call this like any
+ other websearch tool
+ properties: *ref_526
+ required: *ref_527
+ ToolValue:
+ description: >-
+ The implementation of a tool. Can be a flow module (script/flow) or an
+ MCP tool reference
+ oneOf: *ref_528
+ discriminator: *ref_529
+ AgentTool:
+ type: object
+ description: >-
+ A tool available to an AI agent. Can be a flow module or an external MCP
+ (Model Context Protocol) tool
+ properties: *ref_306
+ required: *ref_307
+ schemas-AiAgent:
+ type: object
+ description: >-
+ AI agent step that can use tools to accomplish tasks. The agent receives
+ inputs and can call any of its configured tools to complete the task
+ properties: *ref_300
+ required: *ref_301
schemas-StopAfterIf:
type: object
- properties: *ref_46
- required: *ref_47
+ description: Early termination condition for a module
+ properties: *ref_72
+ required: *ref_73
+ RetryIf:
+ type: object
+ description: Conditional retry based on error or result
+ properties: *ref_167
+ required: *ref_168
schemas-Retry:
type: object
- properties: *ref_218
+ description: Retry configuration for failed module executions
+ properties: *ref_276
+ schemas-FlowNote:
+ type: object
+ description: A sticky note attached to a flow for documentation and annotation
+ properties: *ref_120
+ required: *ref_121
schemas-FlowValue:
type: object
- properties: *ref_377
- required: *ref_378
+ description: >-
+ The flow structure containing modules and optional preprocessor/failure
+ handlers
+ properties: *ref_530
+ required: *ref_531
schemas-FlowStatusModule:
type: object
- properties: *ref_90
- required: *ref_91
+ properties: *ref_124
+ required: *ref_125
diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml
index def7870bed..ab1e0c9f6f 100644
--- a/backend/windmill-api/openapi.yaml
+++ b/backend/windmill-api/openapi.yaml
@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
- version: 1.630.2
+ version: 1.635.1
title: Windmill API
contact:
@@ -41,6 +41,64 @@ paths:
schema:
type: string
+ /health/status:
+ get:
+ summary: health status
+ description: |
+ Health status endpoint. Returns cached health status (database connectivity, worker count).
+ Cache TTL is fixed at 5 seconds. Use force=true query parameter to bypass cache.
+ Note: This endpoint is intentionally different from Kubernetes probes to avoid confusion.
+ For k8s liveness/readiness probes, use /version endpoint.
+ operationId: getHealthStatus
+ tags:
+ - health
+ security: []
+ parameters:
+ - name: force
+ in: query
+ description: Force a fresh check, bypassing the cache
+ required: false
+ schema:
+ type: boolean
+ default: false
+ responses:
+ "200":
+ description: server is healthy or degraded
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/HealthStatusResponse"
+ "503":
+ description: server is unhealthy (database unreachable)
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/HealthStatusResponse"
+
+ /health/detailed:
+ get:
+ summary: detailed health status
+ description: |
+ Returns detailed health information including database pool stats, worker details, and queue status.
+ Requires authentication. Use for monitoring dashboards and debugging.
+ This endpoint always returns fresh data (no caching).
+ operationId: getHealthDetailed
+ tags:
+ - health
+ responses:
+ "200":
+ description: server is healthy or degraded
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/DetailedHealthResponse"
+ "503":
+ description: server is unhealthy (database unreachable)
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/DetailedHealthResponse"
+
/uptodate:
get:
summary: is backend up to date
@@ -1425,6 +1483,39 @@ paths:
items:
$ref: "#/components/schemas/GlobalSetting"
+ /settings/instance_config:
+ get:
+ summary: get full instance config (global settings + worker configs)
+ operationId: getInstanceConfig
+ tags:
+ - setting
+ responses:
+ "200":
+ description: full instance configuration
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InstanceConfig"
+ put:
+ summary: update instance config (bulk upsert, no deletes). Empty or missing global_settings/worker_configs are skipped.
+ operationId: setInstanceConfig
+ tags:
+ - setting
+ requestBody:
+ description: full instance configuration to apply
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InstanceConfig"
+ responses:
+ "200":
+ description: instance config updated
+ content:
+ text/plain:
+ schema:
+ type: string
+
/min_keep_alive_version:
get:
summary: get minimum worker versions required to stay alive
@@ -17416,6 +17507,167 @@ components:
# -- INLINE END --
# Do not change line above
+ HealthStatusResponse:
+ type: object
+ description: Health status response (cached with 5s TTL)
+ required:
+ - status
+ - checked_at
+ - database_healthy
+ - workers_alive
+ properties:
+ status:
+ type: string
+ enum: [healthy, degraded, unhealthy]
+ description: Overall health status
+ checked_at:
+ type: string
+ format: date-time
+ description: Timestamp when the health check was actually performed (not cache return time)
+ database_healthy:
+ type: boolean
+ description: Whether the database is reachable
+ workers_alive:
+ type: integer
+ format: int64
+ description: Number of workers that pinged within last 5 minutes
+
+ DetailedHealthResponse:
+ type: object
+ description: Detailed health status response (always fresh, no caching)
+ required:
+ - status
+ - checked_at
+ - version
+ - checks
+ properties:
+ status:
+ type: string
+ enum: [healthy, degraded, unhealthy]
+ description: Overall health status
+ checked_at:
+ type: string
+ format: date-time
+ description: Timestamp when the health check was performed
+ version:
+ type: string
+ description: Server version (e.g., "EE 1.615.3")
+ checks:
+ $ref: "#/components/schemas/HealthChecks"
+
+ HealthChecks:
+ type: object
+ description: Detailed health checks
+ required:
+ - database
+ - readiness
+ properties:
+ database:
+ $ref: "#/components/schemas/DatabaseHealth"
+ workers:
+ $ref: "#/components/schemas/WorkersHealth"
+ description: Worker status (null if database is unreachable)
+ nullable: true
+ queue:
+ $ref: "#/components/schemas/QueueHealth"
+ description: Queue status (null if database is unreachable)
+ nullable: true
+ readiness:
+ $ref: "#/components/schemas/ReadinessHealth"
+
+ DatabaseHealth:
+ type: object
+ description: Database health status
+ required:
+ - healthy
+ - latency_ms
+ - pool
+ properties:
+ healthy:
+ type: boolean
+ description: Whether the database is reachable
+ latency_ms:
+ type: integer
+ format: int64
+ description: Database query latency in milliseconds
+ pool:
+ $ref: "#/components/schemas/PoolStats"
+
+ PoolStats:
+ type: object
+ description: Database connection pool statistics
+ required:
+ - size
+ - idle
+ - max_connections
+ properties:
+ size:
+ type: integer
+ description: Current number of connections in the pool
+ idle:
+ type: integer
+ description: Number of idle connections
+ max_connections:
+ type: integer
+ description: Maximum number of connections allowed
+
+ WorkersHealth:
+ type: object
+ description: Workers health status
+ required:
+ - healthy
+ - active_count
+ - worker_groups
+ - min_version
+ - versions
+ properties:
+ healthy:
+ type: boolean
+ description: Whether any workers are active
+ active_count:
+ type: integer
+ format: int64
+ description: Number of active workers (pinged in last 5 minutes)
+ worker_groups:
+ type: array
+ items:
+ type: string
+ description: List of active worker groups
+ min_version:
+ type: string
+ description: Minimum required worker version
+ versions:
+ type: array
+ items:
+ type: string
+ description: List of active worker versions
+
+ QueueHealth:
+ type: object
+ description: Job queue status
+ required:
+ - pending_jobs
+ - running_jobs
+ properties:
+ pending_jobs:
+ type: integer
+ format: int64
+ description: Number of pending jobs in the queue
+ running_jobs:
+ type: integer
+ format: int64
+ description: Number of currently running jobs
+
+ ReadinessHealth:
+ type: object
+ description: Server readiness status
+ required:
+ - healthy
+ properties:
+ healthy:
+ type: boolean
+ description: Whether the server is ready to accept requests
+
AutoInviteConfig:
type: object
description: Configuration for auto-inviting users to the workspace
@@ -19496,6 +19748,7 @@ components:
description: True if script_path points to a flow, false if it points to a script
args:
$ref: "#/components/schemas/ScriptArgs"
+ nullable: true
extra_perms:
type: object
additionalProperties:
@@ -19506,57 +19759,74 @@ components:
description: Email of the user who owns this schedule, used for permissioned_as
error:
type: string
+ nullable: true
description: Last error message if the schedule failed to trigger
on_failure:
type: string
+ nullable: true
description: Path to a script or flow to run when the scheduled job fails
on_failure_times:
type: number
+ nullable: true
description: Number of consecutive failures before the on_failure handler is triggered (default 1)
on_failure_exact:
type: boolean
+ nullable: true
description: If true, trigger on_failure handler only on exactly N failures, not on every failure after N
on_failure_extra_args:
$ref: "#/components/schemas/ScriptArgs"
+ nullable: true
on_recovery:
type: string
+ nullable: true
description: Path to a script or flow to run when the schedule recovers after failures
on_recovery_times:
type: number
+ nullable: true
description: Number of consecutive successes before the on_recovery handler is triggered (default 1)
on_recovery_extra_args:
$ref: "#/components/schemas/ScriptArgs"
+ nullable: true
on_success:
type: string
+ nullable: true
description: Path to a script or flow to run after each successful execution
on_success_extra_args:
$ref: "#/components/schemas/ScriptArgs"
+ nullable: true
ws_error_handler_muted:
type: boolean
description: If true, the workspace-level error handler will not be triggered for this schedule's failures
retry:
$ref: "../../openflow.openapi.yaml#/components/schemas/Retry"
+ nullable: true
summary:
type: string
+ nullable: true
description: Short summary describing the purpose of this schedule
description:
type: string
+ nullable: true
description: Detailed description of what this schedule does
no_flow_overlap:
type: boolean
description: If true, skip this schedule's execution if the previous run is still in progress (prevents concurrent runs)
tag:
type: string
+ nullable: true
description: Worker tag to route jobs to specific worker groups
paused_until:
type: string
format: date-time
+ nullable: true
description: ISO 8601 datetime until which the schedule is paused. Schedule resumes automatically after this time
cron_version:
type: string
+ nullable: true
description: Cron parser version. Use 'v2' for extended syntax with additional features
dynamic_skip:
type: string
+ nullable: true
description: Path to a script that validates scheduled datetimes. Receives scheduled_for datetime and returns boolean to skip (true) or run (false)
required:
- path
@@ -19618,60 +19888,77 @@ components:
type: boolean
description: True if script_path points to a flow, false if it points to a script
args:
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
enabled:
type: boolean
description: Whether the schedule is currently active and will trigger jobs
on_failure:
type: string
+ nullable: true
description: Path to a script or flow to run when the scheduled job fails
on_failure_times:
type: number
+ nullable: true
description: Number of consecutive failures before the on_failure handler is triggered (default 1)
on_failure_exact:
type: boolean
+ nullable: true
description: If true, trigger on_failure handler only on exactly N failures, not on every failure after N
on_failure_extra_args:
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
on_recovery:
type: string
+ nullable: true
description: Path to a script or flow to run when the schedule recovers after failures
on_recovery_times:
type: number
+ nullable: true
description: Number of consecutive successes before the on_recovery handler is triggered (default 1)
on_recovery_extra_args:
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
on_success:
type: string
+ nullable: true
description: Path to a script or flow to run after each successful execution
on_success_extra_args:
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
ws_error_handler_muted:
type: boolean
description: If true, the workspace-level error handler will not be triggered for this schedule's failures
retry:
+ nullable: true
$ref: "../../openflow.openapi.yaml#/components/schemas/Retry"
no_flow_overlap:
type: boolean
description: If true, skip this schedule's execution if the previous run is still in progress (prevents concurrent runs)
summary:
type: string
+ nullable: true
description: Short summary describing the purpose of this schedule
description:
type: string
+ nullable: true
description: Detailed description of what this schedule does
tag:
type: string
+ nullable: true
description: Worker tag to route jobs to specific worker groups
paused_until:
type: string
+ nullable: true
format: date-time
description: ISO 8601 datetime until which the schedule is paused. Schedule resumes automatically after this time
cron_version:
type: string
+ nullable: true
description: Cron parser version. Use 'v2' for extended syntax with additional features
dynamic_skip:
type: string
+ nullable: true
description: Path to a script that validates scheduled datetimes. Receives scheduled_for datetime and returns boolean to skip (true) or run (false)
required:
- path
@@ -19691,57 +19978,74 @@ components:
type: string
description: IANA timezone for the schedule (e.g., 'UTC', 'Europe/Paris', 'America/New_York')
args:
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
on_failure:
type: string
+ nullable: true
description: Path to a script or flow to run when the scheduled job fails
on_failure_times:
type: number
+ nullable: true
description: Number of consecutive failures before the on_failure handler is triggered (default 1)
on_failure_exact:
type: boolean
+ nullable: true
description: If true, trigger on_failure handler only on exactly N failures, not on every failure after N
on_failure_extra_args:
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
on_recovery:
type: string
+ nullable: true
description: Path to a script or flow to run when the schedule recovers after failures
on_recovery_times:
type: number
+ nullable: true
description: Number of consecutive successes before the on_recovery handler is triggered (default 1)
on_recovery_extra_args:
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
on_success:
type: string
+ nullable: true
description: Path to a script or flow to run after each successful execution
on_success_extra_args:
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
ws_error_handler_muted:
type: boolean
description: If true, the workspace-level error handler will not be triggered for this schedule's failures
retry:
+ nullable: true
$ref: "../../openflow.openapi.yaml#/components/schemas/Retry"
no_flow_overlap:
type: boolean
description: If true, skip this schedule's execution if the previous run is still in progress (prevents concurrent runs)
summary:
type: string
+ nullable: true
description: Short summary describing the purpose of this schedule
description:
type: string
+ nullable: true
description: Detailed description of what this schedule does
tag:
type: string
+ nullable: true
description: Worker tag to route jobs to specific worker groups
paused_until:
type: string
+ nullable: true
format: date-time
description: ISO 8601 datetime until which the schedule is paused. Schedule resumes automatically after this time
cron_version:
type: string
+ nullable: true
description: Cron parser version. Use 'v2' for extended syntax with additional features
dynamic_skip:
type: string
+ nullable: true
description: Path to a script that validates scheduled datetimes. Receives scheduled_for datetime and returns boolean to skip (true) or run (false)
required:
- schedule
@@ -19953,6 +20257,7 @@ components:
description: The URL route path that will trigger this endpoint (e.g., 'api/myendpoint'). Must NOT start with a /.
static_asset_config:
type: object
+ nullable: true
description: Configuration for serving static assets (s3 bucket, storage path, filename)
properties:
s3:
@@ -19971,12 +20276,15 @@ components:
description: HTTP method (get, post, put, delete, patch) that triggers this endpoint
authentication_resource_path:
type: string
+ nullable: true
description: Path to the resource containing authentication configuration (for api_key, basic_http, custom_script, signature methods)
summary:
type: string
+ nullable: true
description: Short summary describing the purpose of this trigger
description:
type: string
+ nullable: true
description: Detailed description of what this trigger does
request_type:
$ref: "#/components/schemas/HttpRequestType"
@@ -20033,12 +20341,15 @@ components:
description: If true, the route includes the workspace ID in the path
summary:
type: string
+ nullable: true
description: Short summary describing the purpose of this trigger
description:
type: string
+ nullable: true
description: Detailed description of what this trigger does
static_asset_config:
type: object
+ nullable: true
description: Configuration for serving static assets (s3 bucket, storage path, filename)
properties:
s3:
@@ -20060,6 +20371,7 @@ components:
description: HTTP method (get, post, put, delete, patch) that triggers this endpoint
authentication_resource_path:
type: string
+ nullable: true
description: Path to the resource containing authentication configuration (for api_key, basic_http, custom_script, signature methods)
is_async:
type: boolean
@@ -20114,15 +20426,18 @@ components:
description: The URL route path that will trigger this endpoint (e.g., 'api/myendpoint'). Must NOT start with a /.
summary:
type: string
+ nullable: true
description: Short summary describing the purpose of this trigger
description:
type: string
+ nullable: true
description: Detailed description of what this trigger does
workspaced_route:
type: boolean
description: If true, the route includes the workspace ID in the path
static_asset_config:
type: object
+ nullable: true
description: Configuration for serving static assets (s3 bucket, storage path, filename)
properties:
s3:
@@ -20138,6 +20453,7 @@ components:
- s3
authentication_resource_path:
type: string
+ nullable: true
description: Path to the resource containing authentication configuration (for api_key, basic_http, custom_script, signature methods)
is_flow:
type: boolean
@@ -20248,12 +20564,14 @@ components:
- value
initial_messages:
type: array
+ nullable: true
description: Messages to send immediately after connecting (can be raw strings or computed by runnables)
items:
$ref: "#/components/schemas/WebsocketTriggerInitialMessage"
url_runnable_args:
description: Arguments to pass to the script/flow that computes the WebSocket URL
$ref: "#/components/schemas/ScriptArgs"
+ nullable: true
can_return_message:
type: boolean
description: If true, the script can return a message to send back through the WebSocket
@@ -20307,11 +20625,13 @@ components:
- value
initial_messages:
type: array
+ nullable: true
description: Messages to send immediately after connecting (can be raw strings or computed by runnables)
items:
$ref: "#/components/schemas/WebsocketTriggerInitialMessage"
url_runnable_args:
description: Arguments to pass to the script/flow that computes the WebSocket URL
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
can_return_message:
type: boolean
@@ -20367,11 +20687,13 @@ components:
- value
initial_messages:
type: array
+ nullable: true
description: Messages to send immediately after connecting (can be raw strings or computed by runnables)
items:
$ref: "#/components/schemas/WebsocketTriggerInitialMessage"
url_runnable_args:
description: Arguments to pass to the script/flow that computes the WebSocket URL
+ nullable: true
$ref: "#/components/schemas/ScriptArgs"
can_return_message:
type: boolean
@@ -20473,15 +20795,19 @@ components:
description: Array of MQTT topics to subscribe to, each with topic name and QoS level
v3_config:
$ref: "#/components/schemas/MqttV3Config"
+ nullable: true
description: MQTT v3 specific configuration (clean_session)
v5_config:
$ref: "#/components/schemas/MqttV5Config"
+ nullable: true
description: MQTT v5 specific configuration (clean_start, topic_alias_maximum, session_expiry_interval)
client_id:
type: string
+ nullable: true
description: MQTT client ID for this connection
client_version:
$ref: "#/components/schemas/MqttClientVersion"
+ nullable: true
description: MQTT protocol version ('v3' or 'v5')
server_id:
type: string
@@ -20519,14 +20845,18 @@ components:
description: Array of MQTT topics to subscribe to, each with topic name and QoS level
client_id:
type: string
+ nullable: true
description: MQTT client ID for this connection
v3_config:
+ nullable: true
$ref: "#/components/schemas/MqttV3Config"
description: MQTT v3 specific configuration (clean_session)
v5_config:
+ nullable: true
$ref: "#/components/schemas/MqttV5Config"
description: MQTT v5 specific configuration (clean_start, topic_alias_maximum, session_expiry_interval)
client_version:
+ nullable: true
$ref: "#/components/schemas/MqttClientVersion"
description: MQTT protocol version ('v3' or 'v5')
path:
@@ -20569,14 +20899,18 @@ components:
description: Array of MQTT topics to subscribe to, each with topic name and QoS level
client_id:
type: string
+ nullable: true
description: MQTT client ID for this connection
v3_config:
+ nullable: true
$ref: "#/components/schemas/MqttV3Config"
description: MQTT v3 specific configuration (clean_session)
v5_config:
+ nullable: true
$ref: "#/components/schemas/MqttV5Config"
description: MQTT v5 specific configuration (clean_start, topic_alias_maximum, session_expiry_interval)
client_version:
+ nullable: true
$ref: "#/components/schemas/MqttClientVersion"
description: MQTT protocol version ('v3' or 'v5')
path:
@@ -20650,6 +20984,7 @@ components:
$ref: "#/components/schemas/DeliveryType"
delivery_config:
$ref: "#/components/schemas/PushConfig"
+ nullable: true
subscription_mode:
$ref: "#/components/schemas/SubscriptionMode"
last_server_ping:
@@ -20703,6 +21038,7 @@ components:
delivery_type:
$ref: "#/components/schemas/DeliveryType"
delivery_config:
+ nullable: true
$ref: "#/components/schemas/PushConfig"
path:
type: string
@@ -20779,6 +21115,7 @@ components:
description: Path to the AWS resource containing credentials or OIDC configuration
message_attributes:
type: array
+ nullable: true
items:
type: string
description: Array of SQS message attribute names to include with each message
@@ -20870,6 +21207,7 @@ components:
description: Path to the AWS resource containing credentials or OIDC configuration
message_attributes:
type: array
+ nullable: true
items:
type: string
description: Array of SQS message attribute names to include with each message
@@ -20915,6 +21253,7 @@ components:
description: Path to the AWS resource containing credentials or OIDC configuration
message_attributes:
type: array
+ nullable: true
items:
type: string
description: Array of SQS message attribute names to include with each message
@@ -21321,9 +21660,11 @@ components:
description: If true, uses NATS JetStream for durable message delivery
stream_name:
type: string
+ nullable: true
description: JetStream stream name (required when use_jetstream is true)
consumer_name:
type: string
+ nullable: true
description: JetStream consumer name (required when use_jetstream is true)
subjects:
type: array
@@ -21375,9 +21716,11 @@ components:
description: If true, uses NATS JetStream for durable message delivery
stream_name:
type: string
+ nullable: true
description: JetStream stream name (required when use_jetstream is true)
consumer_name:
type: string
+ nullable: true
description: JetStream consumer name (required when use_jetstream is true)
subjects:
type: array
@@ -21415,9 +21758,11 @@ components:
description: If true, uses NATS JetStream for durable message delivery
stream_name:
type: string
+ nullable: true
description: JetStream stream name (required when use_jetstream is true)
consumer_name:
type: string
+ nullable: true
description: JetStream consumer name (required when use_jetstream is true)
subjects:
type: array
@@ -22672,6 +23017,26 @@ components:
- name
- value
+ InstanceConfig:
+ type: object
+ description: Unified instance configuration combining global settings and worker group configs
+ properties:
+ global_settings:
+ type: object
+ description: >
+ Global settings keyed by setting name. Known fields include base_url,
+ license_key, retention_period_secs, smtp_settings, otel, etc.
+ Unknown fields are preserved as-is.
+ additionalProperties: true
+ worker_configs:
+ type: object
+ description: >
+ Worker group configurations keyed by group name (e.g. "default", "gpu").
+ Each value contains worker_tags, init_bash, autoscaling, etc.
+ additionalProperties:
+ type: object
+ additionalProperties: true
+
Config:
type: object
properties:
diff --git a/backend/windmill-api/src/ai.rs b/backend/windmill-api/src/ai.rs
index 34e11e692a..20c6d7548b 100644
--- a/backend/windmill-api/src/ai.rs
+++ b/backend/windmill-api/src/ai.rs
@@ -166,9 +166,18 @@ struct AIStandardResource {
deserialize_with = "empty_string_as_none"
)]
aws_secret_access_key: Option,
+ #[serde(
+ alias = "awsSessionToken",
+ default,
+ deserialize_with = "empty_string_as_none"
+ )]
+ aws_session_token: Option,
/// Platform for Anthropic API (standard or google_vertex_ai)
#[serde(default)]
platform: AnthropicPlatform,
+ /// Enable 1M context window for Anthropic
+ #[serde(alias = "enable_1M_context", default)]
+ enable_1m_context: bool,
}
#[derive(Deserialize, Debug)]
@@ -196,7 +205,10 @@ struct AIRequestConfig {
pub aws_access_key_id: Option,
#[allow(dead_code)]
pub aws_secret_access_key: Option,
+ #[allow(dead_code)]
+ pub aws_session_token: Option,
pub platform: AnthropicPlatform,
+ pub enable_1m_context: bool,
}
impl AIRequestConfig {
@@ -215,11 +227,14 @@ impl AIRequestConfig {
region,
aws_access_key_id,
aws_secret_access_key,
+ aws_session_token,
platform,
+ enable_1m_context,
) = match resource {
AIResource::Standard(resource) => {
let region = resource.region.clone();
let platform = resource.platform.clone();
+ let enable_1m_context = resource.enable_1m_context;
// Skip get_base_url for Bedrock - it uses SDK directly, not HTTP
let base_url = if matches!(provider, AIProvider::AWSBedrock) {
String::new()
@@ -247,6 +262,11 @@ impl AIRequestConfig {
} else {
None
};
+ let aws_session_token = if let Some(session_token) = resource.aws_session_token {
+ Some(get_variable_or_self(session_token, db, w_id).await?)
+ } else {
+ None
+ };
(
api_key,
@@ -257,7 +277,9 @@ impl AIRequestConfig {
region,
aws_access_key_id,
aws_secret_access_key,
+ aws_session_token,
platform,
+ enable_1m_context,
)
}
AIResource::OAuth(resource) => {
@@ -278,7 +300,9 @@ impl AIRequestConfig {
None,
None,
None,
+ None,
AnthropicPlatform::Standard,
+ false,
)
}
};
@@ -292,7 +316,9 @@ impl AIRequestConfig {
region,
aws_access_key_id,
aws_secret_access_key,
+ aws_session_token,
platform,
+ enable_1m_context,
})
}
@@ -394,6 +420,10 @@ impl AIRequestConfig {
}
}
+ if is_anthropic_sdk && self.enable_1m_context {
+ request = request.header("anthropic-beta", "context-1m-2025-08-07");
+ }
+
// Add authentication headers
if let Some(api_key) = self.api_key {
if is_azure {
@@ -830,6 +860,7 @@ async fn proxy(
request_config.api_key.as_deref(),
request_config.aws_access_key_id.as_deref(),
request_config.aws_secret_access_key.as_deref(),
+ request_config.aws_session_token.as_deref(),
region,
)
.await;
@@ -838,6 +869,7 @@ async fn proxy(
request_config.api_key.as_deref(),
request_config.aws_access_key_id.as_deref(),
request_config.aws_secret_access_key.as_deref(),
+ request_config.aws_session_token.as_deref(),
region,
)
.await;
@@ -853,6 +885,7 @@ async fn proxy(
request_config.api_key.as_deref(),
request_config.aws_access_key_id.as_deref(),
request_config.aws_secret_access_key.as_deref(),
+ request_config.aws_session_token.as_deref(),
region,
)
.await;
@@ -863,6 +896,7 @@ async fn proxy(
request_config.api_key.as_deref(),
request_config.aws_access_key_id.as_deref(),
request_config.aws_secret_access_key.as_deref(),
+ request_config.aws_session_token.as_deref(),
region,
)
.await;
diff --git a/backend/windmill-api/src/bedrock.rs b/backend/windmill-api/src/bedrock.rs
index de0e9059d7..3824f8966d 100644
--- a/backend/windmill-api/src/bedrock.rs
+++ b/backend/windmill-api/src/bedrock.rs
@@ -71,7 +71,11 @@ struct OpenAIToolFunction {
/// Authentication configuration for Bedrock clients
enum BedrockAuthConfig {
BearerToken(String),
- IamCredentials { access_key_id: String, secret_access_key: String },
+ IamCredentials {
+ access_key_id: String,
+ secret_access_key: String,
+ session_token: Option,
+ },
Environment,
}
@@ -80,6 +84,7 @@ fn determine_auth_config(
api_key: Option<&str>,
aws_access_key_id: Option<&str>,
aws_secret_access_key: Option<&str>,
+ aws_session_token: Option<&str>,
) -> BedrockAuthConfig {
if let Some(key) = api_key.filter(|k| !k.is_empty()) {
BedrockAuthConfig::BearerToken(key.to_string())
@@ -90,6 +95,9 @@ fn determine_auth_config(
BedrockAuthConfig::IamCredentials {
access_key_id: access_key_id.to_string(),
secret_access_key: secret_access_key.to_string(),
+ session_token: aws_session_token
+ .filter(|token| !token.is_empty())
+ .map(str::to_string),
}
} else {
BedrockAuthConfig::Environment
@@ -101,12 +109,19 @@ async fn create_bedrock_client(
api_key: Option<&str>,
aws_access_key_id: Option<&str>,
aws_secret_access_key: Option<&str>,
+ aws_session_token: Option<&str>,
region: &str,
) -> Result {
- match determine_auth_config(api_key, aws_access_key_id, aws_secret_access_key) {
+ match determine_auth_config(
+ api_key,
+ aws_access_key_id,
+ aws_secret_access_key,
+ aws_session_token,
+ ) {
BedrockAuthConfig::BearerToken(key) => BedrockClient::from_bearer_token(key, region).await,
- BedrockAuthConfig::IamCredentials { access_key_id, secret_access_key } => {
- BedrockClient::from_credentials(access_key_id, secret_access_key, None, region).await
+ BedrockAuthConfig::IamCredentials { access_key_id, secret_access_key, session_token } => {
+ BedrockClient::from_credentials(access_key_id, secret_access_key, session_token, region)
+ .await
}
BedrockAuthConfig::Environment => BedrockClient::from_env(region).await,
}
@@ -163,6 +178,7 @@ async fn create_bedrock_control_client(
api_key: Option<&str>,
aws_access_key_id: Option<&str>,
aws_secret_access_key: Option<&str>,
+ aws_session_token: Option<&str>,
region: &str,
) -> Result {
use aws_config::BehaviorVersion;
@@ -170,7 +186,12 @@ async fn create_bedrock_control_client(
let region_provider = aws_sdk_bedrock::config::Region::new(region.to_string());
- match determine_auth_config(api_key, aws_access_key_id, aws_secret_access_key) {
+ match determine_auth_config(
+ api_key,
+ aws_access_key_id,
+ aws_secret_access_key,
+ aws_session_token,
+ ) {
BedrockAuthConfig::BearerToken(key) => {
let config = aws_sdk_bedrock::config::Builder::new()
.region(region_provider)
@@ -179,11 +200,11 @@ async fn create_bedrock_control_client(
.build();
Ok(aws_sdk_bedrock::Client::from_conf(config))
}
- BedrockAuthConfig::IamCredentials { access_key_id, secret_access_key } => {
+ BedrockAuthConfig::IamCredentials { access_key_id, secret_access_key, session_token } => {
let credentials = aws_credential_types::Credentials::new(
access_key_id,
secret_access_key,
- None,
+ session_token,
None,
"windmill",
);
@@ -209,11 +230,17 @@ pub async fn list_foundation_models(
api_key: Option<&str>,
aws_access_key_id: Option<&str>,
aws_secret_access_key: Option<&str>,
+ aws_session_token: Option<&str>,
region: &str,
) -> Result<(http::StatusCode, http::HeaderMap, axum::body::Body)> {
- let client =
- create_bedrock_control_client(api_key, aws_access_key_id, aws_secret_access_key, region)
- .await?;
+ let client = create_bedrock_control_client(
+ api_key,
+ aws_access_key_id,
+ aws_secret_access_key,
+ aws_session_token,
+ region,
+ )
+ .await?;
let response = client
.list_foundation_models()
@@ -258,11 +285,17 @@ pub async fn list_inference_profiles(
api_key: Option<&str>,
aws_access_key_id: Option<&str>,
aws_secret_access_key: Option<&str>,
+ aws_session_token: Option<&str>,
region: &str,
) -> Result<(http::StatusCode, http::HeaderMap, axum::body::Body)> {
- let client =
- create_bedrock_control_client(api_key, aws_access_key_id, aws_secret_access_key, region)
- .await?;
+ let client = create_bedrock_control_client(
+ api_key,
+ aws_access_key_id,
+ aws_secret_access_key,
+ aws_session_token,
+ region,
+ )
+ .await?;
let response =
client.list_inference_profiles().send().await.map_err(|e| {
@@ -315,14 +348,21 @@ pub async fn handle_bedrock_sdk_streaming(
api_key: Option<&str>,
aws_access_key_id: Option<&str>,
aws_secret_access_key: Option<&str>,
+ aws_session_token: Option<&str>,
region: &str,
) -> Result<(http::StatusCode, http::HeaderMap, axum::body::Body)> {
let openai_req: OpenAIRequest = serde_json::from_slice(body)
.map_err(|e| Error::internal_err(format!("Failed to parse OpenAI request: {}", e)))?;
// Create Bedrock client using shared helper
- let bedrock_client =
- create_bedrock_client(api_key, aws_access_key_id, aws_secret_access_key, region).await?;
+ let bedrock_client = create_bedrock_client(
+ api_key,
+ aws_access_key_id,
+ aws_secret_access_key,
+ aws_session_token,
+ region,
+ )
+ .await?;
// Convert messages using shared conversion
let (bedrock_messages, system_prompts) =
@@ -568,14 +608,21 @@ pub async fn handle_bedrock_sdk_non_streaming(
api_key: Option<&str>,
aws_access_key_id: Option<&str>,
aws_secret_access_key: Option<&str>,
+ aws_session_token: Option<&str>,
region: &str,
) -> Result<(http::StatusCode, http::HeaderMap, axum::body::Body)> {
let openai_req: OpenAIRequest = serde_json::from_slice(body)
.map_err(|e| Error::internal_err(format!("Failed to parse OpenAI request: {}", e)))?;
// Create Bedrock client using shared helper
- let bedrock_client =
- create_bedrock_client(api_key, aws_access_key_id, aws_secret_access_key, region).await?;
+ let bedrock_client = create_bedrock_client(
+ api_key,
+ aws_access_key_id,
+ aws_secret_access_key,
+ aws_session_token,
+ region,
+ )
+ .await?;
// Convert messages using shared conversion
let (bedrock_messages, system_prompts) =
@@ -754,3 +801,60 @@ fn document_to_json(doc: &aws_smithy_types::Document) -> serde_json::Value {
aws_smithy_types::Document::Null => serde_json::Value::Null,
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn determine_auth_config_prioritizes_bearer_token() {
+ let config = determine_auth_config(
+ Some("bearer-token"),
+ Some("AKIA123"),
+ Some("secret"),
+ Some("session-token"),
+ );
+
+ match config {
+ BedrockAuthConfig::BearerToken(token) => assert_eq!(token, "bearer-token"),
+ _ => panic!("expected bearer token auth config"),
+ }
+ }
+
+ #[test]
+ fn determine_auth_config_uses_iam_with_optional_session_token() {
+ let config =
+ determine_auth_config(None, Some("AKIA123"), Some("secret"), Some("session-token"));
+
+ match config {
+ BedrockAuthConfig::IamCredentials {
+ access_key_id,
+ secret_access_key,
+ session_token,
+ } => {
+ assert_eq!(access_key_id, "AKIA123");
+ assert_eq!(secret_access_key, "secret");
+ assert_eq!(session_token.as_deref(), Some("session-token"));
+ }
+ _ => panic!("expected IAM auth config"),
+ }
+ }
+
+ #[test]
+ fn determine_auth_config_treats_empty_session_token_as_none() {
+ let config = determine_auth_config(None, Some("AKIA123"), Some("secret"), Some(""));
+
+ match config {
+ BedrockAuthConfig::IamCredentials { session_token, .. } => {
+ assert!(session_token.is_none());
+ }
+ _ => panic!("expected IAM auth config"),
+ }
+ }
+
+ #[test]
+ fn determine_auth_config_falls_back_to_environment() {
+ let config = determine_auth_config(None, Some("AKIA123"), None, Some("session-token"));
+ assert!(matches!(config, BedrockAuthConfig::Environment));
+ }
+}
diff --git a/backend/windmill-api/src/flows.rs b/backend/windmill-api/src/flows.rs
index cc1c3e97c0..c6a09a9e6a 100644
--- a/backend/windmill-api/src/flows.rs
+++ b/backend/windmill-api/src/flows.rs
@@ -6,8 +6,8 @@
* LICENSE-AGPL for a copy of the license.
*/
-// Re-export everything from windmill-api-scripts
-pub use windmill_api_scripts::flows::*;
+// Re-export everything from windmill-api-flows
+pub use windmill_api_flows::flows::*;
use crate::triggers::{get_triggers_count_internal, TriggersCount};
use axum::{
@@ -20,7 +20,7 @@ use windmill_common::{error::JsonResult, utils::StripPath, DB};
/// Wraps the subcrate's workspaced_service with the trigger count route
/// that depends on windmill-api internals.
pub fn workspaced_service() -> Router {
- windmill_api_scripts::flows::workspaced_service()
+ windmill_api_flows::flows::workspaced_service()
.route("/get_triggers_count/*path", get(get_triggers_count))
}
diff --git a/backend/windmill-api/src/health.rs b/backend/windmill-api/src/health.rs
new file mode 100644
index 0000000000..d861f338ef
--- /dev/null
+++ b/backend/windmill-api/src/health.rs
@@ -0,0 +1,605 @@
+/*
+ * Author: Windmill Labs, Inc 2024
+ * This file and its contents are licensed under the AGPLv3 License.
+ * Please see the included NOTICE for copyright information and
+ * LICENSE-AGPL for a copy of the license.
+ */
+
+use axum::{
+ extract::{Extension, Query},
+ http::StatusCode,
+ response::IntoResponse,
+ routing::get,
+ Json, Router,
+};
+use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
+use std::collections::HashSet;
+use std::sync::Arc;
+use std::time::Duration;
+use tokio::sync::RwLock;
+
+use crate::db::{ApiAuthed, DB};
+use windmill_common::min_version::MIN_KEEP_ALIVE_VERSION;
+use windmill_common::utils::GIT_VERSION;
+use windmill_common::IS_READY;
+
+#[cfg(feature = "prometheus")]
+use windmill_common::METRICS_ENABLED;
+
+/// Fixed 5 second cache TTL for health status
+const HEALTH_CACHE_TTL: Duration = Duration::from_secs(5);
+
+lazy_static::lazy_static! {
+ static ref STATUS_CACHE: Arc>> = Arc::new(RwLock::new(None));
+
+ /// Environment variable to silence health endpoint logs
+ static ref SILENCE_HEALTH_LOGS: bool = std::env::var("SILENCE_HEALTH_LOGS")
+ .map(|v| v.to_lowercase() == "true" || v == "1")
+ .unwrap_or(false);
+}
+
+#[cfg(feature = "prometheus")]
+lazy_static::lazy_static! {
+ /// Health status phase gauge with labels: healthy, degraded, unhealthy
+ /// Only one label will be 1 at a time, others will be 0
+ static ref HEALTH_STATUS_PHASE: Option =
+ if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
+ Some(prometheus::register_int_gauge_vec!(
+ "health_status_phase",
+ "Health status phase (1 = current state, 0 = not current state)",
+ &["phase"]
+ ).unwrap())
+ } else {
+ None
+ };
+
+ /// Database latency in milliseconds
+ static ref HEALTH_DATABASE_LATENCY: Option =
+ if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
+ Some(prometheus::register_gauge!(
+ "health_database_latency_ms",
+ "Database query latency in milliseconds"
+ ).unwrap())
+ } else {
+ None
+ };
+
+ /// Database unresponsive flag (1 = unresponsive, 0 = responsive)
+ static ref HEALTH_DATABASE_UNRESPONSIVE: Option =
+ if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
+ Some(prometheus::register_int_gauge!(
+ "health_database_unresponsive",
+ "Database unresponsive flag (1 = unresponsive, 0 = responsive)"
+ ).unwrap())
+ } else {
+ None
+ };
+
+ /// Database connection pool size
+ static ref HEALTH_DATABASE_POOL_SIZE: Option =
+ if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
+ Some(prometheus::register_int_gauge!(
+ "health_database_pool_size",
+ "Current number of connections in the database pool"
+ ).unwrap())
+ } else {
+ None
+ };
+
+ /// Database connection pool idle connections
+ static ref HEALTH_DATABASE_POOL_IDLE: Option =
+ if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
+ Some(prometheus::register_int_gauge!(
+ "health_database_pool_idle",
+ "Number of idle connections in the database pool"
+ ).unwrap())
+ } else {
+ None
+ };
+
+ /// Database connection pool max connections
+ static ref HEALTH_DATABASE_POOL_MAX: Option =
+ if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
+ Some(prometheus::register_int_gauge!(
+ "health_database_pool_max",
+ "Maximum connections allowed in the database pool"
+ ).unwrap())
+ } else {
+ None
+ };
+}
+
+#[derive(Clone)]
+struct CachedHealthStatus {
+ status: HealthStatusResponse,
+ cached_at: std::time::Instant,
+}
+
+/// Query parameters for status endpoint
+#[derive(Debug, Deserialize)]
+pub struct StatusQuery {
+ /// Force a fresh check, bypassing the cache
+ #[serde(default)]
+ force: bool,
+}
+
+/// Status endpoint - cached health status (unauthenticated)
+pub fn status_service() -> Router {
+ Router::new().route("/", get(health_status))
+}
+
+/// Detailed health endpoint - requires DB auth (always fresh)
+pub fn detailed_service() -> Router {
+ Router::new().route("/", get(health_detailed))
+}
+
+// ============ Response Types ============
+
+#[derive(Serialize, Clone, Copy, PartialEq, Eq)]
+#[serde(rename_all = "lowercase")]
+pub enum HealthStatus {
+ Healthy,
+ Degraded,
+ Unhealthy,
+}
+
+#[derive(Serialize, Clone)]
+pub struct HealthStatusResponse {
+ pub status: HealthStatus,
+ pub checked_at: DateTime,
+ pub database_healthy: bool,
+ pub workers_alive: i64,
+}
+
+#[derive(Serialize)]
+pub struct DetailedHealthResponse {
+ pub status: HealthStatus,
+ pub checked_at: DateTime,
+ pub version: String,
+ pub checks: HealthChecks,
+}
+
+#[derive(Serialize)]
+pub struct HealthChecks {
+ pub database: DatabaseHealth,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub workers: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub queue: Option,
+ pub readiness: ReadinessHealth,
+}
+
+#[derive(Serialize)]
+pub struct DatabaseHealth {
+ pub healthy: bool,
+ pub latency_ms: i64,
+ pub pool: PoolStats,
+}
+
+#[derive(Serialize)]
+pub struct PoolStats {
+ pub size: u32,
+ pub idle: u32,
+ pub max_connections: u32,
+}
+
+#[derive(Serialize)]
+pub struct WorkersHealth {
+ pub healthy: bool,
+ pub active_count: i64,
+ pub worker_groups: Vec,
+ pub min_version: String,
+ pub versions: Vec,
+}
+
+#[derive(Serialize)]
+pub struct QueueHealth {
+ pub pending_jobs: u64,
+ pub running_jobs: u64,
+}
+
+#[derive(Serialize)]
+pub struct ReadinessHealth {
+ pub healthy: bool,
+}
+
+// ============ Check Functions ============
+
+const HEALTH_CHECK_TIMEOUT: Duration = Duration::from_secs(5);
+
+/// Result of a database health check including latency
+struct DatabaseCheckResult {
+ healthy: bool,
+ latency_ms: i64,
+}
+
+async fn check_database_with_latency(db: &DB) -> DatabaseCheckResult {
+ let start = std::time::Instant::now();
+ let healthy = tokio::time::timeout(
+ HEALTH_CHECK_TIMEOUT,
+ sqlx::query_scalar!("SELECT 1").fetch_one(db),
+ )
+ .await
+ .map(|r| r.is_ok())
+ .unwrap_or(false);
+ let latency_ms = start.elapsed().as_millis() as i64;
+
+ DatabaseCheckResult { healthy, latency_ms }
+}
+
+fn get_pool_stats(db: &DB) -> PoolStats {
+ PoolStats {
+ size: db.size(),
+ idle: db.num_idle() as u32,
+ max_connections: db.options().get_max_connections(),
+ }
+}
+
+async fn check_database_detailed(db: &DB) -> DatabaseHealth {
+ let check = check_database_with_latency(db).await;
+ let pool = get_pool_stats(db);
+
+ DatabaseHealth {
+ healthy: check.healthy,
+ latency_ms: check.latency_ms,
+ pool,
+ }
+}
+
+async fn check_worker_count(db: &DB) -> i64 {
+ sqlx::query_scalar!(
+ "SELECT COUNT(*) FROM worker_ping WHERE ping_at > now() - interval '5 minutes'"
+ )
+ .fetch_one(db)
+ .await
+ .unwrap_or(Some(0))
+ .unwrap_or(0)
+}
+
+async fn check_workers_detailed(db: &DB) -> WorkersHealth {
+ let workers = sqlx::query!(
+ r#"
+ SELECT
+ worker_group,
+ wm_version
+ FROM worker_ping
+ WHERE ping_at > now() - interval '5 minutes'
+ "#
+ )
+ .fetch_all(db)
+ .await
+ .unwrap_or_default();
+
+ let active_count = workers.len() as i64;
+
+ let worker_groups: Vec = workers
+ .iter()
+ .map(|w| w.worker_group.clone())
+ .collect::>()
+ .into_iter()
+ .collect();
+
+ let versions: Vec = workers
+ .iter()
+ .map(|w| w.wm_version.clone())
+ .filter(|v| !v.is_empty())
+ .collect::>()
+ .into_iter()
+ .collect();
+
+ let min_version = format!(
+ "v{}.{}.{}",
+ MIN_KEEP_ALIVE_VERSION.0, MIN_KEEP_ALIVE_VERSION.1, MIN_KEEP_ALIVE_VERSION.2
+ );
+
+ let healthy = active_count > 0;
+
+ WorkersHealth {
+ healthy,
+ active_count,
+ worker_groups,
+ min_version,
+ versions,
+ }
+}
+
+async fn check_queue(db: &DB) -> QueueHealth {
+ let pending_counts = windmill_common::queue::get_queue_counts(db).await;
+ let running_counts = windmill_common::queue::get_queue_running_counts(db).await;
+
+ let pending_jobs: u64 = pending_counts.values().map(|&v| v as u64).sum();
+ let running_jobs: u64 = running_counts.values().map(|&v| v as u64).sum();
+
+ QueueHealth { pending_jobs, running_jobs }
+}
+
+fn check_readiness() -> ReadinessHealth {
+ let healthy = IS_READY.load(std::sync::atomic::Ordering::Relaxed);
+ ReadinessHealth { healthy }
+}
+
+#[cfg(feature = "enterprise")]
+fn get_version() -> String {
+ format!("EE {GIT_VERSION}")
+}
+
+#[cfg(not(feature = "enterprise"))]
+fn get_version() -> String {
+ format!("CE {GIT_VERSION}")
+}
+
+// ============ Background Loop ============
+
+/// Spawn a background task that performs a health check every 10 seconds.
+/// Updates the cache and prometheus metrics continuously.
+pub fn start_health_check_loop(
+ db: DB,
+ mut killpill_rx: tokio::sync::broadcast::Receiver<()>,
+) {
+ tokio::spawn(async move {
+ let mut interval = tokio::time::interval(Duration::from_secs(10));
+ interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
+ loop {
+ tokio::select! {
+ biased;
+ _ = killpill_rx.recv() => {
+ tracing::info!("health check loop shutting down");
+ break;
+ }
+ _ = interval.tick() => {
+ let result = perform_health_check(&db).await;
+
+ log_health_status(&result.response);
+ #[cfg(feature = "prometheus")]
+ update_health_metrics(&result.metrics_data);
+
+ let cached = CachedHealthStatus {
+ status: result.response,
+ cached_at: std::time::Instant::now(),
+ };
+ *STATUS_CACHE.write().await = Some(cached);
+ }
+ }
+ }
+ });
+}
+
+// ============ Handlers ============
+
+/// Log health status based on severity
+fn log_health_status(status: &HealthStatusResponse) {
+ if *SILENCE_HEALTH_LOGS {
+ return;
+ }
+
+ match status.status {
+ HealthStatus::Healthy => {
+ tracing::info!(
+ status = "healthy",
+ database_healthy = status.database_healthy,
+ workers_alive = status.workers_alive,
+ "health check completed"
+ );
+ }
+ HealthStatus::Degraded => {
+ tracing::warn!(
+ status = "degraded",
+ database_healthy = status.database_healthy,
+ workers_alive = status.workers_alive,
+ "health check: degraded status (no workers alive)"
+ );
+ }
+ HealthStatus::Unhealthy => {
+ tracing::error!(
+ status = "unhealthy",
+ database_healthy = status.database_healthy,
+ workers_alive = status.workers_alive,
+ "health check: unhealthy status"
+ );
+ }
+ }
+}
+
+/// Data needed for prometheus metrics (internal, not serialized)
+#[cfg(feature = "prometheus")]
+struct HealthMetricsData {
+ status: HealthStatus,
+ database_healthy: bool,
+ database_latency_ms: i64,
+ pool_size: u32,
+ pool_idle: u32,
+ pool_max: u32,
+}
+
+/// Update prometheus metrics for health status
+#[cfg(feature = "prometheus")]
+fn update_health_metrics(data: &HealthMetricsData) {
+ // Update health status phase (only one label is 1, others are 0)
+ if let Some(gauge_vec) = HEALTH_STATUS_PHASE.as_ref() {
+ let (healthy, degraded, unhealthy) = match data.status {
+ HealthStatus::Healthy => (1, 0, 0),
+ HealthStatus::Degraded => (0, 1, 0),
+ HealthStatus::Unhealthy => (0, 0, 1),
+ };
+ gauge_vec.with_label_values(&["healthy"]).set(healthy);
+ gauge_vec.with_label_values(&["degraded"]).set(degraded);
+ gauge_vec.with_label_values(&["unhealthy"]).set(unhealthy);
+ }
+
+ // Database latency
+ if let Some(gauge) = HEALTH_DATABASE_LATENCY.as_ref() {
+ gauge.set(data.database_latency_ms as f64);
+ }
+
+ // Database unresponsive flag
+ if let Some(gauge) = HEALTH_DATABASE_UNRESPONSIVE.as_ref() {
+ gauge.set(if data.database_healthy { 0 } else { 1 });
+ }
+
+ // Pool metrics
+ if let Some(gauge) = HEALTH_DATABASE_POOL_SIZE.as_ref() {
+ gauge.set(data.pool_size as i64);
+ }
+ if let Some(gauge) = HEALTH_DATABASE_POOL_IDLE.as_ref() {
+ gauge.set(data.pool_idle as i64);
+ }
+ if let Some(gauge) = HEALTH_DATABASE_POOL_MAX.as_ref() {
+ gauge.set(data.pool_max as i64);
+ }
+}
+
+/// Result of perform_health_check including data needed for metrics
+struct HealthCheckResult {
+ response: HealthStatusResponse,
+ #[cfg(feature = "prometheus")]
+ metrics_data: HealthMetricsData,
+}
+
+/// Perform fresh health check
+async fn perform_health_check(db: &DB) -> HealthCheckResult {
+ let checked_at = Utc::now();
+ let db_check = check_database_with_latency(db).await;
+
+ let workers_alive = if db_check.healthy {
+ check_worker_count(db).await
+ } else {
+ 0
+ };
+
+ let status = if !db_check.healthy {
+ HealthStatus::Unhealthy
+ } else if workers_alive == 0 {
+ HealthStatus::Degraded
+ } else {
+ HealthStatus::Healthy
+ };
+
+ let response = HealthStatusResponse {
+ status,
+ checked_at,
+ database_healthy: db_check.healthy,
+ workers_alive,
+ };
+
+ #[cfg(feature = "prometheus")]
+ let metrics_data = {
+ let pool_stats = get_pool_stats(db);
+ HealthMetricsData {
+ status,
+ database_healthy: db_check.healthy,
+ database_latency_ms: db_check.latency_ms,
+ pool_size: pool_stats.size,
+ pool_idle: pool_stats.idle,
+ pool_max: pool_stats.max_connections,
+ }
+ };
+
+ HealthCheckResult {
+ response,
+ #[cfg(feature = "prometheus")]
+ metrics_data,
+ }
+}
+
+/// Status check - cached DB/worker status with optional force refresh
+async fn health_status(
+ Extension(db): Extension,
+ Query(query): Query,
+) -> impl IntoResponse {
+ // Check cache (unless force=true)
+ if !query.force {
+ let cache = STATUS_CACHE.read().await;
+ if let Some(cached) = cache.as_ref() {
+ if cached.cached_at.elapsed() < HEALTH_CACHE_TTL {
+ let status_code = if cached.status.status == HealthStatus::Unhealthy {
+ StatusCode::SERVICE_UNAVAILABLE
+ } else {
+ StatusCode::OK
+ };
+ return (status_code, Json(cached.status.clone()));
+ }
+ }
+ }
+
+ // Cache miss, expired, or force=true - fetch fresh data
+ let health_check_result = perform_health_check(&db).await;
+
+ // Log and update metrics on fresh check
+ log_health_status(&health_check_result.response);
+ #[cfg(feature = "prometheus")]
+ update_health_metrics(&health_check_result.metrics_data);
+
+ // Update cache (clone before acquiring lock to minimize lock duration)
+ let cached = CachedHealthStatus {
+ status: health_check_result.response.clone(),
+ cached_at: std::time::Instant::now(),
+ };
+ {
+ let mut cache = STATUS_CACHE.write().await;
+ *cache = Some(cached);
+ }
+
+ let status_code = if health_check_result.response.status == HealthStatus::Unhealthy {
+ StatusCode::SERVICE_UNAVAILABLE
+ } else {
+ StatusCode::OK
+ };
+
+ (status_code, Json(health_check_result.response))
+}
+
+/// Detailed health check - requires DB authentication (always fresh, no caching)
+async fn health_detailed(
+ _authed: ApiAuthed,
+ Extension(db): Extension,
+) -> impl IntoResponse {
+ let checked_at = Utc::now();
+ let database = check_database_detailed(&db).await;
+ let readiness = check_readiness();
+
+ // Short-circuit if database is down
+ if !database.healthy {
+ let response = DetailedHealthResponse {
+ status: HealthStatus::Unhealthy,
+ checked_at,
+ version: get_version(),
+ checks: HealthChecks {
+ database,
+ workers: None,
+ queue: None,
+ readiness,
+ },
+ };
+ return (StatusCode::SERVICE_UNAVAILABLE, Json(response));
+ }
+
+ let workers = check_workers_detailed(&db).await;
+ let queue = check_queue(&db).await;
+
+ let status = if !workers.healthy {
+ HealthStatus::Degraded
+ } else {
+ HealthStatus::Healthy
+ };
+
+ let response = DetailedHealthResponse {
+ status,
+ checked_at,
+ version: get_version(),
+ checks: HealthChecks {
+ database,
+ workers: Some(workers),
+ queue: Some(queue),
+ readiness,
+ },
+ };
+
+ let status_code = if status == HealthStatus::Unhealthy {
+ StatusCode::SERVICE_UNAVAILABLE
+ } else {
+ StatusCode::OK
+ };
+
+ (status_code, Json(response))
+}
diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs
index b2cc8623d1..fbd9a9b682 100644
--- a/backend/windmill-api/src/jobs.rs
+++ b/backend/windmill-api/src/jobs.rs
@@ -2135,9 +2135,7 @@ pub async fn resume_suspended_flow_as_owner(
// Check approval conditions (self-approval, required groups, etc.)
if let Some(ref flow_status_value) = flow.flow_status {
- if let Ok(flow_status) =
- serde_json::from_value::(flow_status_value.clone())
- {
+ if let Ok(flow_status) = serde_json::from_value::(flow_status_value.clone()) {
let trigger_email = flow.email.as_deref().unwrap_or("");
conditionally_require_authed_user(Some(authed.clone()), flow_status, trigger_email)?;
}
@@ -5224,7 +5222,7 @@ async fn add_batch_jobs(
let tag = if let Some(dedicated_worker) = dedicated_worker {
if dedicated_worker && path.is_some() {
- format!("{}:{}", w_id, path.clone().unwrap())
+ windmill_common::worker::dedicated_worker_tag(&w_id, &path.clone().unwrap())
} else {
format!("{}", language.as_str())
}
diff --git a/backend/windmill-api/src/lib.rs b/backend/windmill-api/src/lib.rs
index 3d544bec11..76fe0224ed 100644
--- a/backend/windmill-api/src/lib.rs
+++ b/backend/windmill-api/src/lib.rs
@@ -92,6 +92,7 @@ mod folders;
mod granular_acls;
mod group_history;
mod groups;
+mod health;
#[cfg(feature = "private")]
pub mod indexer_ee;
mod indexer_oss;
@@ -376,6 +377,10 @@ pub async fn run_server(
start_all_listeners(db.clone(), &killpill_rx);
}
+ if server_mode {
+ health::start_health_check_loop(db.clone(), killpill_rx.resubscribe());
+ }
+
let listener = tokio::net::TcpListener::bind(addr)
.await
.context("binding main windmill server")?;
@@ -546,6 +551,7 @@ pub async fn run_server(
.nest("/ai", ai::global_service())
.nest("/inkeep", inkeep_oss::global_service())
.nest("/mcp/w/:workspace_id/list_tools", mcp_list_tools_service)
+ .nest("/health/detailed", health::detailed_service())
.route_layer(from_extractor::())
.route_layer(from_extractor::())
// Workspace-scoped OAuth endpoints that don't require authentication
@@ -741,6 +747,7 @@ pub async fn run_server(
}
})
.route("/version", get(git_v))
+ .nest("/health/status", health::status_service())
.route("/min_keep_alive_version", get(min_keep_alive_version))
.route("/uptodate", get(is_up_to_date))
.route("/ee_license", get(ee_license))
diff --git a/backend/windmill-common/Cargo.toml b/backend/windmill-common/Cargo.toml
index d399c08840..d7e79cfcd4 100644
--- a/backend/windmill-common/Cargo.toml
+++ b/backend/windmill-common/Cargo.toml
@@ -7,6 +7,7 @@ edition.workspace = true
[features]
default = []
enterprise = ["dep:aws-config"]
+instance_config_schema = ["dep:schemars"]
local_reports = ["dep:rsa", "dep:aes-gcm"]
private = ["dep:aws-sdk-rds"]
jemalloc = ["dep:tikv-jemalloc-ctl"]
@@ -96,6 +97,7 @@ windmill-parser.workspace = true
jsonwebtoken.workspace = true
backon.workspace = true
openidconnect = { workspace = true, optional = true }
+schemars = { workspace = true, optional = true }
strum.workspace = true
strum_macros.workspace = true
windmill-types.workspace = true
diff --git a/backend/windmill-common/src/cache.rs b/backend/windmill-common/src/cache.rs
index 11d6217fba..27af55ea01 100644
--- a/backend/windmill-common/src/cache.rs
+++ b/backend/windmill-common/src/cache.rs
@@ -909,9 +909,15 @@ pub mod workspace_dependencies {
/// Cache key: (workspace_id, language)
/// Cache value: (exists: bool, cached_at timestamp)
static ref DEFAULT_WD_EXISTS_CACHE: quick_cache::sync::Cache<(String, String), (bool, Instant)> = quick_cache::sync::Cache::new(500);
+
+ /// Cache timeout for existence checks (default 10 seconds, configurable via EXISTS_CACHE_TIMEOUT_MS env var)
+ pub static ref EXISTS_CACHE_TIMEOUT: Duration = Duration::from_millis(
+ std::env::var("EXISTS_CACHE_TIMEOUT_MS")
+ .ok()
+ .and_then(|v| v.parse().ok())
+ .unwrap_or(10_000)
+ );
}
- /// Cache timeout for existence checks (10 seconds)
- pub const EXISTS_CACHE_TIMEOUT: Duration = Duration::from_secs(10);
pub fn fetch_workspace_dependencies<'c>(
id: i64,
@@ -932,7 +938,7 @@ pub mod workspace_dependencies {
let exists_key = (workspace_id.to_string(), dependencies_filename);
if let Some((exists, cached_at)) = DEFAULT_WD_EXISTS_CACHE.get(&exists_key) {
- if cached_at.elapsed() < EXISTS_CACHE_TIMEOUT {
+ if cached_at.elapsed() < *EXISTS_CACHE_TIMEOUT {
tracing::debug!(
workspace_id = %workspace_id,
exists,
diff --git a/backend/windmill-common/src/global_settings.rs b/backend/windmill-common/src/global_settings.rs
index 59a941701b..93a20e9041 100644
--- a/backend/windmill-common/src/global_settings.rs
+++ b/backend/windmill-common/src/global_settings.rs
@@ -14,11 +14,14 @@ pub const NUGET_CONFIG_SETTING: &str = "nuget_config";
pub const POWERSHELL_REPO_URL_SETTING: &str = "powershell_repo_url";
pub const POWERSHELL_REPO_PAT_SETTING: &str = "powershell_repo_pat";
pub const MAVEN_REPOS_SETTING: &str = "maven_repos";
+pub const MAVEN_SETTINGS_XML_SETTING: &str = "maven_settings_xml";
pub const NO_DEFAULT_MAVEN_SETTING: &str = "no_default_maven";
pub const RUBY_REPOS_SETTING: &str = "ruby_repos";
+pub const CARGO_REGISTRIES_SETTING: &str = "cargo_registries";
pub const EXTRA_PIP_INDEX_URL_SETTING: &str = "pip_extra_index_url";
pub const PIP_INDEX_URL_SETTING: &str = "pip_index_url";
+pub const UV_INDEX_STRATEGY_SETTING: &str = "uv_index_strategy";
pub const INSTANCE_PYTHON_VERSION_SETTING: &str = "instance_python_version";
pub const SCIM_TOKEN_SETTING: &str = "scim_token";
pub const SAML_METADATA_SETTING: &str = "saml_metadata";
@@ -33,6 +36,7 @@ pub const EXPOSE_METRICS_SETTING: &str = "expose_metrics";
pub const EXPOSE_DEBUG_METRICS_SETTING: &str = "expose_debug_metrics";
pub const KEEP_JOB_DIR_SETTING: &str = "keep_job_dir";
pub const REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING: &str = "require_preexisting_user_for_oauth";
+pub const JOB_ISOLATION_SETTING: &str = "job_isolation";
pub const OBJECT_STORE_CONFIG_SETTING: &str = "object_store_cache_config";
pub const HUB_API_SECRET_SETTING: &str = "hub_api_secret";
@@ -81,6 +85,7 @@ pub const ENV_SETTINGS: &[&str] = &[
"GOPRIVATE",
"GOPROXY",
"NETRC",
+ "CARGO_REGISTRIES",
"INSTANCE_PYTHON_VERSION",
"PIP_INDEX_URL",
"PIP_EXTRA_INDEX_URL",
diff --git a/backend/windmill-common/src/instance_config.rs b/backend/windmill-common/src/instance_config.rs
new file mode 100644
index 0000000000..1b39ea0325
--- /dev/null
+++ b/backend/windmill-common/src/instance_config.rs
@@ -0,0 +1,2101 @@
+use std::collections::BTreeMap;
+use std::fmt;
+
+use serde::{Deserialize, Serialize};
+
+use crate::global_settings::LICENSE_KEY_SETTING;
+
+// ---------------------------------------------------------------------------
+// Kubernetes Secret reference support
+// ---------------------------------------------------------------------------
+
+/// Reference to a key inside a Kubernetes Secret.
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "instance_config_schema", derive(schemars::JsonSchema))]
+pub struct SecretKeyRef {
+ pub name: String,
+ pub key: String,
+}
+
+/// Wrapper that produces `{ "secretKeyRef": { "name": "…", "key": "…" } }` in YAML/JSON.
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "instance_config_schema", derive(schemars::JsonSchema))]
+pub struct SecretKeyRefWrapper {
+ #[serde(rename = "secretKeyRef")]
+ pub secret_key_ref: SecretKeyRef,
+}
+
+/// Reference to an environment variable.
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "instance_config_schema", derive(schemars::JsonSchema))]
+pub struct EnvRefWrapper {
+ #[serde(rename = "envRef")]
+ pub env_ref: String,
+}
+
+/// A string field that can be a literal value, a reference to a Kubernetes
+/// Secret key, or a reference to an environment variable.
+///
+/// Uses `#[serde(untagged)]` so that in YAML/JSON:
+///
+/// - A plain string deserializes as `Literal("…")`
+/// - An object `{ secretKeyRef: { name, key } }` deserializes as `SecretRef(…)`
+/// - An object `{ envRef: "VAR_NAME" }` deserializes as `EnvRef(…)`
+///
+/// `Literal` serializes back to a plain JSON string, preserving backwards
+/// compatibility with existing consumers.
+#[derive(Deserialize, Serialize, Clone, Debug)]
+#[cfg_attr(feature = "instance_config_schema", derive(schemars::JsonSchema))]
+#[serde(untagged)]
+pub enum StringOrSecretRef {
+ Literal(String),
+ SecretRef(SecretKeyRefWrapper),
+ EnvRef(EnvRefWrapper),
+}
+
+impl StringOrSecretRef {
+ /// Returns the literal string value, or `None` if this is an unresolved ref.
+ pub fn as_literal(&self) -> Option<&str> {
+ match self {
+ Self::Literal(s) => Some(s),
+ Self::SecretRef(_) | Self::EnvRef(_) => None,
+ }
+ }
+
+ /// Returns the literal value, panicking if this is an unresolved ref.
+ /// Use only after resolution.
+ pub fn literal_value(&self) -> &str {
+ match self {
+ Self::Literal(s) => s,
+ Self::SecretRef(_) => panic!("literal_value() called on unresolved secret ref"),
+ Self::EnvRef(_) => panic!("literal_value() called on unresolved env ref"),
+ }
+ }
+
+ /// Returns `true` if this is a secret reference (not yet resolved).
+ pub fn is_secret_ref(&self) -> bool {
+ matches!(self, Self::SecretRef(_))
+ }
+
+ /// Returns the inner `SecretKeyRef` if this is a secret reference.
+ pub fn as_secret_ref(&self) -> Option<&SecretKeyRef> {
+ match self {
+ Self::SecretRef(w) => Some(&w.secret_key_ref),
+ _ => None,
+ }
+ }
+
+ /// Returns `true` if this is an environment variable reference.
+ pub fn is_env_ref(&self) -> bool {
+ matches!(self, Self::EnvRef(_))
+ }
+
+ /// Returns the env var name if this is an env ref.
+ pub fn as_env_ref(&self) -> Option<&str> {
+ match self {
+ Self::EnvRef(w) => Some(&w.env_ref),
+ _ => None,
+ }
+ }
+}
+
+impl Default for StringOrSecretRef {
+ fn default() -> Self {
+ Self::Literal(String::new())
+ }
+}
+
+impl From for StringOrSecretRef {
+ fn from(s: String) -> Self {
+ Self::Literal(s)
+ }
+}
+
+impl From<&str> for StringOrSecretRef {
+ fn from(s: &str) -> Self {
+ Self::Literal(s.to_string())
+ }
+}
+
+impl PartialEq for StringOrSecretRef {
+ fn eq(&self, other: &str) -> bool {
+ self.as_literal() == Some(other)
+ }
+}
+
+impl PartialEq for StringOrSecretRef {
+ fn eq(&self, other: &StringOrSecretRef) -> bool {
+ match (self, other) {
+ (Self::Literal(a), Self::Literal(b)) => a == b,
+ (Self::SecretRef(a), Self::SecretRef(b)) => a == b,
+ (Self::EnvRef(a), Self::EnvRef(b)) => a == b,
+ _ => false,
+ }
+ }
+}
+
+impl fmt::Display for StringOrSecretRef {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Literal(s) => f.write_str(s),
+ Self::SecretRef(w) => write!(
+ f,
+ "secretKeyRef({}/{})",
+ w.secret_key_ref.name, w.secret_key_ref.key
+ ),
+ Self::EnvRef(w) => write!(f, "envRef({})", w.env_ref),
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// Top-level wrapper
+// ---------------------------------------------------------------------------
+
+/// Unified instance configuration combining global settings and worker configs.
+#[derive(Deserialize, Serialize, Clone, Debug, Default)]
+#[cfg_attr(feature = "instance_config_schema", derive(schemars::JsonSchema))]
+pub struct InstanceConfig {
+ #[serde(default)]
+ pub global_settings: GlobalSettings,
+ #[serde(default)]
+ pub worker_configs: BTreeMap,
+}
+
+// ---------------------------------------------------------------------------
+// Global settings
+// ---------------------------------------------------------------------------
+
+/// Generate a schema for opaque JSON objects (used for EE-private settings).
+/// Produces `{"type": "object", "nullable": true}` so the CRD passes K8s
+/// structural schema validation while still accepting any JSON object.
+#[cfg(feature = "instance_config_schema")]
+fn opaque_json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
+ schemars::schema::SchemaObject {
+ instance_type: Some(schemars::schema::InstanceType::Object.into()),
+ metadata: Some(Box::default()),
+ extensions: {
+ let mut m = schemars::Map::new();
+ m.insert(
+ "nullable".to_string(),
+ serde_json::Value::Bool(true),
+ );
+ m.insert(
+ "x-kubernetes-preserve-unknown-fields".to_string(),
+ serde_json::Value::Bool(true),
+ );
+ m
+ },
+ ..Default::default()
+ }
+ .into()
+}
+
+/// Typed global settings with schema validation.
+/// Known settings have explicit fields; unknown settings pass through via `extra`.
+#[derive(Deserialize, Serialize, Clone, Debug, Default)]
+#[cfg_attr(feature = "instance_config_schema", derive(schemars::JsonSchema))]
+pub struct GlobalSettings {
+ // Numeric settings
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub base_url: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub license_key: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub retention_period_secs: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub job_default_timeout: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub request_size_limit_mb: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub timeout_wait_result: Option,
+
+ // Boolean settings
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub expose_metrics: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub expose_debug_metrics: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub keep_job_dir: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub disable_stats: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub require_preexisting_user_for_oauth: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub dev_instance: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub critical_alert_mute_ui: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub monitor_logs_on_s3: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub app_workspaced_route: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub no_default_maven: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub default_tags_per_workspace: Option,
+
+ // String settings
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub email_domain: Option