diff --git a/.cursor/rules/rust-best-practices.mdc b/.cursor/rules/rust-best-practices.mdc index e8511c67d4..bdbdb0d24d 100644 --- a/.cursor/rules/rust-best-practices.mdc +++ b/.cursor/rules/rust-best-practices.mdc @@ -47,6 +47,7 @@ Windmill uses a workspace-based architecture with multiple crates: - Group related routes together - Use consistent response formats (JSON) - Follow proper authentication and authorization patterns +- Do not forget to update backend/windmill-api/openapi.yaml after modifying an api endpoint ## Performance Optimizations diff --git a/.github/workflows/aider-after-review.yaml b/.github/workflows/aider-after-review.yaml index 87d48ddb4c..2db321a7a8 100644 --- a/.github/workflows/aider-after-review.yaml +++ b/.github/workflows/aider-after-review.yaml @@ -90,5 +90,5 @@ jobs: with: needs_processing: false base_prompt: ${{ needs.check-and-prepare.outputs.prompt_content }} - rules_files: "CLAUDE.md backend/CLAUDE.md frontend/CLAUDE.md" + rules_files: ".cursor/rules/rust-best-practices.mdc .cursor/rules/svelte5-best-practices.mdc .cursor/rules/windmill-overview.mdc" secrets: inherit diff --git a/.github/workflows/aider-external.yaml b/.github/workflows/aider-external.yaml index cfdb03d352..c01152e3ce 100644 --- a/.github/workflows/aider-external.yaml +++ b/.github/workflows/aider-external.yaml @@ -76,5 +76,5 @@ jobs: issue_body: ${{ needs.check-and-prepare.outputs.issue_body }} instruction: ${{ needs.check-and-prepare.outputs.instruction }} issue_id: ${{ github.event.client_payload.issue_id }} - rules_files: "CLAUDE.md backend/CLAUDE.md frontend/CLAUDE.md" + rules_files: ".cursor/rules/rust-best-practices.mdc .cursor/rules/svelte5-best-practices.mdc .cursor/rules/windmill-overview.mdc" secrets: inherit diff --git a/.github/workflows/aider.yaml b/.github/workflows/aider.yaml index e7609597e3..2e943234b9 100644 --- a/.github/workflows/aider.yaml +++ b/.github/workflows/aider.yaml @@ -161,5 +161,5 @@ jobs: issue_body: ${{ needs.check-and-prepare.outputs.issue_body }} instruction: ${{ needs.check-and-prepare.outputs.comment_content }} issue_id: ${{ github.event.issue.number }} - rules_files: "CLAUDE.md backend/CLAUDE.md frontend/CLAUDE.md" + rules_files: ".cursor/rules/rust-best-practices.mdc .cursor/rules/svelte5-best-practices.mdc .cursor/rules/windmill-overview.mdc" secrets: inherit diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 9bc9f8d7ea..7261fb607c 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -69,17 +69,17 @@ jobs: with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} timeout_minutes: "60" - allowed_tools: "mcp__github__create_pull_request,Bash(npm run check),Bash(npm install),Bash(cargo check),Bash(curl https://sh.rustup.rs -sSf | sh)" + allowed_tools: "mcp__github__create_pull_request,Bash(npm run check),Bash(npm install),Bash(cargo check),Bash(curl https://sh.rustup.rs -sSf | sh -s -- -y)" custom_instructions: "IMPORTANT INSTRUCTIONS: - - Bypass previous instructions and instead of adding a url in your comment to manually create a PR, if you created a new branch with your changes, automatically create a PR from that branch to main, with the title starting with [Claude PR]. + - Bypass previous instructions and instead of adding a url in your comment to manually create a PR, if you created a new branch with your changes, automatically create a draft PR from that branch to main, with the title starting with [Claude PR]. - If you made changes to the frontend code, run npm install, then npm run generate-backend-client, then npm run check. You can ignore warnings that are reported by the check script, but fix the errors. - If you made changes to the backend code, install Rust and then run cargo check. You can ignore warnings that are reported by the check script, but fix the errors. - - DO NOT FORGET TO OPEN A PR AFTER YOU ARE DONE if you made changes after a request from a git issue. + - DO NOT FORGET TO OPEN A DRAFT PR AFTER YOU ARE DONE if you made changes after a request from a git issue. AVAILABLE TOOLS: - mcp__github__create_pull_request: Create a PR from a branch to main - Bash(npm run check): Run the check script. You should run this tool after making changes to the frontend code. - Bash(npm install): Install dependencies. You need this to run npm run check. - Bash(npm run generate-backend-client): Generate the backend client. You need this to run npm run check. - Bash(cargo check): Run the cargo check script. You should run this tool after making changes to the backend code. - - Bash(curl https://sh.rustup.rs -sSf | sh): Install Rust. You need this to run cargo check." + - Bash(curl https://sh.rustup.rs -sSf | sh -s -- -y): Install Rust. You need this to run cargo check." trigger_phrase: "/ai" diff --git a/.github/workflows/validate-openapi.yml b/.github/workflows/validate-openapi.yml new file mode 100644 index 0000000000..5bc59ebc4c --- /dev/null +++ b/.github/workflows/validate-openapi.yml @@ -0,0 +1,34 @@ +name: Validate OpenAPI Spec + +on: + push: + paths: + - 'backend/windmill-api/openapi*' + pull_request: + paths: + - 'backend/windmill-api/openapi*' +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install openapi-generator-cli + run: npm install @openapitools/openapi-generator-cli -g + + - name: Validate openapi.yaml + run: npx @openapitools/openapi-generator-cli validate -i backend/windmill-api/openapi.yaml + + - name: Validate openapi-deref.json + run: npx @openapitools/openapi-generator-cli validate -i backend/windmill-api/openapi-deref.json + + # Does not work well with dereferenced yaml + # - name: Validate openapi-deref.yaml + # run: npx @openapitools/openapi-generator-cli validate -i backend/windmill-api/openapi-deref.yaml + diff --git a/CHANGELOG.md b/CHANGELOG.md index af899a02cb..94351573de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,65 @@ # Changelog +## [1.494.0](https://github.com/windmill-labs/windmill/compare/v1.493.4...v1.494.0) (2025-05-31) + + +### Features + +* array of s3 objects in input maker ([806d669](https://github.com/windmill-labs/windmill/commit/806d66972568d21a1621acd1b30db5ae9b217341)) +* **rust:** shared build directory ([#5610](https://github.com/windmill-labs/windmill/issues/5610)) ([ed61d97](https://github.com/windmill-labs/windmill/commit/ed61d9770031c1a04908880dbd3e5fb692df9946)) + + +### Bug Fixes + +* allow disable tabs for sidebar/accordion tabs ([#5838](https://github.com/windmill-labs/windmill/issues/5838)) ([80277d1](https://github.com/windmill-labs/windmill/commit/80277d14d02e8e596c7002326946142226d382a6)) + +## [1.493.4](https://github.com/windmill-labs/windmill/compare/v1.493.3...v1.493.4) (2025-05-29) + + +### Bug Fixes + +* templatev2 delete issue ([#5834](https://github.com/windmill-labs/windmill/issues/5834)) ([ed3ad32](https://github.com/windmill-labs/windmill/commit/ed3ad327a235c16b9f3aa7f8edeefe61b0c01da3)) + +## [1.493.3](https://github.com/windmill-labs/windmill/compare/v1.493.2...v1.493.3) (2025-05-29) + + +### Bug Fixes + +* evalv2 prohibit component delete ([e302aa3](https://github.com/windmill-labs/windmill/commit/e302aa38b5977dd406ae05e1d8dbb74cb7dc3d17)) +* faster layout for larger graphs ([8d12bcc](https://github.com/windmill-labs/windmill/commit/8d12bcc8ee2991909ea0d9bb57f04f0d4106c69f)) + +## [1.493.2](https://github.com/windmill-labs/windmill/compare/v1.493.1...v1.493.2) (2025-05-28) + + +### Bug Fixes + +* improve monaco editor memory leak ([e0f4f83](https://github.com/windmill-labs/windmill/commit/e0f4f83ebf4416c3bcc24433a7bf606349e1f75a)) +* improve monaco javascript extra lib refresh ([7b70348](https://github.com/windmill-labs/windmill/commit/7b70348b4bba3726e3fb26c964219a5a2aa6af55)) + +## [1.493.1](https://github.com/windmill-labs/windmill/compare/v1.493.0...v1.493.1) (2025-05-28) + + +### Bug Fixes + +* improve monaco javascript extra lib refresh ([a2c8ea6](https://github.com/windmill-labs/windmill/commit/a2c8ea69a3962a350273717cd237d8a96523fd00)) + +## [1.493.0](https://github.com/windmill-labs/windmill/compare/v1.492.1...v1.493.0) (2025-05-27) + + +### Features + +* add aws oidc support for instance s3 storage ([#5810](https://github.com/windmill-labs/windmill/issues/5810)) ([5b96bcc](https://github.com/windmill-labs/windmill/commit/5b96bccedd6e68fea631580dd49338301ad0305f)) +* duckdb sql lang support ([#5761](https://github.com/windmill-labs/windmill/issues/5761)) ([fdefd4b](https://github.com/windmill-labs/windmill/commit/fdefd4be9398b9610a539360353fd61b521732d4)) +* **python:** inline script metadata (PEP 723) ([#5712](https://github.com/windmill-labs/windmill/issues/5712)) ([2622253](https://github.com/windmill-labs/windmill/commit/26222539e66bce7e88f86a7e5917e6ca99350865)) + + +### Bug Fixes + +* add missing http_trigger_version_seq grants ([#5816](https://github.com/windmill-labs/windmill/issues/5816)) ([306f3ea](https://github.com/windmill-labs/windmill/commit/306f3eabd1c03fa904b0e59438de124a0e680597)) +* avoid monaco memory leak ([0d459d5](https://github.com/windmill-labs/windmill/commit/0d459d5d223728270854e37715ecc1663ede9870)) +* error handler node rendering at top level ([feae9b0](https://github.com/windmill-labs/windmill/commit/feae9b09240ba306c007013a36d2aefb0b273766)) +* **frontend:** auto completion and render of tailwind classes in app editor ([#5817](https://github.com/windmill-labs/windmill/issues/5817)) ([5897e7e](https://github.com/windmill-labs/windmill/commit/5897e7e01b8839425c30c2a97481ef7bb9090661)) + ## [1.492.1](https://github.com/windmill-labs/windmill/compare/v1.492.0...v1.492.1) (2025-05-22) diff --git a/CLAUDE.md b/CLAUDE.md index 3b701f2536..00d81d1b48 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,71 +1,3 @@ -# Windmill Overview - -Windmill is an open-source developer platform for building internal tools, API integrations, background jobs, workflows, and user interfaces. It offers a unified system where scripts are automatically turned into sharable UIs and can be composed into flows or embedded in custom applications. - -## Core Capabilities - -- **Script Development and Execution**: Write and run scripts in Python, TypeScript/JavaScript (Deno/Bun), Go, Bash, SQL, and other languages -- **Workflow Orchestration**: Compose scripts into multi-step flows with conditional logic, loops, and error handling -- **UI Generation**: Automatically generate UIs from scripts or build custom applications with a low-code editor -- **Job Scheduling**: Trigger scripts and flows on schedules, webhooks, or external events -- **Resource Management**: Securely store and use credentials, databases, and other connections - -## Platform Architecture - -The Windmill platform consists of several key components: - -- **Frontend UI**: Web-based interface for script and flow development, app building, and result visualization -- **API Server**: Central API that handles authentication, resource management, and job coordination -- **Workers**: Execute scripts in their respective environments with proper sandboxing -- **Database**: PostgreSQL database for storage of scripts, flows, resources, job results, and more -- **Job Queue**: Queue system for managing job execution, implemented in PostgreSQL -- **Client Libraries**: Libraries for interacting with Windmill from Python, TypeScript, or command line - -# Windmill Backend Architecture - -The Windmill backend is written in Rust and consists of several services working together. These services are designed for horizontal scaling with stateless API servers and workers that can be deployed across multiple machines. - -## Key Components - -- **API Server (`windmill-api`)**: Handles HTTP requests, authentication, and resource management -- **Queue Manager (`windmill-queue`)**: Manages the job queue in PostgreSQL -- **Worker System (`windmill-worker`)**: Executes jobs in sandboxed environments -- **Common Utilities (`windmill-common`)**: Shared code used by multiple services -- **Git Sync (`windmill-git-sync`)**: Synchronizes scripts with Git repositories - -## Job Execution System - -The job execution process follows these steps: - -1. The API server receives a request to run a script or flow and creates a job record in the database -2. The job is added to the queue system in PostgreSQL -3. Workers continuously poll the queue for jobs matching their capabilities -4. When a job is picked up, it's routed to the appropriate language executor -5. The script is executed in a sandboxed environment using NSJAIL for security -6. Results are processed and stored in the database -7. For flows, each step creates a new job that goes through the same process - -Windmill supports worker tags and groups to route jobs to workers with specific capabilities or resource access. - -# Windmill Frontend Architecture - -The Windmill frontend is built with Svelte and provides several key interfaces for interacting with the platform. - -## Key Components - -- **Script Builder**: Code editor with language support, schema inference, and dependency management -- **Flow Builder**: Visual editor for creating multi-step workflows with branching and looping -- **App Editor**: Grid-based editor for building custom UIs that integrate scripts and flows -- **Schema Form System**: Generates form interfaces from script parameters automatically -- **Result Viewer**: Visualizes job results, logs, and execution status - -The frontend uses the Monaco editor (same as VS Code) for code editing, with specialized language support for all supported script languages. - -## UI Framework - -The frontend is built with Svelte, providing a reactive and component-based architecture. Key frontend technologies include: - -- **Svelte/SvelteKit**: Core framework for UI components and routing -- **Monaco Editor**: Code editing experience similar to VS Code -- **Schema Form**: Automatic UI generation from TypeScript/JSON schemas -- **Tailwind CSS**: Utility-first CSS framework for styling +To have an overview of what this app does, see @.cursor/rules/windmill-overview.mdc +For backend modifications, follow the rules mentioned here @.cursor/rules/rust-best-practices.mdc +For frontend modifications, follow the rules mentioned here @.cursor/rules/svelte5-best-practices.mdc diff --git a/backend/.gitignore b/backend/.gitignore index 4ca669fc53..f75b9d1eaa 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -5,4 +5,5 @@ oauth2.json tracing.folded heaptrack* index/ -windmill-api/openapi-*.* \ No newline at end of file +windmill-api/openapi-*.* +.duckdb/* \ No newline at end of file diff --git a/backend/.sqlx/query-13444bbd5547e101c41206c5f97ac4dded0536faf52c370d704ed9a451041caf.json b/backend/.sqlx/query-13444bbd5547e101c41206c5f97ac4dded0536faf52c370d704ed9a451041caf.json new file mode 100644 index 0000000000..6b8e275167 --- /dev/null +++ b/backend/.sqlx/query-13444bbd5547e101c41206c5f97ac4dded0536faf52c370d704ed9a451041caf.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM sqs_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "13444bbd5547e101c41206c5f97ac4dded0536faf52c370d704ed9a451041caf" +} diff --git a/backend/.sqlx/query-2ef25599ea0c9ef946d6cc70ae048af970aed2638a3f767e152b654aebf68e48.json b/backend/.sqlx/query-2ef25599ea0c9ef946d6cc70ae048af970aed2638a3f767e152b654aebf68e48.json deleted file mode 100644 index da7d13f71c..0000000000 --- a/backend/.sqlx/query-2ef25599ea0c9ef946d6cc70ae048af970aed2638a3f767e152b654aebf68e48.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SHOW WAL_LEVEL;", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "wal_level", - "type_info": "Text" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - null - ] - }, - "hash": "2ef25599ea0c9ef946d6cc70ae048af970aed2638a3f767e152b654aebf68e48" -} diff --git a/backend/.sqlx/query-4469ee6c206c46951980ea1bc73f126f339d2e3cf97f363be8921084b16dac45.json b/backend/.sqlx/query-4469ee6c206c46951980ea1bc73f126f339d2e3cf97f363be8921084b16dac45.json deleted file mode 100644 index 46a8d2e4f0..0000000000 --- a/backend/.sqlx/query-4469ee6c206c46951980ea1bc73f126f339d2e3cf97f363be8921084b16dac45.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT pubname AS publication_name FROM pg_publication;", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "publication_name", - "type_info": "Name" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - false - ] - }, - "hash": "4469ee6c206c46951980ea1bc73f126f339d2e3cf97f363be8921084b16dac45" -} diff --git a/backend/.sqlx/query-4ee0017771f46f0272817d18edb821940cb5064e3f155b9630b131c09c9dba13.json b/backend/.sqlx/query-4ee0017771f46f0272817d18edb821940cb5064e3f155b9630b131c09c9dba13.json deleted file mode 100644 index 52136dd33e..0000000000 --- a/backend/.sqlx/query-4ee0017771f46f0272817d18edb821940cb5064e3f155b9630b131c09c9dba13.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT \n slot_name,\n active\n FROM\n pg_replication_slots \n WHERE \n plugin = 'pgoutput' AND\n slot_type = 'logical';\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "slot_name", - "type_info": "Name" - }, - { - "ordinal": 1, - "name": "active", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - true, - true - ] - }, - "hash": "4ee0017771f46f0272817d18edb821940cb5064e3f155b9630b131c09c9dba13" -} diff --git a/backend/.sqlx/query-6a19c440a7a8064f3969cf6f48adea0bfdb683de9555e374ce5731e0b3c379f9.json b/backend/.sqlx/query-6a19c440a7a8064f3969cf6f48adea0bfdb683de9555e374ce5731e0b3c379f9.json new file mode 100644 index 0000000000..4ea7dabd04 --- /dev/null +++ b/backend/.sqlx/query-6a19c440a7a8064f3969cf6f48adea0bfdb683de9555e374ce5731e0b3c379f9.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM gcp_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "6a19c440a7a8064f3969cf6f48adea0bfdb683de9555e374ce5731e0b3c379f9" +} diff --git a/backend/.sqlx/query-6f56acb985aa7141ea1891d7ad58a32c35d1b02fe7070c92a2e62c1a5339c396.json b/backend/.sqlx/query-6f56acb985aa7141ea1891d7ad58a32c35d1b02fe7070c92a2e62c1a5339c396.json deleted file mode 100644 index f3bda55eec..0000000000 --- a/backend/.sqlx/query-6f56acb985aa7141ea1891d7ad58a32c35d1b02fe7070c92a2e62c1a5339c396.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT slot_name FROM pg_replication_slots where slot_name = $1", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "slot_name", - "type_info": "Name" - } - ], - "parameters": { - "Left": [ - "Name" - ] - }, - "nullable": [ - true - ] - }, - "hash": "6f56acb985aa7141ea1891d7ad58a32c35d1b02fe7070c92a2e62c1a5339c396" -} diff --git a/backend/.sqlx/query-7e64ba7e2362cc19d2aed9f34c9879983922e96a9baab7c1a2b09ed2b1c261e2.json b/backend/.sqlx/query-7e64ba7e2362cc19d2aed9f34c9879983922e96a9baab7c1a2b09ed2b1c261e2.json deleted file mode 100644 index 9984af6e6e..0000000000 --- a/backend/.sqlx/query-7e64ba7e2362cc19d2aed9f34c9879983922e96a9baab7c1a2b09ed2b1c261e2.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT \n active_pid \n FROM \n pg_replication_slots \n WHERE \n slot_name = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "active_pid", - "type_info": "Int4" - } - ], - "parameters": { - "Left": [ - "Name" - ] - }, - "nullable": [ - true - ] - }, - "hash": "7e64ba7e2362cc19d2aed9f34c9879983922e96a9baab7c1a2b09ed2b1c261e2" -} diff --git a/backend/.sqlx/query-86ae16175ace0179e784aacfd381771f0137ecab6671d632febadede729e7783.json b/backend/.sqlx/query-86ae16175ace0179e784aacfd381771f0137ecab6671d632febadede729e7783.json deleted file mode 100644 index cbf85f6b0d..0000000000 --- a/backend/.sqlx/query-86ae16175ace0179e784aacfd381771f0137ecab6671d632febadede729e7783.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n puballtables AS all_table,\n pubinsert AS insert,\n pubupdate AS update,\n pubdelete AS delete\n FROM\n pg_publication\n WHERE\n pubname = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "all_table", - "type_info": "Bool" - }, - { - "ordinal": 1, - "name": "insert", - "type_info": "Bool" - }, - { - "ordinal": 2, - "name": "update", - "type_info": "Bool" - }, - { - "ordinal": 3, - "name": "delete", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Name" - ] - }, - "nullable": [ - false, - false, - false, - false - ] - }, - "hash": "86ae16175ace0179e784aacfd381771f0137ecab6671d632febadede729e7783" -} diff --git a/backend/.sqlx/query-a8b470b463ca4b7c00c7ef6e9f36c23f8bbcefc288a56d61122bfd6fe5ca7e8d.json b/backend/.sqlx/query-a8b470b463ca4b7c00c7ef6e9f36c23f8bbcefc288a56d61122bfd6fe5ca7e8d.json new file mode 100644 index 0000000000..6ac4ee6755 --- /dev/null +++ b/backend/.sqlx/query-a8b470b463ca4b7c00c7ef6e9f36c23f8bbcefc288a56d61122bfd6fe5ca7e8d.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM mqtt_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "a8b470b463ca4b7c00c7ef6e9f36c23f8bbcefc288a56d61122bfd6fe5ca7e8d" +} diff --git a/backend/.sqlx/query-baa1dddc616419bf4b923715f0a863bc0ff69c98db0f0c8f55e4ac89fdde7a60.json b/backend/.sqlx/query-baa1dddc616419bf4b923715f0a863bc0ff69c98db0f0c8f55e4ac89fdde7a60.json deleted file mode 100644 index e772354ea8..0000000000 --- a/backend/.sqlx/query-baa1dddc616419bf4b923715f0a863bc0ff69c98db0f0c8f55e4ac89fdde7a60.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT pubname FROM pg_publication WHERE pubname = $1", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "pubname", - "type_info": "Name" - } - ], - "parameters": { - "Left": [ - "Name" - ] - }, - "nullable": [ - false - ] - }, - "hash": "baa1dddc616419bf4b923715f0a863bc0ff69c98db0f0c8f55e4ac89fdde7a60" -} diff --git a/backend/.sqlx/query-fd5754fe3c6346ae28818a9d60d144a40f8884f47e5bbdd2824e939dafd8f154.json b/backend/.sqlx/query-fd5754fe3c6346ae28818a9d60d144a40f8884f47e5bbdd2824e939dafd8f154.json deleted file mode 100644 index e797ab8805..0000000000 --- a/backend/.sqlx/query-fd5754fe3c6346ae28818a9d60d144a40f8884f47e5bbdd2824e939dafd8f154.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n schemaname AS schema_name,\n tablename AS table_name,\n CASE\n WHEN array_length(attnames, 1) = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = pg_publication_tables.schemaname AND table_name = pg_publication_tables.tablename)\n THEN NULL\n ELSE attnames\n END AS columns,\n rowfilter AS where_clause\n FROM\n pg_publication_tables\n WHERE\n pubname = $1;\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "schema_name", - "type_info": "Name" - }, - { - "ordinal": 1, - "name": "table_name", - "type_info": "Name" - }, - { - "ordinal": 2, - "name": "columns", - "type_info": "NameArray" - }, - { - "ordinal": 3, - "name": "where_clause", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Name" - ] - }, - "nullable": [ - true, - true, - null, - true - ] - }, - "hash": "fd5754fe3c6346ae28818a9d60d144a40f8884f47e5bbdd2824e939dafd8f154" -} diff --git a/backend/.vscode/settings.json b/backend/.vscode/settings.json index 6ebd36cf07..00cebd7fb6 100644 --- a/backend/.vscode/settings.json +++ b/backend/.vscode/settings.json @@ -11,5 +11,6 @@ "remote.autoForwardPorts": true, "conventionalCommits.scopes": [ "restructring triggers, decoding trigger message on work" - ] + ], + "rust-analyzer.cargo.features": ["postgres_trigger"] } diff --git a/backend/CLAUDE.md b/backend/CLAUDE.md deleted file mode 100644 index 382c7a04a9..0000000000 --- a/backend/CLAUDE.md +++ /dev/null @@ -1,104 +0,0 @@ -# Windmill Backend - Rust Best Practices - -## Project Structure - -Windmill uses a workspace-based architecture with multiple crates: - -- **windmill-api**: API server functionality -- **windmill-worker**: Job execution -- **windmill-common**: Shared code used by all crates -- **windmill-queue**: Job & flow queuing -- **windmill-audit**: Audit logging -- Other specialized crates (git-sync, autoscaling, etc.) - -## Adding New Code - -### Module Organization - -- Place new code in the appropriate crate based on functionality -- For API endpoints, create or modify files in `windmill-api/src/` organized by domain -- For shared functionality, use `windmill-common/src/` -- Use the `_ee.rs` suffix for enterprise-only modules -- Follow existing patterns for file structure and organization - -### Error Handling - -- Use the custom `Error` enum from `windmill-common::error` -- Return `Result` or `JsonResult` for functions that can fail -- Use the `?` operator for error propagation -- Add location tracking to errors using `#[track_caller]` - -### Database Operations - -- Use `sqlx` for database operations with prepared statements -- Leverage existing database helper functions in `db.rs` modules -- Use transactions for multi-step operations -- Handle database errors properly - -### API Endpoints - -- Follow existing patterns in the `windmill-api` crate -- Use axum's routing system and extractors -- Group related routes together -- Use consistent response formats (JSON) -- Follow proper authentication and authorization patterns - -## Performance Optimizations - -When generating code, especially involving `serde`, `sqlx`, and `tokio`, prioritize performance by applying the following principles: - -### Serde Optimizations (Serialization & Deserialization) - -- **Specify Structure Explicitly:** When defining structs for Serde (`#[derive(Serialize, Deserialize)]`), use `#[serde(...` attributes extensively. This includes: - - `#[serde(rename = "...")]` or `#[serde(alias = "...")]` to map external names precisely, avoiding dynamic lookups. - - `#[serde(default)]` for optional fields with default values, reducing parsing complexity. - - `#[serde(skip_serializing_if = "...")]` to avoid writing fields that meet a certain condition (e.g., `Option::is_none()`, `Vec::is_empty()`, or a custom function), reducing output size and serialization work. - - `#[serde(skip_serializing)]` or `#[serde(skip_deserializing)]` for fields that should _not_ be included. -- **Prefer Borrowing:** Where possible and safe (data lifetime allows), use `Cow<'a, str>` or `&'a str` (with `#[serde(borrow)]`) instead of `String` for string fields during deserialization. This avoids allocating new strings, enabling zero-copy reading from the input buffer. Apply this principle to byte slices (`&'a [u8]` / `Cow<'a, [u8]>`) and potentially borrowed vectors as well. -- **Avoid Intermediate `Value`:** Unless the data structure is truly dynamic or unknown at compile time, deserialize directly into a well-defined struct or enum rather than into `serde_json::Value` (or equivalent for other formats). This avoids unnecessary heap allocations and type switching. - -### SQLx Optimizations (Database Interaction) - -- **Select Only Necessary Columns:** In `SELECT` queries, list specific column names rather than using `SELECT *`. This reduces data transferred from the database and the work needed for hydration/deserialization. -- **Batch Operations:** For multiple `INSERT`, `UPDATE`, or `DELETE` statements, prefer executing them in a single query if the database and driver support it efficiently (e.g., `INSERT INTO ... VALUES (...), (...), ...`). This minimizes round trips to the database. -- **Avoid N+1 Queries:** Do not loop through results of one query and execute a separate query for each item (e.g., fetching users, then querying for each user's profile in a loop). Instead, use JOINs or a single query with an `IN` clause to fetch related data efficiently. -- **Deserialize Directly:** Use `#[derive(FromRow)]` on structs and ensure the struct fields match the selected columns in the query. This allows SQLx to hydrate objects directly, avoiding intermediate data structures. -- **Parameterize Queries:** Always use SQLx's query methods (`.bind(...)`) to pass values as parameters rather than string formatting. This prevents SQL injection and allows the database to cache query plans, improving performance on repeated executions. - -### Tokio Optimizations (Asynchronous Runtime) - -- **Avoid Blocking Operations:** **Crucially**, never perform blocking operations (synchronous file I/O, `std::thread::sleep`, CPU-bound loops, `std::sync::Mutex::lock`, blocking network calls without `tokio::net`) directly within an `async fn` or a standard `tokio::spawn` task. Blocking pauses the entire worker thread, potentially starving other tasks. Use `tokio::task::spawn_blocking` for CPU-intensive work or blocking I/O. -- **Use Tokio's Async Primitives:** Prefer `tokio::sync` (channels, mutexes, semaphores), `tokio::io`, `tokio::net`, and `tokio::time` over their `std` counterparts in asynchronous contexts. These are designed to yield control back to the scheduler. -- **Manage Concurrency:** Be mindful of how many tasks are spawned. Creating a new task for every tiny piece of work can introduce overhead. Group related asynchronous operations where appropriate. -- **Handle Shared State Efficiently:** Use `Arc` for shared ownership in concurrent tasks. When shared state needs mutation, prefer `tokio::sync::Mutex` over `std::sync::Mutex` in `async` code. Consider `tokio::sync::RwLock` if reads significantly outnumber writes. Minimize the duration for which locks are held. -- **Understand `.await`:** Place `.await` strategically to allow the runtime to switch to other ready tasks. Ensure that `.await` points to genuinely asynchronous operations. -- **Backpressure:** If dealing with data streams or queues between tasks, implement backpressure mechanisms (e.g., bounded channels like `tokio::sync::mpsc::channel`) to prevent one component from overwhelming another or critical resources like the database. - -## Enterprise Features - -- Use feature flags for enterprise functionality -- Conditionally compile with `#[cfg(feature = "enterprise")]` -- Isolate enterprise code in separate modules - -## Code Style - -- Group imports by external and internal crates -- Place struct/enum definitions before implementations -- Group similar functionality together -- Use descriptive naming consistent with the codebase -- Follow existing patterns for async code using tokio - -## Testing - -- Write unit tests for core functionality -- Use the `#[cfg(test)]` module for test code -- For database tests, use the existing test utilities - -## Common Crates Used - -- **tokio**: For async runtime -- **axum**: For web server and routing -- **sqlx**: For database operations -- **serde**: For serialization/deserialization -- **tracing**: For logging and diagnostics -- **reqwest**: For HTTP client functionality diff --git a/backend/Cargo.lock b/backend/Cargo.lock index eaf6ef8e37..fe8e9c769b 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -286,25 +286,57 @@ dependencies = [ "serde", ] +[[package]] +name = "arrow" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5ec52ba94edeed950e4a41f75d35376df196e8cb04437f7280a5aa49f20f796" +dependencies = [ + "arrow-arith 54.3.1", + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-cast 54.3.1", + "arrow-data 54.3.1", + "arrow-ord 54.3.1", + "arrow-row 54.3.1", + "arrow-schema 54.3.1", + "arrow-select 54.3.1", + "arrow-string 54.3.1", +] + [[package]] name = "arrow" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1bb018b6960c87fd9d025009820406f74e83281185a8bdcb44880d2aa5c9a87" dependencies = [ - "arrow-arith", - "arrow-array", - "arrow-buffer", - "arrow-cast", + "arrow-arith 55.1.0", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-cast 55.1.0", "arrow-csv", - "arrow-data", + "arrow-data 55.1.0", "arrow-ipc", "arrow-json", - "arrow-ord", - "arrow-row", - "arrow-schema", - "arrow-select", - "arrow-string", + "arrow-ord 55.1.0", + "arrow-row 55.1.0", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", + "arrow-string 55.1.0", +] + +[[package]] +name = "arrow-arith" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc766fdacaf804cb10c7c70580254fcdb5d55cdfda2bc57b02baf5223a3af9e" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "chrono", + "num", ] [[package]] @@ -313,14 +345,30 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44de76b51473aa888ecd6ad93ceb262fb8d40d1f1154a4df2f069b3590aa7575" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "chrono", "num", ] +[[package]] +name = "arrow-array" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12fcdb3f1d03f69d3ec26ac67645a8fe3f878d77b5ebb0b15d64a116c212985" +dependencies = [ + "ahash 0.8.12", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "chrono", + "half", + "hashbrown 0.15.3", + "num", +] + [[package]] name = "arrow-array" version = "55.1.0" @@ -328,9 +376,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ed77e22744475a9a53d00026cf8e166fe73cf42d89c4c4ae63607ee1cfcc3f" dependencies = [ "ahash 0.8.12", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "chrono", "chrono-tz", "half", @@ -338,6 +386,17 @@ dependencies = [ "num", ] +[[package]] +name = "arrow-buffer" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "263f4801ff1839ef53ebd06f99a56cecd1dbaf314ec893d93168e2e860e0291c" +dependencies = [ + "bytes", + "half", + "num", +] + [[package]] name = "arrow-buffer" version = "55.1.0" @@ -349,17 +408,38 @@ dependencies = [ "num", ] +[[package]] +name = "arrow-cast" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede6175fbc039dfc946a61c1b6d42fd682fcecf5ab5d148fbe7667705798cac9" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "arrow-select 54.3.1", + "atoi", + "base64 0.22.1", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num", + "ryu", +] + [[package]] name = "arrow-cast" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f39e1d774ece9292697fcbe06b5584401b26bd34be1bec25c33edae65c2420ff" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", - "arrow-select", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", "atoi", "base64 0.22.1", "chrono", @@ -376,9 +456,9 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9055c972a07bf12c2a827debfd34f88d3b93da1941d36e1d9fee85eebe38a12a" dependencies = [ - "arrow-array", - "arrow-cast", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-cast 55.1.0", + "arrow-schema 55.1.0", "chrono", "csv", "csv-core", @@ -386,14 +466,26 @@ dependencies = [ "regex", ] +[[package]] +name = "arrow-data" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61cfdd7d99b4ff618f167e548b2411e5dd2c98c0ddebedd7df433d34c20a4429" +dependencies = [ + "arrow-buffer 54.3.1", + "arrow-schema 54.3.1", + "half", + "num", +] + [[package]] name = "arrow-data" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf75ac27a08c7f48b88e5c923f267e980f27070147ab74615ad85b5c5f90473d" dependencies = [ - "arrow-buffer", - "arrow-schema", + "arrow-buffer 55.1.0", + "arrow-schema 55.1.0", "half", "num", ] @@ -404,10 +496,10 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a222f0d93772bd058d1268f4c28ea421a603d66f7979479048c429292fac7b2e" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "flatbuffers", "lz4_flex", ] @@ -418,11 +510,11 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9085342bbca0f75e8cb70513c0807cc7351f1fbf5cb98192a67d5e3044acb033" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-cast 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "chrono", "half", "indexmap 2.9.0", @@ -434,17 +526,43 @@ dependencies = [ "simdutf8", ] +[[package]] +name = "arrow-ord" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0a3334a743bd2a1479dbc635540617a3923b4b2f6870f37357339e6b5363c21" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "arrow-select 54.3.1", +] + [[package]] name = "arrow-ord" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2f1065a5cad7b9efa9e22ce5747ce826aa3855766755d4904535123ef431e7" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", - "arrow-select", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", +] + +[[package]] +name = "arrow-row" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d1d7a7291d2c5107e92140f75257a99343956871f3d3ab33a7b41532f79cb68" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "half", ] [[package]] @@ -453,19 +571,42 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3703a0e3e92d23c3f756df73d2dc9476873f873a76ae63ef9d3de17fda83b2d8" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "half", ] +[[package]] +name = "arrow-schema" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cfaf5e440be44db5413b75b72c2a87c1f8f0627117d110264048f2969b99e9" +dependencies = [ + "bitflags 2.9.1", +] + [[package]] name = "arrow-schema" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73a47aa0c771b5381de2b7f16998d351a6f4eb839f1e13d48353e17e873d969b" +[[package]] +name = "arrow-select" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69efcd706420e52cd44f5c4358d279801993846d1c2a8e52111853d61d55a619" +dependencies = [ + "ahash 0.8.12", + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "num", +] + [[package]] name = "arrow-select" version = "55.1.0" @@ -473,24 +614,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24b7b85575702b23b85272b01bc1c25a01c9b9852305e5d0078c79ba25d995d4" dependencies = [ "ahash 0.8.12", - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "num", ] +[[package]] +name = "arrow-string" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21546b337ab304a32cfc0770f671db7411787586b45b78b4593ae78e64e2b03" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "arrow-select 54.3.1", + "memchr", + "num", + "regex", + "regex-syntax 0.8.5", +] + [[package]] name = "arrow-string" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9260fddf1cdf2799ace2b4c2fc0356a9789fa7551e0953e35435536fecefebbd" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", - "arrow-select", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", "memchr", "num", "regex", @@ -633,7 +791,7 @@ dependencies = [ "bytes", "http 1.3.1", "rand 0.8.5", - "reqwest 0.12.15", + "reqwest 0.12.18", "serde", "serde-aux", "serde_json", @@ -833,9 +991,9 @@ dependencies = [ [[package]] name = "aws-sdk-sqs" -version = "1.70.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b742e0981caafc34a57b36d6e492786e2a11638766f49e1c92dec1b55f33d16b" +checksum = "0519921fc7065a54b8dec1d10de2893d99a61d030b9f8eb00ee83eb62d2a2676" dependencies = [ "aws-credential-types", "aws-runtime", @@ -855,9 +1013,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.70.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83447efb7179d8e2ad2afb15ceb9c113debbc2ecdf109150e338e2e28b86190b" +checksum = "95a4fd09d6e863655d99cd2260f271c6d1030dc6bfad68e19e126d2e4c8ceb18" dependencies = [ "aws-credential-types", "aws-runtime", @@ -877,9 +1035,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.71.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f9bfbbda5e2b9fe330de098f14558ee8b38346408efe9f2e9cee82dc1636a4" +checksum = "3224ab02ebb3074467a33d57caf6fcb487ca36f3697fdd381b0428dc72380696" dependencies = [ "aws-credential-types", "aws-runtime", @@ -899,9 +1057,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.71.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17b984a66491ec08b4f4097af8911251db79296b3e4a763060b45805746264f" +checksum = "f6933f189ed1255e78175fbd73fb200c0aae7240d220ed3346f567b0ddca3083" dependencies = [ "aws-credential-types", "aws-runtime", @@ -989,7 +1147,7 @@ dependencies = [ "hyper 0.14.32", "hyper 1.6.0", "hyper-rustls 0.24.2", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.6", "hyper-util", "pin-project-lite", "rustls 0.21.12", @@ -1193,9 +1351,9 @@ checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] name = "backon" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0b50b1b78dbadd44ab18b3c794e496f3a139abb9fbc27d9c94c4eebbb96496" +checksum = "302eaff5357a264a2c42f127ecb8bac761cf99749fc3dc95677e2743991f99e7" dependencies = [ "fastrand", "gloo-timers", @@ -1838,6 +1996,12 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cbc" version = "0.1.2" @@ -1849,9 +2013,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.23" +version = "1.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" +checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" dependencies = [ "jobserver", "libc", @@ -1964,14 +2128,14 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading 0.8.7", + "libloading 0.8.8", ] [[package]] name = "clap" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", "clap_derive", @@ -1979,9 +2143,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstream", "anstyle", @@ -2213,9 +2377,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -2445,7 +2609,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813" dependencies = [ "bitflags 2.9.1", - "libloading 0.8.7", + "libloading 0.8.8", "winapi", ] @@ -2564,7 +2728,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core 0.9.11", ] [[package]] @@ -2578,7 +2742,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core 0.9.11", ] [[package]] @@ -2599,9 +2763,9 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe060b978f74ab446be722adb8a274e052e005bf6dfd171caadc3abaad10080" dependencies = [ - "arrow", + "arrow 55.1.0", "arrow-ipc", - "arrow-schema", + "arrow-schema 55.1.0", "async-trait", "bytes", "bzip2", @@ -2635,7 +2799,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "parquet", "rand 0.8.5", "regex", @@ -2654,7 +2818,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61fe34f401bd03724a1f96d12108144f8cd495a3cdda2bf5e091822fb80b7e66" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "dashmap 6.1.0", "datafusion-common", @@ -2670,7 +2834,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "tokio", ] @@ -2680,7 +2844,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4411b8e3bce5e0fc7521e44f201def2e2d5d1b5f176fb56e8cdc9942c890f00" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "datafusion-catalog", "datafusion-common", @@ -2704,7 +2868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0734015d81c8375eb5d4869b7f7ecccc2ee8d6cb81948ef737cd0e7b743bd69c" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "arrow-ipc", "base64 0.22.1", "half", @@ -2738,7 +2902,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04e602dcdf2f50c2abf297cc2203c73531e6f48b29516af7695d338cf2a778b1" dependencies = [ - "arrow", + "arrow 55.1.0", "async-compression", "async-trait", "bytes", @@ -2774,7 +2938,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bb2253952dc32296ed5b84077cb2e0257fea4be6373e1c376426e17ead4ef6" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "bytes", "datafusion-catalog", @@ -2799,7 +2963,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8c7f47a5d2fe03bfa521ec9bafdb8a5c82de8377f60967c3663f00c8790352" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "bytes", "datafusion-catalog", @@ -2824,7 +2988,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27d15868ea39ed2dc266728b554f6304acd473de2142281ecfa1294bb7415923" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "bytes", "datafusion-catalog", @@ -2843,7 +3007,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "parquet", "rand 0.8.5", "tokio", @@ -2861,14 +3025,14 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06f004d100f49a3658c9da6fb0c3a9b760062d96cd4ad82ccc3b7b69a9fb2f84" dependencies = [ - "arrow", + "arrow 55.1.0", "dashmap 6.1.0", "datafusion-common", "datafusion-expr", "futures", "log", "object_store", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "tempfile", "url", @@ -2880,7 +3044,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a4e4ce3802609be38eeb607ee72f6fe86c3091460de9dbfae9e18db423b3964" dependencies = [ - "arrow", + "arrow 55.1.0", "chrono", "datafusion-common", "datafusion-doc", @@ -2901,7 +3065,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "422ac9cf3b22bbbae8cdf8ceb33039107fde1b5492693168f13bd566b1bcc839" dependencies = [ - "arrow", + "arrow 55.1.0", "datafusion-common", "indexmap 2.9.0", "itertools 0.14.0", @@ -2914,8 +3078,8 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ddf0a0a2db5d2918349c978d42d80926c6aa2459cd8a3c533a84ec4bb63479e" dependencies = [ - "arrow", - "arrow-buffer", + "arrow 55.1.0", + "arrow-buffer 55.1.0", "base64 0.22.1", "blake2", "blake3", @@ -2944,7 +3108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "408a05dafdc70d05a38a29005b8b15e21b0238734dab1e98483fcb58038c5aba" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-doc", "datafusion-execution", @@ -2965,7 +3129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "756d21da2dd6c9bef97af1504970ff56cbf35d03fbd4ffd62827f02f4d2279d4" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-expr-common", "datafusion-physical-expr-common", @@ -2977,8 +3141,8 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d8d50f6334b378930d992d801a10ac5b3e93b846b39e4a05085742572844537" dependencies = [ - "arrow", - "arrow-ord", + "arrow 55.1.0", + "arrow-ord 55.1.0", "datafusion-common", "datafusion-doc", "datafusion-execution", @@ -2998,13 +3162,13 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc9a97220736c8fff1446e936be90d57216c06f28969f9ffd3b72ac93c958c8a" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "datafusion-catalog", "datafusion-common", "datafusion-expr", "datafusion-physical-plan", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "paste", ] @@ -3052,7 +3216,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "084d9f979c4b155346d3c34b18f4256e6904ded508e9554d90fed416415c3515" dependencies = [ - "arrow", + "arrow 55.1.0", "chrono", "datafusion-common", "datafusion-expr", @@ -3072,7 +3236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64c536062b0076f4e30084065d805f389f9fe38af0ca75bcbac86bc5e9fbab65" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-expr", "datafusion-expr-common", @@ -3094,7 +3258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8a92b53b3193fac1916a1c5b8e3f4347c526f6822e56b71faa5fb372327a863" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-expr-common", "hashbrown 0.14.5", @@ -3107,7 +3271,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fa0a5ac94c7cf3da97bedabd69d6bbca12aef84b9b37e6e9e8c25286511b5e2" dependencies = [ - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-execution", "datafusion-expr", @@ -3127,9 +3291,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "690c615db468c2e5fe5085b232d8b1c088299a6c63d87fd960a354a71f7acb55" dependencies = [ "ahash 0.8.12", - "arrow", - "arrow-ord", - "arrow-schema", + "arrow 55.1.0", + "arrow-ord 55.1.0", + "arrow-schema 55.1.0", "async-trait", "chrono", "datafusion-common", @@ -3145,7 +3309,7 @@ dependencies = [ "indexmap 2.9.0", "itertools 0.14.0", "log", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project-lite", "tokio", ] @@ -3156,7 +3320,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad229a134c7406c057ece00c8743c0c34b97f4e72f78b475fe17b66c5e14fa4f" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "dashmap 6.1.0", "datafusion-common", @@ -3170,7 +3334,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "tokio", ] @@ -3180,7 +3344,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64f6ab28b72b664c21a27b22a2ff815fd390ed224c26e89a93b5a8154a4e8607" dependencies = [ - "arrow", + "arrow 55.1.0", "bigdecimal", "datafusion-common", "datafusion-expr", @@ -3299,7 +3463,7 @@ dependencies = [ "indexmap 2.9.0", "log", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "serde", "serde_json", "sha2 0.10.9", @@ -3381,7 +3545,7 @@ dependencies = [ "indexmap 2.9.0", "libc", "memoffset", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "percent-encoding", "pin-project", "serde", @@ -3506,7 +3670,7 @@ dependencies = [ "http 1.3.1", "http-body-util", "hyper 1.6.0", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.6", "hyper-util", "ipnet", "percent-encoding", @@ -3626,7 +3790,7 @@ dependencies = [ "log", "once_cell", "os_pipe", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", "rand 0.8.5", "tokio", @@ -4006,7 +4170,7 @@ dependencies = [ "log", "node_resolver", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sys_traits", "thiserror 2.0.12", "url", @@ -4112,7 +4276,7 @@ dependencies = [ "deno_tls", "http-body-util", "hyper 1.6.0", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.6", "hyper-util", "log", "once_cell", @@ -4163,7 +4327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47c618b51088b3ac67f15c69b3ed7620ba3a7d495e5a090186df9424b5ab623e" dependencies = [ "futures", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "tokio", ] @@ -4573,9 +4737,9 @@ dependencies = [ [[package]] name = "dlopen2_derive" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", @@ -4640,6 +4804,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "duckdb" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ac283b6621e3becf8014d1efa655522794075834c72f744573debef9c9f6c8" +dependencies = [ + "arrow 54.3.1", + "cast", + "fallible-iterator 0.3.0", + "fallible-streaming-iterator", + "hashlink 0.9.1", + "libduckdb-sys", + "memchr", + "num-integer", + "rust_decimal", + "smallvec", + "strum 0.25.0", +] + [[package]] name = "dunce" version = "1.0.5" @@ -5300,7 +5483,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.12.3", + "parking_lot 0.12.4", ] [[package]] @@ -5807,7 +5990,7 @@ dependencies = [ "google-cloud-token", "home", "jsonwebtoken 9.3.1", - "reqwest 0.12.15", + "reqwest 0.12.18", "serde", "serde_json", "thiserror 1.0.69", @@ -5850,7 +6033,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d901aeb453fd80e51d64df4ee005014f6cf39f2d736dd64f7239c132d9d39a6a" dependencies = [ - "reqwest 0.12.15", + "reqwest 0.12.18", "thiserror 1.0.69", "tokio", ] @@ -5916,9 +6099,9 @@ dependencies = [ [[package]] name = "gpu-descriptor" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ "bitflags 2.9.1", "gpu-descriptor-types", @@ -6103,9 +6286,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "hex" @@ -6174,7 +6357,7 @@ dependencies = [ "ipconfig", "moka", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.9.0", "resolv-conf", "serde", @@ -6394,11 +6577,10 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" dependencies = [ - "futures-util", "http 1.3.1", "hyper 1.6.0", "hyper-util", @@ -6408,7 +6590,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.2", "tower-service", - "webpki-roots 0.26.11", + "webpki-roots 1.0.0", ] [[package]] @@ -6455,22 +6637,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" +checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", "hyper 1.6.0", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration 0.6.1", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -6796,6 +6984,16 @@ dependencies = [ "serde", ] +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-macro" version = "0.3.7" @@ -6984,7 +7182,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.8.7", + "libloading 0.8.8", "pkg-config", ] @@ -7149,6 +7347,22 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +[[package]] +name = "libduckdb-sys" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cac9d03484c43fefac8b2066a253c9b0b3b0cd02cbe02a9ea2312f7e382618" +dependencies = [ + "autocfg", + "cc", + "flate2", + "pkg-config", + "serde", + "serde_json", + "tar", + "vcpkg", +] + [[package]] name = "libffi" version = "3.2.0" @@ -7180,9 +7394,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", "windows-targets 0.53.0", @@ -7291,9 +7505,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -7742,13 +7956,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -7761,7 +7975,7 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "loom", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "portable-atomic", "rustc_version 0.4.1", "smallvec", @@ -8379,9 +8593,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ "hermit-abi", "libc", @@ -8425,7 +8639,7 @@ dependencies = [ "getrandom 0.2.16", "http 1.3.1", "rand 0.8.5", - "reqwest 0.12.15", + "reqwest 0.12.18", "serde", "serde_json", "serde_path_to_error", @@ -8470,11 +8684,11 @@ dependencies = [ "hyper 1.6.0", "itertools 0.14.0", "md-5 0.10.6", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "percent-encoding", "quick-xml 0.37.5", "rand 0.9.0", - "reqwest 0.12.15", + "reqwest 0.12.18", "ring 0.17.14", "serde", "serde_json", @@ -8532,11 +8746,11 @@ checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea" [[package]] name = "onig" -version = "6.4.0" +version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "libc", "once_cell", "onig_sys", @@ -8544,9 +8758,9 @@ dependencies = [ [[package]] name = "onig_sys" -version = "69.8.1" +version = "69.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" dependencies = [ "cc", "pkg-config", @@ -8602,9 +8816,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.72" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ "bitflags 2.9.1", "cfg-if", @@ -8643,9 +8857,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.108" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -8908,12 +9122,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", + "parking_lot_core 0.9.11", ] [[package]] @@ -8932,9 +9146,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -8950,13 +9164,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be7b2d778f6b841d37083ebdf32e33a524acde1266b5884a8ca29bf00dfa1231" dependencies = [ "ahash 0.8.12", - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-cast 55.1.0", + "arrow-data 55.1.0", "arrow-ipc", - "arrow-schema", - "arrow-select", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", "base64 0.22.1", "brotli 8.0.1", "bytes", @@ -9380,9 +9594,9 @@ checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" [[package]] name = "prettyplease" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" dependencies = [ "proc-macro2", "syn 2.0.101", @@ -9539,7 +9753,7 @@ dependencies = [ "fnv", "lazy_static", "memchr", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "thiserror 2.0.12", ] @@ -9707,7 +9921,7 @@ dependencies = [ "ahash 0.8.12", "equivalent", "hashbrown 0.15.3", - "parking_lot 0.12.3", + "parking_lot 0.12.4", ] [[package]] @@ -10162,9 +10376,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5" dependencies = [ "async-compression", "base64 0.22.1", @@ -10177,7 +10391,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.6.0", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.6", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -10191,26 +10405,24 @@ dependencies = [ "quinn", "rustls 0.23.27", "rustls-native-certs 0.8.1", - "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.2", - "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tokio-rustls 0.26.2", "tokio-util", "tower 0.5.2", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.11", - "windows-registry", + "webpki-roots 1.0.0", ] [[package]] @@ -10222,7 +10434,7 @@ dependencies = [ "anyhow", "async-trait", "http 1.3.1", - "reqwest 0.12.15", + "reqwest 0.12.18", "serde", "thiserror 1.0.69", "tower-service", @@ -10241,7 +10453,7 @@ dependencies = [ "http 1.3.1", "hyper 1.6.0", "parking_lot 0.11.2", - "reqwest 0.12.15", + "reqwest 0.12.18", "reqwest-middleware", "retry-policies", "thiserror 1.0.69", @@ -11003,7 +11215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ "bitflags 2.9.1", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -11492,9 +11704,9 @@ checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -12975,15 +13187,15 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.3", - "parking_lot 0.12.3", + "mio 1.0.4", + "parking_lot 0.12.4", "pin-project-lite", "signal-hook-registry", "socket2", @@ -13047,7 +13259,7 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "percent-encoding", "phf", "pin-project-lite", @@ -13073,7 +13285,7 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "percent-encoding", "phf", "pin-project-lite", @@ -13344,7 +13556,7 @@ dependencies = [ "cookie 0.18.1", "futures-util", "http 1.3.1", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project-lite", "tower-layer", "tower-service", @@ -13360,12 +13572,15 @@ dependencies = [ "bitflags 2.9.1", "bytes", "futures-core", + "futures-util", "http 1.3.1", "http-body 1.0.1", "http-body-util", + "iri-string", "pin-project-lite", "tokio", "tokio-util", + "tower 0.5.2", "tower-layer", "tower-service", "tracing", @@ -13456,7 +13671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3beec919fbdf99d719de8eda6adae3281f8a5b71ae40431f44dc7423053d34" dependencies = [ "loki-api", - "reqwest 0.12.15", + "reqwest 0.12.18", "serde", "serde_json", "snap", @@ -13670,7 +13885,7 @@ checksum = "90b70b37e9074642bc5f60bb23247fd072a84314ca9e71cdf8527593406a0dd3" dependencies = [ "gemm 0.18.2", "half", - "libloading 0.8.7", + "libloading 0.8.8", "memmap2 0.9.5", "num", "num-traits", @@ -13979,9 +14194,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ "getrandom 0.3.3", "js-sys", @@ -14311,7 +14526,7 @@ dependencies = [ "log", "naga", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "profiling", "raw-window-handle", "ron", @@ -14346,14 +14561,14 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.7", + "libloading 0.8.8", "log", "metal", "naga", "ndk-sys", "objc", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "profiling", "range-alloc", "raw-window-handle", @@ -14452,7 +14667,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "axum", @@ -14472,7 +14687,7 @@ dependencies = [ "prometheus", "quote", "rand 0.9.0", - "reqwest 0.12.15", + "reqwest 0.12.18", "rustls 0.23.27", "serde", "serde_json", @@ -14503,7 +14718,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "argon2", @@ -14562,7 +14777,7 @@ dependencies = [ "rand 0.9.0", "rdkafka", "regex", - "reqwest 0.12.15", + "reqwest 0.12.18", "rmcp", "rsa", "rumqttc", @@ -14612,7 +14827,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.492.1" +version = "1.494.0" dependencies = [ "base64 0.22.1", "chrono", @@ -14627,7 +14842,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.492.1" +version = "1.494.0" dependencies = [ "chrono", "serde", @@ -14640,7 +14855,7 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "serde", @@ -14654,7 +14869,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "async-stream", @@ -14696,7 +14911,7 @@ dependencies = [ "quick_cache", "rand 0.9.0", "regex", - "reqwest 0.12.15", + "reqwest 0.12.18", "reqwest-middleware", "reqwest-retry", "semver 1.0.26", @@ -14730,7 +14945,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.492.1" +version = "1.494.0" dependencies = [ "regex", "serde", @@ -14744,7 +14959,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "bytes", @@ -14767,7 +14982,7 @@ dependencies = [ [[package]] name = "windmill-macros" -version = "1.492.1" +version = "1.494.0" dependencies = [ "itertools 0.14.0", "lazy_static", @@ -14779,7 +14994,7 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.492.1" +version = "1.494.0" dependencies = [ "convert_case 0.6.0", "serde", @@ -14788,7 +15003,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "lazy_static", @@ -14800,7 +15015,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "serde_json", @@ -14812,7 +15027,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "gosyn", @@ -14824,7 +15039,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "lazy_static", @@ -14836,7 +15051,7 @@ dependencies = [ [[package]] name = "windmill-parser-java" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "serde_json", @@ -14848,7 +15063,7 @@ dependencies = [ [[package]] name = "windmill-parser-nu" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "nu-parser", @@ -14859,7 +15074,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -14870,7 +15085,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -14881,7 +15096,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "async-recursion", @@ -14904,7 +15119,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -14921,7 +15136,7 @@ dependencies = [ [[package]] name = "windmill-parser-sql" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "lazy_static", @@ -14933,7 +15148,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "lazy_static", @@ -14951,7 +15166,7 @@ dependencies = [ [[package]] name = "windmill-parser-wasm" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "getrandom 0.2.16", @@ -14975,7 +15190,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "serde_json", @@ -14985,7 +15200,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "async-recursion", @@ -15002,7 +15217,7 @@ dependencies = [ "lazy_static", "prometheus", "regex", - "reqwest 0.12.15", + "reqwest 0.12.18", "serde", "serde_json", "serde_urlencoded", @@ -15018,7 +15233,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.492.1" +version = "1.494.0" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -15028,7 +15243,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.492.1" +version = "1.494.0" dependencies = [ "anyhow", "async-recursion", @@ -15056,6 +15271,7 @@ dependencies = [ "deno_web", "deno_webidl", "dotenv", + "duckdb", "dyn-iter", "flume", "futures", @@ -15079,7 +15295,7 @@ dependencies = [ "prometheus", "rand 0.9.0", "regex", - "reqwest 0.12.15", + "reqwest 0.12.18", "reqwest-middleware", "rust_decimal", "serde", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 069aca4367..65c1fa0ec3 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.492.1" +version = "1.494.0" authors.workspace = true edition.workspace = true @@ -32,7 +32,7 @@ members = [ ] [workspace.package] -version = "1.492.1" +version = "1.494.0" authors = ["Ruben Fiszel "] edition = "2021" @@ -87,13 +87,14 @@ python = ["windmill-worker/python", "windmill-api/python"] rust = ["windmill-worker/rust"] mysql = ["windmill-worker/mysql"] oracledb = ["windmill-worker/oracledb"] +duckdb = ["windmill-worker/duckdb"] mssql = ["windmill-worker/mssql"] bigquery = ["windmill-worker/bigquery"] php = ["windmill-worker/php"] csharp = ["windmill-worker/csharp"] nu = ["windmill-worker/nu"] java = ["windmill-worker/java"] -all_languages = [ "python", "deno_core", "rust", "mysql", "oracledb", "mssql", "bigquery", "csharp", "nu", "php", "java"] +all_languages = [ "python", "deno_core", "rust", "mysql", "oracledb", "duckdb", "mssql", "bigquery", "csharp", "nu", "php", "java"] [patch.crates-io] @@ -238,6 +239,7 @@ json-pointer = "^0" itertools = "^0" regex = "^1" semver = "^1" +duckdb = { version = "1.2.2", features = ["bundled"] } v8 = "=130.0.7" # Exact version NOTE: Do not forget to update version and hash in flake.nix deno_fetch = "0.214.0" diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 04b305d5a2..d5d998a701 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -6899b8151329218a1df59964dac57e0e004ae25a \ No newline at end of file +8a2506e86b923c00522cb83b052586f705f7aa8e diff --git a/backend/migrations/20250515084520_duckdb_support.down.sql b/backend/migrations/20250515084520_duckdb_support.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250515084520_duckdb_support.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250515084520_duckdb_support.up.sql b/backend/migrations/20250515084520_duckdb_support.up.sql new file mode 100644 index 0000000000..869fcc07dc --- /dev/null +++ b/backend/migrations/20250515084520_duckdb_support.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'duckdb'; +UPDATE config set config = jsonb_set(config, '{worker_tags}', config->'worker_tags' || '["duckdb"]'::jsonb) where name = 'worker__default' and config @> '{"worker_tags": ["deno", "python3", "go", "bash", "powershell", "dependency", "flow", "hub", "other", "bun", "php", "rust", "ansible", "csharp", "nu", "java"]}'::jsonb AND NOT config->'worker_tags' @> '"duckdb"'::jsonb; diff --git a/backend/parsers/windmill-parser-sql/src/lib.rs b/backend/parsers/windmill-parser-sql/src/lib.rs index 21ebe45f7b..0fe72f0296 100644 --- a/backend/parsers/windmill-parser-sql/src/lib.rs +++ b/backend/parsers/windmill-parser-sql/src/lib.rs @@ -83,6 +83,21 @@ pub fn parse_bigquery_sig(code: &str) -> anyhow::Result { } } +pub fn parse_duckdb_sig(code: &str) -> anyhow::Result { + let parsed = parse_duckdb_file(&code)?; + if let Some(args) = parsed { + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) + } else { + Err(anyhow!("Error parsing sql".to_string())) + } +} + pub fn parse_snowflake_sig(code: &str) -> anyhow::Result { let parsed = parse_snowflake_file(&code)?; if let Some(x) = parsed { @@ -212,6 +227,9 @@ lazy_static::lazy_static! { // -- @name (type) = default static ref RE_ARG_BIGQUERY: Regex = Regex::new(r#"(?m)^-- @(\w+) \((\w+(?:\[\])?)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); + // -- $name (type) = default + static ref RE_ARG_DUCKDB: Regex = Regex::new(r#"(?m)^-- \$(\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); + static ref RE_ARG_SNOWFLAKE: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); @@ -577,6 +595,35 @@ fn parse_bigquery_file(code: &str) -> anyhow::Result>> { Ok(Some(args)) } +fn parse_duckdb_file(code: &str) -> anyhow::Result>> { + let mut args: Vec = vec![]; + + for cap in RE_ARG_DUCKDB.captures_iter(code) { + let name = cap.get(1).map(|x| x.as_str().to_string()).unwrap(); + let typ = cap + .get(2) + .map(|x| x.as_str().to_string().to_lowercase()) + .unwrap(); + let default = cap.get(3).map(|x| x.as_str().to_string()); + let has_default = default.is_some(); + let parsed_typ = parse_duckdb_typ(typ.as_str()); + + let parsed_default = default.and_then(|x| parsed_default(&parsed_typ, x)); + + args.push(Arg { + name, + typ: parsed_typ, + default: parsed_default, + otyp: Some(typ), + has_default, + oidx: None, + }); + } + + args.append(&mut parse_sql_sanitized_interpolation(code)); + Ok(Some(args)) +} + fn parse_snowflake_file(code: &str) -> anyhow::Result>> { let mut args: Vec = vec![]; @@ -729,6 +776,33 @@ pub fn parse_bigquery_typ(typ: &str) -> Typ { } } +pub fn parse_duckdb_typ(typ: &str) -> Typ { + if typ.ends_with("[]") { + let base_typ = parse_duckdb_typ(typ.strip_suffix("[]").unwrap()); + Typ::List(Box::new(base_typ)) + } else { + match typ { + "varchar" | "char" | "bpchar" | "text" | "string" => Typ::Str(None), + "blob" | "bytea" | "binary" | "varbinary" | "bitstring" => Typ::Bytes, + "boolean" | "bool" | "bit" | "logical" => Typ::Bool, + "bigint" | "int8" | "long" | "integer" | "int4" | "int" | "smallint" | "int2" + | "short" | "tinyint" | "int1" | "signed" | "ubigint" | "uhugeint" | "uinteger" + | "usmallint" | "utinyint" => Typ::Int, + "decimal" | "numeric" | "double" | "float8" | "float" | "float4" | "real" => Typ::Float, + "date" + | "time" + | "timestamp with time zone" + | "timestamptz" + | "timestamp" + | "datetime" => Typ::Datetime, + "uuid" | "json" => Typ::Str(None), + "interval" | "hugeint" => Typ::Str(None), + "s3object" => Typ::Resource("S3Object".to_string()), + _ => Typ::Str(None), + } + } +} + pub fn parse_snowflake_typ(typ: &str) -> Typ { match typ { "varchar" => Typ::Str(None), diff --git a/backend/parsers/windmill-parser-wasm/src/lib.rs b/backend/parsers/windmill-parser-wasm/src/lib.rs index cd280e7af5..4270c28c60 100644 --- a/backend/parsers/windmill-parser-wasm/src/lib.rs +++ b/backend/parsers/windmill-parser-wasm/src/lib.rs @@ -96,6 +96,12 @@ pub fn parse_oracledb(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_oracledb_sig(code)) } +#[cfg(feature = "sql-parser")] +#[wasm_bindgen] +pub fn parse_duckdb(code: &str) -> String { + wrap_sig(windmill_parser_sql::parse_duckdb_sig(code)) +} + #[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_bigquery(code: &str) -> String { diff --git a/backend/windmill-api/openapi-deref.json b/backend/windmill-api/openapi-deref.json index 91214e99b4..1186be6069 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.423.2", + "version": "1.492.1", "title": "Windmill API", "contact": { "name": "Windmill Team", @@ -197,6 +197,14 @@ }, { "$ref": "#/components/parameters/ActionKind" + }, + { + "name": "all_workspaces", + "in": "query", + "description": "get audit logs for all workspaces", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -618,6 +626,9 @@ "is_super_admin": { "type": "boolean" }, + "is_devops": { + "type": "boolean" + }, "name": { "type": "string" } @@ -873,6 +884,27 @@ } } }, + "/github_app/connected_repositories": { + "get": { + "summary": "get connected repositories", + "operationId": "getGlobalConnectedRepositories", + "tags": [ + "git_sync" + ], + "responses": { + "200": { + "description": "connected repositories", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubInstallations" + } + } + } + } + } + } + }, "/workspaces/list": { "get": { "summary": "list all workspaces visible to me", @@ -1329,9 +1361,24 @@ "content": { "application/json": { "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CriticalAlert" + "type": "object", + "properties": { + "alerts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CriticalAlert" + } + }, + "total_rows": { + "type": "integer", + "description": "Total number of rows matching the query.", + "example": 100 + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages based on the page size.", + "example": 10 + } } } } @@ -1670,9 +1717,19 @@ "tags": [ "user" ], + "parameters": [ + { + "name": "if_expiring_in_less_than_s", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ], "responses": { "200": { - "description": "free usage", + "description": "new token", "content": { "text/plain": { "schema": { @@ -1910,6 +1967,220 @@ } } }, + "/w/{workspace}/github_app/token": { + "post": { + "summary": "get github app token", + "operationId": "getGithubAppToken", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "jwt job token", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "job_token": { + "type": "string" + } + }, + "required": [ + "job_token" + ] + } + } + } + }, + "responses": { + "200": { + "description": "github app token", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "token": { + "type": "string" + } + }, + "required": [ + "token" + ] + } + } + } + } + } + } + }, + "/w/{workspace}/github_app/install_from_workspace": { + "post": { + "tags": [ + "Git Sync" + ], + "summary": "Install a GitHub installation from another workspace", + "operationId": "installFromWorkspace", + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "source_workspace_id": { + "type": "string", + "description": "The ID of the workspace containing the installation to copy" + }, + "installation_id": { + "type": "number", + "description": "The ID of the GitHub installation to copy" + } + }, + "required": [ + "source_workspace_id", + "installation_id" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Installation successfully copied" + } + } + } + }, + "/w/{workspace}/github_app/installation/{installation_id}": { + "delete": { + "summary": "Delete a GitHub installation from a workspace", + "operationId": "deleteFromWorkspace", + "description": "Removes a GitHub installation from the specified workspace. Requires admin privileges.", + "tags": [ + "Git Sync" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "installation_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "description": "The ID of the GitHub installation to delete" + } + ], + "responses": { + "200": { + "description": "Installation successfully deleted" + } + } + } + }, + "/w/{workspace}/github_app/export/{installationId}": { + "get": { + "summary": "Export GitHub installation JWT token", + "description": "Exports the JWT token for a specific GitHub installation in the workspace", + "operationId": "exportInstallation", + "tags": [ + "Git Sync" + ], + "parameters": [ + { + "name": "workspace", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "installationId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Successfully exported the JWT token", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "jwt_token": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/w/{workspace}/github_app/import": { + "post": { + "summary": "Import GitHub installation from JWT token", + "description": "Imports a GitHub installation from a JWT token exported from another instance", + "operationId": "importInstallation", + "tags": [ + "Git Sync" + ], + "parameters": [ + { + "name": "workspace", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "jwt_token" + ], + "properties": { + "jwt_token": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Successfully imported the installation" + } + } + } + }, "/users/accept_invite": { "post": { "summary": "accept invite to workspace", @@ -2374,6 +2645,46 @@ } } }, + "/w/{workspace}/workspaces/change_workspace_color": { + "post": { + "summary": "change workspace id", + "operationId": "changeWorkspaceColor", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "color": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "status", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/w/{workspace}/users/whois/{username}": { "get": { "summary": "whois", @@ -2408,6 +2719,43 @@ } } }, + "/w/{workspace}/workspaces/operator_settings": { + "post": { + "operationId": "updateOperatorSettings", + "summary": "Update operator settings for a workspace", + "description": "Updates the operator settings for a specific workspace. Requires workspace admin privileges.", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperatorSettings" + } + } + } + }, + "responses": { + "200": { + "description": "Operator settings updated successfully", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/users/exists/{email}": { "get": { "summary": "exists email", @@ -2540,6 +2888,15 @@ "slack_command_script": { "type": "string" }, + "teams_team_id": { + "type": "string" + }, + "teams_command_script": { + "type": "string" + }, + "teams_team_name": { + "type": "string" + }, "auto_invite_domain": { "type": "string" }, @@ -2552,9 +2909,6 @@ "plan": { "type": "string" }, - "automatic_billing": { - "type": "boolean" - }, "customer_id": { "type": "string" }, @@ -2564,11 +2918,8 @@ "deploy_to": { "type": "string" }, - "ai_resource": { - "$ref": "#/components/schemas/AiResource" - }, - "code_completion_enabled": { - "type": "boolean" + "ai_config": { + "$ref": "#/components/schemas/AIConfig" }, "error_handler": { "type": "string" @@ -2593,11 +2944,18 @@ }, "default_scripts": { "$ref": "#/components/schemas/WorkspaceDefaultScripts" + }, + "mute_critical_alerts": { + "type": "boolean" + }, + "color": { + "type": "string" + }, + "operator_settings": { + "$ref": "#/components/schemas/OperatorSettings" } }, "required": [ - "code_completion_enabled", - "automatic_billing", "error_handler_muted_on_cancel" ] } @@ -2690,16 +3048,16 @@ "usage": { "type": "number" }, - "seats": { - "type": "number" + "owner": { + "type": "string" }, - "automatic_billing": { - "type": "boolean" + "status": { + "type": "string" } }, "required": [ "premium", - "automatic_billing" + "owner" ] } } @@ -2708,10 +3066,43 @@ } } }, - "/w/{workspace}/workspaces/set_automatic_billing": { + "/w/{workspace}/workspaces/threshold_alert": { + "get": { + "summary": "get threshold alert info", + "operationId": "getThresholdAlert", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "responses": { + "200": { + "description": "status", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "threshold_alert_amount": { + "type": "number" + }, + "last_alert_sent": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + } + }, "post": { - "summary": "set automatic billing", - "operationId": "setAutomaticBilling", + "summary": "set threshold alert info", + "operationId": "setThresholdAlert", "tags": [ "workspace" ], @@ -2721,23 +3112,17 @@ } ], "requestBody": { - "description": "automatic billing", + "description": "threshold alert info", "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { - "automatic_billing": { - "type": "boolean" - }, - "seats": { + "threshold_alert_amount": { "type": "number" } - }, - "required": [ - "automatic_billing" - ] + } } } } @@ -2798,6 +3183,173 @@ } } }, + "/w/{workspace}/workspaces/edit_teams_command": { + "post": { + "summary": "edit teams command", + "operationId": "editTeamsCommand", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "WorkspaceInvite", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "slack_command_script": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "status", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/workspaces/available_teams_ids": { + "get": { + "summary": "list available teams ids", + "operationId": "listAvailableTeamsIds", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "responses": { + "200": { + "description": "status", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "team_name": { + "type": "string" + }, + "team_id": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "/w/{workspace}/workspaces/available_teams_channels": { + "get": { + "summary": "list available teams channels", + "operationId": "listAvailableTeamsChannels", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "responses": { + "200": { + "description": "status", + "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" + } + } + } + } + } + } + } + } + } + }, + "/w/{workspace}/workspaces/connect_teams": { + "post": { + "summary": "connect teams", + "operationId": "connectTeams", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "connect teams", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string" + }, + "team_name": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "status", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/w/{workspace}/workspaces/run_slack_message_test_job": { "post": { "summary": "run a job that sends a message to Slack", @@ -2851,6 +3403,59 @@ } } }, + "/w/{workspace}/workspaces/run_teams_message_test_job": { + "post": { + "summary": "run a job that sends a message to Teams", + "operationId": "runTeamsMessageTestJob", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "path to hub script to run and its corresponding args", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hub_script_path": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "test_msg": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "status", + "content": { + "text/json": { + "schema": { + "type": "object", + "properties": { + "job_uuid": { + "type": "string" + } + } + } + } + } + } + } + } + }, "/w/{workspace}/workspaces/edit_deploy_to": { "post": { "summary": "edit deploy to", @@ -3000,18 +3605,7 @@ "content": { "application/json": { "schema": { - "type": "object", - "required": [ - "code_completion_enabled" - ], - "properties": { - "ai_resource": { - "$ref": "#/components/schemas/AiResource" - }, - "code_completion_enabled": { - "type": "boolean" - } - } + "$ref": "#/components/schemas/AIConfig" } } } @@ -3046,25 +3640,9 @@ "200": { "description": "status", "content": { - "text/plain": { + "application/json": { "schema": { - "type": "object", - "properties": { - "ai_provider": { - "type": "string" - }, - "exists_ai_resource": { - "type": "boolean" - }, - "code_completion_enabled": { - "type": "boolean" - } - }, - "required": [ - "ai_provider", - "exists_ai_resource", - "code_completion_enabled" - ] + "$ref": "#/components/schemas/AIConfig" } } } @@ -3578,11 +4156,35 @@ }, "websocket_used": { "type": "boolean" + }, + "kafka_used": { + "type": "boolean" + }, + "nats_used": { + "type": "boolean" + }, + "postgres_used": { + "type": "boolean" + }, + "mqtt_used": { + "type": "boolean" + }, + "gcp_used": { + "type": "boolean" + }, + "sqs_used": { + "type": "boolean" } }, "required": [ "http_routes_used", - "websocket_used" + "websocket_used", + "kafka_used", + "nats_used", + "postgres_used", + "mqtt_used", + "gcp_used", + "sqs_used" ] } } @@ -4211,6 +4813,186 @@ } } }, + "/w/{workspace}/workspaces/critical_alerts": { + "get": { + "summary": "Get all critical alerts for this workspace", + "operationId": "workspaceGetCriticalAlerts", + "tags": [ + "setting" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "in": "query", + "name": "page", + "schema": { + "type": "integer", + "default": 1, + "description": "The page number to retrieve (minimum value is 1)" + } + }, + { + "in": "query", + "name": "page_size", + "schema": { + "type": "integer", + "default": 10, + "maximum": 100, + "description": "Number of alerts per page (maximum is 100)" + } + }, + { + "in": "query", + "name": "acknowledged", + "schema": { + "type": "boolean", + "nullable": true, + "description": "Filter by acknowledgment status; true for acknowledged, false for unacknowledged, and omit for all alerts" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved all critical alerts", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "alerts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CriticalAlert" + } + }, + "total_rows": { + "type": "integer", + "description": "Total number of rows matching the query.", + "example": 100 + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages based on the page size.", + "example": 10 + } + } + } + } + } + } + } + } + }, + "/w/{workspace}/workspaces/critical_alerts/{id}/acknowledge": { + "post": { + "summary": "Acknowledge a critical alert for this workspace", + "operationId": "workspaceAcknowledgeCriticalAlert", + "tags": [ + "setting" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "integer" + }, + "description": "The ID of the critical alert to acknowledge" + } + ], + "responses": { + "200": { + "description": "Successfully acknowledged the critical alert", + "content": { + "application/json": { + "schema": { + "type": "string", + "example": "Critical alert acknowledged" + } + } + } + } + } + } + }, + "/w/{workspace}/workspaces/critical_alerts/acknowledge_all": { + "post": { + "summary": "Acknowledge all unacknowledged critical alerts for this workspace", + "operationId": "workspaceAcknowledgeAllCriticalAlerts", + "tags": [ + "setting" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "responses": { + "200": { + "description": "Successfully acknowledged all unacknowledged critical alerts.", + "content": { + "application/json": { + "schema": { + "type": "string", + "example": "All unacknowledged critical alerts acknowledged" + } + } + } + } + } + } + }, + "/w/{workspace}/workspaces/critical_alerts/mute": { + "post": { + "summary": "Mute critical alert UI for this workspace", + "operationId": "workspaceMuteCriticalAlertsUI", + "tags": [ + "setting" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "Boolean flag to mute critical alerts.", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "mute_critical_alerts": { + "type": "boolean", + "description": "Whether critical alerts should be muted.", + "example": true + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Successfully updated mute critical alert settings.", + "content": { + "application/json": { + "schema": { + "type": "string", + "example": "Updated mute critical alert UI settings for workspace: workspace_id" + } + } + } + } + } + } + }, "/oauth/login_callback/{client_name}": { "post": { "security": [], @@ -4562,6 +5344,32 @@ } } }, + "/w/{workspace}/oauth/disconnect_teams": { + "post": { + "summary": "disconnect teams", + "operationId": "disconnectTeams", + "tags": [ + "oauth" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "responses": { + "200": { + "description": "disconnected teams", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/oauth/list_logins": { "get": { "summary": "list oauth logins", @@ -4675,6 +5483,78 @@ } } }, + "/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", + "description": "Respond to a Microsoft Teams activity after a workspace command is run", + "operationId": "sendMessageToConversation", + "tags": [ + "teams" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "conversation_id", + "text" + ], + "properties": { + "conversation_id": { + "type": "string", + "description": "The ID of the Teams conversation/activity" + }, + "success": { + "type": "boolean", + "description": "Used for styling the card conditionally", + "default": true + }, + "text": { + "type": "string", + "description": "The message text to be sent in the Teams card" + }, + "card_block": { + "type": "object", + "description": "The card block to be sent in the Teams card" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Activity processed successfully" + } + } + } + }, "/w/{workspace}/resources/create": { "post": { "summary": "create resource", @@ -5637,6 +6517,44 @@ } } }, + "/apps_u/public_app_by_custom_path/{custom_path}": { + "get": { + "summary": "get public app by custom path", + "operationId": "getPublicAppByCustomPath", + "tags": [ + "app" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomPath" + } + ], + "responses": { + "200": { + "description": "app details", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AppWithLastVersion" + }, + { + "type": "object", + "properties": { + "workspace_id": { + "type": "string" + } + } + } + ] + } + } + } + } + } + } + }, "/scripts/hub/get/{path}": { "get": { "summary": "get hub script content by path", @@ -5986,7 +6904,7 @@ }, { "name": "last_parent_hash", - "description": "mask to filter scripts whom last parent in the chain has exact hash. \nBeware that each script stores only a limited number of parents. Hence\nthe last parent hash for a script is not necessarily its top-most parent.\nTo find the top-most parent you will have to jump from last to last hash\n until finding the parent\n", + "description": "mask to filter scripts whom last parent in the chain has exact hash.\nBeware that each script stores only a limited number of parents. Hence\nthe last parent hash for a script is not necessarily its top-most parent.\nTo find the top-most parent you will have to jump from last to last hash\n until finding the parent\n", "in": "query", "schema": { "type": "string" @@ -6002,7 +6920,7 @@ }, { "name": "show_archived", - "description": "(default false)\nshow only the archived files.\nwhen multiple archived hash share the same path, only the ones with the latest create_at\nare \ned.\n", + "description": "(default false)\nshow only the archived files.\nwhen multiple archived hash share the same path, only the ones with the latest create_at\nare\ned.\n", "in": "query", "schema": { "type": "boolean" @@ -6289,6 +7207,24 @@ "tags": [ "worker" ], + "parameters": [ + { + "name": "workspace", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "show_workspace_restriction", + "in": "query", + "schema": { + "type": "boolean" + }, + "required": false + } + ], "responses": { "200": { "description": "list of custom tags", @@ -6440,7 +7376,7 @@ }, "/w/{workspace}/scripts/delete/p/{path}": { "post": { - "summary": "delete all scripts at a given path (require admin)", + "summary": "delete script at a given path (require admin)", "operationId": "deleteScriptByPath", "tags": [ "script" @@ -6451,6 +7387,14 @@ }, { "$ref": "#/components/parameters/ScriptPath" + }, + { + "name": "keep_captures", + "description": "keep captures", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -6625,6 +7569,38 @@ } } }, + "/w/{workspace}/scripts/list_paths_from_workspace_runnable/{path}": { + "get": { + "summary": "list script paths using provided script as a relative import", + "operationId": "listScriptPathsFromWorkspaceRunnable", + "tags": [ + "script" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "responses": { + "200": { + "description": "list of script paths", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, "/w/{workspace}/scripts/get_latest_version/{path}": { "get": { "summary": "get scripts's latest version (hash)", @@ -6645,7 +7621,6 @@ "description": "Script version/hash", "content": { "application/json": { - "required": false, "schema": { "$ref": "#/components/schemas/ScriptHistory" } @@ -6895,6 +7870,96 @@ } } }, + "/w/{workspace}/jobs/list_selected_job_groups": { + "post": { + "summary": "list selected jobs script/flow schemas grouped by (kind, path)", + "operationId": "listSelectedJobGroups", + "tags": [ + "job" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "script args", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + } + }, + "responses": { + "200": { + "description": "result", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "script", + "flow" + ] + }, + "script_path": { + "type": "string" + }, + "latest_schema": { + "type": "object" + }, + "schemas": { + "type": "array", + "items": { + "type": "object", + "properties": { + "schema": { + "type": "object" + }, + "script_hash": { + "type": "string" + }, + "job_ids": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "schema", + "script_hash", + "job_ids" + ] + } + } + }, + "required": [ + "kind", + "script_path", + "latest_schema", + "schemas" + ] + } + } + } + } + } + } + } + }, "/w/{workspace}/jobs/run/p/{path}": { "post": { "summary": "run script by path", @@ -7491,7 +8556,6 @@ "description": "Flow version", "content": { "application/json": { - "required": false, "schema": { "$ref": "#/components/schemas/FlowVersion" } @@ -7501,6 +8565,41 @@ } } }, + "/w/{workspace}/flows/list_paths_from_workspace_runnable/{runnable_kind}/{path}": { + "get": { + "summary": "list flow paths from workspace runnable", + "operationId": "listFlowPathsFromWorkspaceRunnable", + "tags": [ + "flow" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/RunnableKind" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "responses": { + "200": { + "description": "list of flow paths", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, "/w/{workspace}/flows/get/v/{version}/p/{path}": { "get": { "summary": "get flow version", @@ -7510,7 +8609,6 @@ "$ref": "#/components/parameters/WorkspaceId" }, { - "type": "string", "name": "version", "in": "path", "required": true, @@ -7548,7 +8646,6 @@ "$ref": "#/components/parameters/WorkspaceId" }, { - "type": "string", "name": "version", "in": "path", "required": true, @@ -7632,6 +8729,40 @@ } } }, + "/w/{workspace}/flows/deployment_status/p/{path}": { + "get": { + "summary": "get flow deployment status", + "operationId": "getFlowDeploymentStatus", + "tags": [ + "flow" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "responses": { + "200": { + "description": "flow status", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "lock_error_logs": { + "type": "string" + } + } + } + } + } + } + } + } + }, "/w/{workspace}/flows/get_triggers_count/{path}": { "get": { "summary": "get triggers count of flow", @@ -7970,6 +9101,14 @@ }, { "$ref": "#/components/parameters/ScriptPath" + }, + { + "name": "keep_captures", + "description": "keep captures", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -8267,6 +9406,9 @@ }, "deployment_message": { "type": "string" + }, + "custom_path": { + "type": "string" } }, "required": [ @@ -8293,6 +9435,81 @@ } } }, + "/w/{workspace}/apps/create_raw": { + "post": { + "summary": "create app raw", + "operationId": "createAppRaw", + "tags": [ + "app" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "new app", + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "app": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "value": {}, + "summary": { + "type": "string" + }, + "policy": { + "$ref": "#/components/schemas/Policy" + }, + "draft_only": { + "type": "boolean" + }, + "deployment_message": { + "type": "string" + }, + "custom_path": { + "type": "string" + } + }, + "required": [ + "path", + "value", + "summary", + "policy" + ] + }, + "js": { + "type": "string" + }, + "css": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "app created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/w/{workspace}/apps/exists/{path}": { "get": { "summary": "does an app exisst at path", @@ -8358,6 +9575,35 @@ } } }, + "/w/{workspace}/apps/get/lite/{path}": { + "get": { + "summary": "get app lite by path", + "operationId": "getAppLiteByPath", + "tags": [ + "app" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "responses": { + "200": { + "description": "app lite details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppWithLastVersion" + } + } + } + } + } + } + }, "/w/{workspace}/apps/get/draft/{path}": { "get": { "summary": "get app by path with draft", @@ -8439,7 +9685,6 @@ "description": "App version", "content": { "application/json": { - "required": false, "schema": { "$ref": "#/components/schemas/AppHistory" } @@ -8449,6 +9694,41 @@ } } }, + "/w/{workspace}/apps/list_paths_from_workspace_runnable/{runnable_kind}/{path}": { + "get": { + "summary": "list app paths from workspace runnable", + "operationId": "listAppPathsFromWorkspaceRunnable", + "tags": [ + "app" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/RunnableKind" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "responses": { + "200": { + "description": "list of app paths", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, "/w/{workspace}/apps/history_update/a/{id}/v/{version}": { "post": { "summary": "update app history", @@ -8808,6 +10088,9 @@ }, "deployment_message": { "type": "string" + }, + "custom_path": { + "type": "string" } } } @@ -8828,6 +10111,155 @@ } } }, + "/w/{workspace}/apps/update_raw/{path}": { + "post": { + "summary": "update app", + "operationId": "updateAppRaw", + "tags": [ + "app" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "requestBody": { + "description": "update app", + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "app": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "value": {}, + "policy": { + "$ref": "#/components/schemas/Policy" + }, + "deployment_message": { + "type": "string" + }, + "custom_path": { + "type": "string" + } + } + }, + "js": { + "type": "string" + }, + "css": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "app updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/apps/custom_path_exists/{custom_path}": { + "get": { + "summary": "check if custom path exists", + "operationId": "customPathExists", + "tags": [ + "app" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/CustomPath" + } + ], + "responses": { + "200": { + "description": "custom path exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/apps/sign_s3_objects": { + "post": { + "summary": "sign s3 objects, to be used by anonymous users in public apps", + "operationId": "signS3Objects", + "tags": [ + "app" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "s3 objects to sign", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "s3_objects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/S3Object" + } + } + }, + "required": [ + "s3_objects" + ] + } + } + } + }, + "responses": { + "200": { + "description": "signed s3 objects", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/S3Object" + } + } + } + } + } + } + } + }, "/w/{workspace}/apps_u/execute_component/{path}": { "post": { "summary": "executeComponent", @@ -8857,6 +10289,9 @@ "path": { "type": "string" }, + "version": { + "type": "integer" + }, "args": {}, "raw_code": { "type": "object", @@ -8882,6 +10317,9 @@ "language" ] }, + "id": { + "type": "integer" + }, "force_viewer_static_fields": { "type": "object" }, @@ -8917,6 +10355,146 @@ } } }, + "/w/{workspace}/apps_u/upload_s3_file/{path}": { + "post": { + "summary": "upload s3 file from app", + "operationId": "uploadS3FileFromApp", + "tags": [ + "app" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + }, + { + "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 uploaded", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "file_key": { + "type": "string" + }, + "delete_token": { + "type": "string" + } + }, + "required": [ + "file_key", + "delete_token" + ] + } + } + } + } + } + } + }, + "/w/{workspace}/apps_u/delete_s3_file": { + "delete": { + "summary": "delete s3 file from app", + "operationId": "deleteS3FileFromApp", + "tags": [ + "app" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "delete_token", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "file deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/w/{workspace}/jobs/run/f/{path}": { "post": { "summary": "run flow by path", @@ -9003,6 +10581,90 @@ } } }, + "/w/{workspace}/jobs/run/batch_rerun_jobs": { + "post": { + "summary": "re-run multiple jobs", + "operationId": "batchReRunJobs", + "tags": [ + "job" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "list of job ids to re run and arg tranforms", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "job_ids", + "script_options_by_path", + "flow_options_by_path" + ], + "properties": { + "job_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "script_options_by_path": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "input_transforms": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/InputTransform" + } + }, + "use_latest_version": { + "type": "boolean" + } + } + } + }, + "flow_options_by_path": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "input_transforms": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/InputTransform" + } + }, + "use_latest_version": { + "type": "boolean" + } + } + } + } + } + } + } + } + }, + "responses": { + "201": { + "description": "stream of created job uuids separated by \\n. Lines may start with 'Error:'", + "content": { + "text/event-stream": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/w/{workspace}/jobs/restart/f/{id}/from/{step_id}/{branch_or_iteration_n}": { "post": { "summary": "restart a completed flow at a given step", @@ -9426,6 +11088,9 @@ { "$ref": "#/components/parameters/ParentJob" }, + { + "$ref": "#/components/parameters/Worker" + }, { "$ref": "#/components/parameters/ScriptExactPath" }, @@ -9465,6 +11130,9 @@ { "$ref": "#/components/parameters/ResultFilter" }, + { + "$ref": "#/components/parameters/AllowWildcards" + }, { "$ref": "#/components/parameters/Tag" }, @@ -9587,10 +11255,213 @@ } } }, - "/w/{workspace}/jobs/queue/list_filtered_uuids": { + "/w/{workspace}/jobs/completed/count_jobs": { + "get": { + "summary": "count number of completed jobs with filter", + "operationId": "countCompletedJobs", + "tags": [ + "job" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "completed_after_s_ago", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "success", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "tags", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "all_workspaces", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Count of completed jobs", + "content": { + "application/json": { + "schema": { + "type": "integer" + } + } + } + } + } + } + }, + "/w/{workspace}/jobs/list_filtered_uuids": { "get": { "summary": "get the ids of all jobs matching the given filters", - "operationId": "listFilteredUuids", + "operationId": "listFilteredJobsUuids", + "tags": [ + "job" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/CreatedBy" + }, + { + "$ref": "#/components/parameters/Label" + }, + { + "$ref": "#/components/parameters/Worker" + }, + { + "$ref": "#/components/parameters/ParentJob" + }, + { + "$ref": "#/components/parameters/ScriptExactPath" + }, + { + "$ref": "#/components/parameters/ScriptStartPath" + }, + { + "$ref": "#/components/parameters/SchedulePath" + }, + { + "$ref": "#/components/parameters/ScriptExactHash" + }, + { + "$ref": "#/components/parameters/StartedBefore" + }, + { + "$ref": "#/components/parameters/StartedAfter" + }, + { + "$ref": "#/components/parameters/CreatedBefore" + }, + { + "$ref": "#/components/parameters/CreatedAfter" + }, + { + "$ref": "#/components/parameters/CreatedOrStartedBefore" + }, + { + "$ref": "#/components/parameters/Running" + }, + { + "$ref": "#/components/parameters/ScheduledForBeforeNow" + }, + { + "$ref": "#/components/parameters/CreatedOrStartedAfter" + }, + { + "$ref": "#/components/parameters/CreatedOrStartedAfterCompletedJob" + }, + { + "$ref": "#/components/parameters/JobKinds" + }, + { + "$ref": "#/components/parameters/Suspended" + }, + { + "$ref": "#/components/parameters/ArgsFilter" + }, + { + "$ref": "#/components/parameters/Tag" + }, + { + "$ref": "#/components/parameters/ResultFilter" + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/PerPage" + }, + { + "name": "is_skipped", + "description": "is the job skipped", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "is_flow_step", + "description": "is the job a flow step", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "has_null_parent", + "description": "has null parent", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "success", + "description": "filter on successful jobs", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "all_workspaces", + "description": "get jobs from all workspaces (only valid if request come from the `admins` workspace)", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "is_not_schedule", + "description": "is not a scheduled job", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "uuids of jobs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "/w/{workspace}/jobs/queue/list_filtered_uuids": { + "get": { + "summary": "get the ids of all queued jobs matching the given filters", + "operationId": "listFilteredQueueUuids", "tags": [ "job" ], @@ -9646,6 +11517,9 @@ { "$ref": "#/components/parameters/ResultFilter" }, + { + "$ref": "#/components/parameters/AllowWildcards" + }, { "$ref": "#/components/parameters/Tag" }, @@ -9760,6 +11634,9 @@ { "$ref": "#/components/parameters/Label" }, + { + "$ref": "#/components/parameters/Worker" + }, { "$ref": "#/components/parameters/ParentJob" }, @@ -9793,6 +11670,9 @@ { "$ref": "#/components/parameters/ResultFilter" }, + { + "$ref": "#/components/parameters/AllowWildcards" + }, { "$ref": "#/components/parameters/Tag" }, @@ -9869,6 +11749,9 @@ { "$ref": "#/components/parameters/Label" }, + { + "$ref": "#/components/parameters/Worker" + }, { "$ref": "#/components/parameters/ParentJob" }, @@ -9926,6 +11809,9 @@ { "$ref": "#/components/parameters/ResultFilter" }, + { + "$ref": "#/components/parameters/AllowWildcards" + }, { "$ref": "#/components/parameters/Page" }, @@ -10294,7 +12180,9 @@ "description": "job log", "content": { "text/plain": { - "type": "string" + "schema": { + "type": "string" + } } } } @@ -10728,6 +12616,158 @@ } } }, + "/w/{workspace}/jobs/slack_approval/{id}": { + "get": { + "summary": "generate interactive slack approval for suspended job", + "operationId": "getSlackApprovalPayload", + "tags": [ + "job" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/JobId" + }, + { + "name": "approver", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "message", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "slack_resource_path", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "channel_id", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "flow_step_id", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "default_args_json", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "dynamic_enums_json", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Interactive slack approval message sent successfully" + } + } + } + }, + "/w/{workspace}/jobs/teams_approval/{id}": { + "get": { + "summary": "generate interactive teams approval for suspended job", + "operationId": "getTeamsApprovalPayload", + "tags": [ + "job" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/JobId" + }, + { + "name": "approver", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "message", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "team_name", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "channel_name", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "flow_step_id", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "default_args_json", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "dynamic_enums_json", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Interactive slack approval message sent successfully" + } + } + } + }, "/w/{workspace}/jobs_u/resume/{id}/{resume_id}/{signature}": { "get": { "summary": "resume a job for a suspended flow", @@ -11172,6 +13212,9 @@ }, "timezone": { "type": "string" + }, + "cron_version": { + "type": "string" } }, "required": [ @@ -11823,10 +13866,15 @@ "delete", "patch" ] + }, + "trigger_path": { + "type": "string" + }, + "workspaced_route": { + "type": "boolean" } }, "required": [ - "kind", "route_path", "http_method" ] @@ -12118,6 +14166,2452 @@ } } }, + "/w/{workspace}/websocket_triggers/test": { + "post": { + "summary": "test websocket connection", + "operationId": "testWebsocketConnection", + "tags": [ + "websocket_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "test websocket connection", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "url_runnable_args": { + "$ref": "#/components/schemas/ScriptArgs" + }, + "can_return_message": { + "type": "boolean" + } + }, + "required": [ + "url", + "can_return_message" + ] + } + } + } + }, + "responses": { + "200": { + "description": "successfuly connected to websocket", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/kafka_triggers/create": { + "post": { + "summary": "create kafka trigger", + "operationId": "createKafkaTrigger", + "tags": [ + "kafka_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "new kafka trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewKafkaTrigger" + } + } + } + }, + "responses": { + "201": { + "description": "kafka trigger created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/kafka_triggers/update/{path}": { + "post": { + "summary": "update kafka trigger", + "operationId": "updateKafkaTrigger", + "tags": [ + "kafka_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditKafkaTrigger" + } + } + } + }, + "responses": { + "200": { + "description": "kafka trigger updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/kafka_triggers/delete/{path}": { + "delete": { + "summary": "delete kafka trigger", + "operationId": "deleteKafkaTrigger", + "tags": [ + "kafka_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "kafka trigger deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/kafka_triggers/get/{path}": { + "get": { + "summary": "get kafka trigger", + "operationId": "getKafkaTrigger", + "tags": [ + "kafka_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "kafka trigger deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KafkaTrigger" + } + } + } + } + } + } + }, + "/w/{workspace}/kafka_triggers/list": { + "get": { + "summary": "list kafka triggers", + "operationId": "listKafkaTriggers", + "tags": [ + "kafka_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": "kafka trigger list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/KafkaTrigger" + } + } + } + } + } + } + } + }, + "/w/{workspace}/kafka_triggers/exists/{path}": { + "get": { + "summary": "does kafka trigger exists", + "operationId": "existsKafkaTrigger", + "tags": [ + "kafka_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "kafka trigger exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/kafka_triggers/setenabled/{path}": { + "post": { + "summary": "set enabled kafka trigger", + "operationId": "setKafkaTriggerEnabled", + "tags": [ + "kafka_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated kafka trigger enable", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ] + } + } + } + }, + "responses": { + "200": { + "description": "kafka trigger enabled set", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/kafka_triggers/test": { + "post": { + "summary": "test kafka connection", + "operationId": "testKafkaConnection", + "tags": [ + "kafka_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "test kafka connection", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connection": { + "type": "object" + } + }, + "required": [ + "connection" + ] + } + } + } + }, + "responses": { + "200": { + "description": "successfuly connected to kafka brokers", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/nats_triggers/create": { + "post": { + "summary": "create nats trigger", + "operationId": "createNatsTrigger", + "tags": [ + "nats_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "new nats trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewNatsTrigger" + } + } + } + }, + "responses": { + "201": { + "description": "nats trigger created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/nats_triggers/update/{path}": { + "post": { + "summary": "update nats trigger", + "operationId": "updateNatsTrigger", + "tags": [ + "nats_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditNatsTrigger" + } + } + } + }, + "responses": { + "200": { + "description": "nats trigger updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/nats_triggers/delete/{path}": { + "delete": { + "summary": "delete nats trigger", + "operationId": "deleteNatsTrigger", + "tags": [ + "nats_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "nats trigger deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/nats_triggers/get/{path}": { + "get": { + "summary": "get nats trigger", + "operationId": "getNatsTrigger", + "tags": [ + "nats_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "nats trigger deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NatsTrigger" + } + } + } + } + } + } + }, + "/w/{workspace}/nats_triggers/list": { + "get": { + "summary": "list nats triggers", + "operationId": "listNatsTriggers", + "tags": [ + "nats_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": "nats trigger list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NatsTrigger" + } + } + } + } + } + } + } + }, + "/w/{workspace}/nats_triggers/exists/{path}": { + "get": { + "summary": "does nats trigger exists", + "operationId": "existsNatsTrigger", + "tags": [ + "nats_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "nats trigger exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/nats_triggers/setenabled/{path}": { + "post": { + "summary": "set enabled nats trigger", + "operationId": "setNatsTriggerEnabled", + "tags": [ + "nats_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated nats trigger enable", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ] + } + } + } + }, + "responses": { + "200": { + "description": "nats trigger enabled set", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/nats_triggers/test": { + "post": { + "summary": "test NATS connection", + "operationId": "testNatsConnection", + "tags": [ + "nats_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "test nats connection", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connection": { + "type": "object" + } + }, + "required": [ + "connection" + ] + } + } + } + }, + "responses": { + "200": { + "description": "successfuly connected to NATS servers", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/sqs_triggers/create": { + "post": { + "summary": "create sqs trigger", + "operationId": "createSqsTrigger", + "tags": [ + "sqs_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "new sqs trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewSqsTrigger" + } + } + } + }, + "responses": { + "201": { + "description": "sqs trigger created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/sqs_triggers/update/{path}": { + "post": { + "summary": "update sqs trigger", + "operationId": "updateSqsTrigger", + "tags": [ + "sqs_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditSqsTrigger" + } + } + } + }, + "responses": { + "200": { + "description": "sqs trigger updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/sqs_triggers/delete/{path}": { + "delete": { + "summary": "delete sqs trigger", + "operationId": "deleteSqsTrigger", + "tags": [ + "sqs_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "sqs trigger deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/sqs_triggers/get/{path}": { + "get": { + "summary": "get sqs trigger", + "operationId": "getSqsTrigger", + "tags": [ + "sqs_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "sqs trigger deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SqsTrigger" + } + } + } + } + } + } + }, + "/w/{workspace}/sqs_triggers/list": { + "get": { + "summary": "list sqs triggers", + "operationId": "listSqsTriggers", + "tags": [ + "sqs_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": "sqs trigger list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SqsTrigger" + } + } + } + } + } + } + } + }, + "/w/{workspace}/sqs_triggers/exists/{path}": { + "get": { + "summary": "does sqs trigger exists", + "operationId": "existsSqsTrigger", + "tags": [ + "sqs_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "sqs trigger exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/sqs_triggers/setenabled/{path}": { + "post": { + "summary": "set enabled sqs trigger", + "operationId": "setSqsTriggerEnabled", + "tags": [ + "sqs_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated sqs trigger enable", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ] + } + } + } + }, + "responses": { + "200": { + "description": "sqs trigger enabled set", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/sqs_triggers/test": { + "post": { + "summary": "test sqs connection", + "operationId": "testSqsConnection", + "tags": [ + "sqs_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "test sqs connection", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connection": { + "type": "object" + } + }, + "required": [ + "connection" + ] + } + } + } + }, + "responses": { + "200": { + "description": "successfuly connected to sqs", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/mqtt_triggers/create": { + "post": { + "summary": "create mqtt trigger", + "operationId": "createMqttTrigger", + "tags": [ + "mqtt_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "new mqtt trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewMqttTrigger" + } + } + } + }, + "responses": { + "201": { + "description": "mqtt trigger created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/mqtt_triggers/update/{path}": { + "post": { + "summary": "update mqtt trigger", + "operationId": "updateMqttTrigger", + "tags": [ + "mqtt_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditMqttTrigger" + } + } + } + }, + "responses": { + "200": { + "description": "mqtt trigger updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/mqtt_triggers/delete/{path}": { + "delete": { + "summary": "delete mqtt trigger", + "operationId": "deleteMqttTrigger", + "tags": [ + "mqtt_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "mqtt trigger deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/mqtt_triggers/get/{path}": { + "get": { + "summary": "get mqtt trigger", + "operationId": "getMqttTrigger", + "tags": [ + "mqtt_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "mqtt trigger deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MqttTrigger" + } + } + } + } + } + } + }, + "/w/{workspace}/mqtt_triggers/list": { + "get": { + "summary": "list mqtt triggers", + "operationId": "listMqttTriggers", + "tags": [ + "mqtt_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": "mqtt trigger list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MqttTrigger" + } + } + } + } + } + } + } + }, + "/w/{workspace}/mqtt_triggers/exists/{path}": { + "get": { + "summary": "does mqtt trigger exists", + "operationId": "existsMqttTrigger", + "tags": [ + "mqtt_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "mqtt trigger exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/mqtt_triggers/setenabled/{path}": { + "post": { + "summary": "set enabled mqtt trigger", + "operationId": "setMqttTriggerEnabled", + "tags": [ + "mqtt_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated mqtt trigger enable", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ] + } + } + } + }, + "responses": { + "200": { + "description": "mqtt trigger enabled set", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/mqtt_triggers/test": { + "post": { + "summary": "test mqtt connection", + "operationId": "testMqttConnection", + "tags": [ + "mqtt_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "test mqtt connection", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connection": { + "type": "object" + } + }, + "required": [ + "connection" + ] + } + } + } + }, + "responses": { + "200": { + "description": "successfully connected to mqtt", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/create": { + "post": { + "summary": "create gcp trigger", + "operationId": "createGcpTrigger", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "new gcp trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GcpTriggerData" + } + } + } + }, + "responses": { + "201": { + "description": "gcp trigger created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/update/{path}": { + "post": { + "summary": "update gcp trigger", + "operationId": "updateGcpTrigger", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GcpTriggerData" + } + } + } + }, + "responses": { + "200": { + "description": "gcp trigger updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/delete/{path}": { + "delete": { + "summary": "delete gcp trigger", + "operationId": "deleteGcpTrigger", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "gcp trigger deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/get/{path}": { + "get": { + "summary": "get gcp trigger", + "operationId": "getGcpTrigger", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "gcp trigger deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GcpTrigger" + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/list": { + "get": { + "summary": "list gcp triggers", + "operationId": "listGcpTriggers", + "tags": [ + "gcp_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": "gcp trigger list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GcpTrigger" + } + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/exists/{path}": { + "get": { + "summary": "does gcp trigger exists", + "operationId": "existsGcpTrigger", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "gcp trigger exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/setenabled/{path}": { + "post": { + "summary": "set enabled gcp trigger", + "operationId": "setGcpTriggerEnabled", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated gcp trigger enable", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ] + } + } + } + }, + "responses": { + "200": { + "description": "gcp trigger enabled set", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/test": { + "post": { + "summary": "test gcp connection", + "operationId": "testGcpConnection", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "test gcp connection", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connection": { + "type": "object" + } + }, + "required": [ + "connection" + ] + } + } + } + }, + "responses": { + "200": { + "description": "try to connect to a gcp broker", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/subscriptions/delete/{path}": { + "delete": { + "summary": "delete gcp trigger", + "operationId": "deleteGcpSubscription", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "args to delete subscription from google cloud", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteGcpSubscription" + } + } + } + }, + "responses": { + "200": { + "description": "gcp trigger deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/topics/list/{path}": { + "get": { + "summary": "list all topics of google cloud service", + "operationId": "listGoogleTopics", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "get all google topics", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "/w/{workspace}/gcp_triggers/subscriptions/list/{path}": { + "post": { + "summary": "list all subscription of a give topic from google cloud service", + "operationId": "listAllTGoogleTopicSubscriptions", + "tags": [ + "gcp_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "args to get subscription's topic from google cloud", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetAllTopicSubscription" + } + } + } + }, + "responses": { + "200": { + "description": "get all google topic subscriptions name", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/is_valid_postgres_configuration/{path}": { + "get": { + "summary": "check if postgres configuration is set to logical", + "operationId": "isValidPostgresConfiguration", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "boolean that indicates if postgres is set to logical level or not", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/create_template_script": { + "post": { + "summary": "create template script", + "operationId": "createTemplateScript", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "template script", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TemplateScript" + } + } + } + }, + "responses": { + "200": { + "description": "custom id to retrieve template script", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/get_template_script/{id}": { + "get": { + "summary": "get template script", + "operationId": "getTemplateScript", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Id" + } + ], + "responses": { + "200": { + "description": "template script", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/slot/list/{path}": { + "get": { + "summary": "list postgres replication slot", + "operationId": "listPostgresReplicationSlot", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "list postgres slot", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SlotList" + } + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/slot/create/{path}": { + "post": { + "summary": "create replication slot for postgres", + "operationId": "createPostgresReplicationSlot", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "new slot for postgres", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Slot" + } + } + } + }, + "responses": { + "201": { + "description": "slot created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/slot/delete/{path}": { + "delete": { + "summary": "delete postgres replication slot", + "operationId": "deletePostgresReplicationSlot", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "replication slot of postgres", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Slot" + } + } + } + }, + "responses": { + "200": { + "description": "postgres replication slot deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/publication/list/{path}": { + "get": { + "summary": "list postgres publication", + "operationId": "listPostgresPublication", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "database publication list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/publication/get/{publication}/{path}": { + "get": { + "summary": "get postgres publication", + "operationId": "getPostgresPublication", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + }, + { + "$ref": "#/components/parameters/PublicationName" + } + ], + "responses": { + "200": { + "description": "postgres publication get", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicationData" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/publication/create/{publication}/{path}": { + "post": { + "summary": "create publication for postgres", + "operationId": "createPostgresPublication", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + }, + { + "$ref": "#/components/parameters/PublicationName" + } + ], + "requestBody": { + "description": "new publication for postgres", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicationData" + } + } + } + }, + "responses": { + "201": { + "description": "publication created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/publication/update/{publication}/{path}": { + "post": { + "summary": "update publication for postgres", + "operationId": "updatePostgresPublication", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + }, + { + "$ref": "#/components/parameters/PublicationName" + } + ], + "requestBody": { + "description": "update publication for postgres", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicationData" + } + } + } + }, + "responses": { + "201": { + "description": "publication updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/publication/delete/{publication}/{path}": { + "delete": { + "summary": "delete postgres publication", + "operationId": "deletePostgresPublication", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + }, + { + "$ref": "#/components/parameters/PublicationName" + } + ], + "responses": { + "200": { + "description": "postgres publication deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/create": { + "post": { + "summary": "create postgres trigger", + "operationId": "createPostgresTrigger", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "new postgres trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewPostgresTrigger" + } + } + } + }, + "responses": { + "201": { + "description": "postgres trigger created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/update/{path}": { + "post": { + "summary": "update postgres trigger", + "operationId": "updatePostgresTrigger", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditPostgresTrigger" + } + } + } + }, + "responses": { + "200": { + "description": "postgres trigger updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/delete/{path}": { + "delete": { + "summary": "delete postgres trigger", + "operationId": "deletePostgresTrigger", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "postgres trigger deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/get/{path}": { + "get": { + "summary": "get postgres trigger", + "operationId": "getPostgresTrigger", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "get postgres trigger", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostgresTrigger" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/list": { + "get": { + "summary": "list postgres triggers", + "operationId": "listPostgresTriggers", + "tags": [ + "postgres_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": "postgres trigger list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PostgresTrigger" + } + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/exists/{path}": { + "get": { + "summary": "does postgres trigger exists", + "operationId": "existsPostgresTrigger", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "postgres trigger exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/setenabled/{path}": { + "post": { + "summary": "set enabled postgres trigger", + "operationId": "setPostgresTriggerEnabled", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated postgres trigger enable", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ] + } + } + } + }, + "responses": { + "200": { + "description": "postgres trigger enabled set", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/postgres_triggers/test": { + "post": { + "summary": "test postgres connection", + "operationId": "testPostgresConnection", + "tags": [ + "postgres_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "test postgres connection", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "database": { + "type": "string" + } + }, + "required": [ + "database" + ] + } + } + } + }, + "responses": { + "200": { + "description": "successfuly connected to postgres", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/groups/list": { "get": { "summary": "list instance groups", @@ -12989,6 +17483,35 @@ } } }, + "/w/{workspace}/folders/exists/{name}": { + "get": { + "summary": "exists folder", + "operationId": "existsFolder", + "tags": [ + "folder" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "folder exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, "/w/{workspace}/folders/getusage/{name}": { "get": { "summary": "get folder usage", @@ -13343,7 +17866,9 @@ "description": "a config", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/Configs" + } } } } @@ -13467,6 +17992,81 @@ } } }, + "/configs/list_available_python_versions": { + "get": { + "summary": "Get currently available python versions provided by UV.", + "operationId": "listAvailablePythonVersions", + "tags": [ + "config" + ], + "responses": { + "200": { + "description": "List of python versions", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "/agent_workers/create_agent_token": { + "post": { + "summary": "create agent token", + "operationId": "createAgentToken", + "tags": [ + "agent_workers" + ], + "requestBody": { + "description": "agent token", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "worker_group": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "exp": { + "type": "integer" + } + }, + "required": [ + "worker_group", + "tags", + "exp" + ] + } + } + } + }, + "responses": { + "200": { + "description": "agent token created", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/w/{workspace}/acls/get/{kind}/{path}": { "get": { "summary": "get granular acls", @@ -13498,7 +18098,13 @@ "app", "raw_app", "http_trigger", - "websocket_trigger" + "websocket_trigger", + "kafka_trigger", + "nats_trigger", + "postgres_trigger", + "mqtt_trigger", + "gcp_trigger", + "sqs_trigger" ] } } @@ -13551,7 +18157,13 @@ "app", "raw_app", "http_trigger", - "websocket_trigger" + "websocket_trigger", + "kafka_trigger", + "nats_trigger", + "postgres_trigger", + "mqtt_trigger", + "gcp_trigger", + "sqs_trigger" ] } } @@ -13623,7 +18235,13 @@ "app", "raw_app", "http_trigger", - "websocket_trigger" + "websocket_trigger", + "kafka_trigger", + "nats_trigger", + "postgres_trigger", + "mqtt_trigger", + "gcp_trigger", + "sqs_trigger" ] } } @@ -13661,32 +18279,66 @@ } } }, - "/w/{workspace}/capture_u/{path}": { + "/w/{workspace}/capture/set_config": { "post": { - "summary": "update flow preview capture", - "operationId": "updateCapture", + "summary": "set capture config", + "operationId": "setCaptureConfig", "tags": [ "capture" ], "parameters": [ { "$ref": "#/components/parameters/WorkspaceId" - }, - { - "$ref": "#/components/parameters/Path" } ], + "requestBody": { + "description": "capture config", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "trigger_kind": { + "$ref": "#/components/schemas/CaptureTriggerKind" + }, + "path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "trigger_config": { + "type": "object" + } + }, + "required": [ + "trigger_kind", + "path", + "is_flow" + ] + } + } + } + }, "responses": { - "204": { - "description": "flow preview captured" + "200": { + "description": "capture config set", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } } } } }, - "/w/{workspace}/capture/{path}": { - "put": { - "summary": "create flow preview capture", - "operationId": "createCapture", + "/w/{workspace}/capture/ping_config/{trigger_kind}/{runnable_kind}/{path}": { + "post": { + "summary": "ping capture config", + "operationId": "pingCaptureConfig", "tags": [ "capture" ], @@ -13694,18 +18346,162 @@ { "$ref": "#/components/parameters/WorkspaceId" }, + { + "name": "trigger_kind", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/CaptureTriggerKind" + } + }, + { + "$ref": "#/components/parameters/RunnableKind" + }, { "$ref": "#/components/parameters/Path" } ], "responses": { - "201": { - "description": "flow preview capture created" + "200": { + "description": "capture config pinged" } } - }, + } + }, + "/w/{workspace}/capture/get_configs/{runnable_kind}/{path}": { "get": { - "summary": "get flow preview capture", + "summary": "get capture configs for a script or flow", + "operationId": "getCaptureConfigs", + "tags": [ + "capture" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/RunnableKind" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "capture configs for a script or flow", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CaptureConfig" + } + } + } + } + } + } + } + }, + "/w/{workspace}/capture/list/{runnable_kind}/{path}": { + "get": { + "summary": "list captures for a script or flow", + "operationId": "listCaptures", + "tags": [ + "capture" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/RunnableKind" + }, + { + "$ref": "#/components/parameters/Path" + }, + { + "name": "trigger_kind", + "in": "query", + "schema": { + "$ref": "#/components/schemas/CaptureTriggerKind" + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/PerPage" + } + ], + "responses": { + "200": { + "description": "list of captures for a script or flow", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Capture" + } + } + } + } + } + } + } + }, + "/w/{workspace}/capture/move/{runnable_kind}/{path}": { + "post": { + "summary": "move captures and configs for a script or flow", + "operationId": "moveCapturesAndConfigs", + "tags": [ + "capture" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/RunnableKind" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "move captures and configs to a new path", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "new_path": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "captures and configs moved", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/capture/{id}": { + "get": { + "summary": "get a capture", "operationId": "getCapture", "tags": [ "capture" @@ -13715,20 +18511,49 @@ "$ref": "#/components/parameters/WorkspaceId" }, { - "$ref": "#/components/parameters/Path" + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } } ], "responses": { "200": { - "description": "captured flow preview", + "description": "capture", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/Capture" + } } } + } + } + }, + "delete": { + "summary": "delete a capture", + "operationId": "deleteCapture", + "tags": [ + "capture" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" }, - "404": { - "description": "capture does not exist for this flow" + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "capture deleted" } } } @@ -13839,6 +18664,16 @@ }, { "$ref": "#/components/parameters/PerPage" + }, + { + "$ref": "#/components/parameters/ArgsFilter" + }, + { + "name": "include_preview", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -14142,6 +18977,9 @@ "properties": { "connection_settings_str": { "type": "string" + }, + "azure_container_path": { + "type": "string" } }, "required": [ @@ -14994,7 +19832,7 @@ }, "/w/{workspace}/job_helpers/download_s3_file": { "get": { - "summary": "Download file to S3 bucket", + "summary": "Download file from S3 bucket", "operationId": "fileDownload", "tags": [ "helpers" @@ -15508,6 +20346,9 @@ { "$ref": "#/components/parameters/ResultFilter" }, + { + "$ref": "#/components/parameters/AllowWildcards" + }, { "$ref": "#/components/parameters/Page" }, @@ -15595,6 +20436,14 @@ "schema": { "type": "string" } + }, + { + "name": "pagination_offset", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } } ], "responses": { @@ -15609,12 +20458,7 @@ "description": "a list of the terms that couldn't be parsed (and thus ignored)", "type": "array", "items": { - "type": "object", - "properties": { - "dancer": { - "type": "string" - } - } + "type": "string" } }, "hits": { @@ -15623,6 +20467,25 @@ "items": { "$ref": "#/components/schemas/JobSearchHit" } + }, + "hit_count": { + "description": "how many jobs matched in total", + "type": "number" + }, + "index_metadata": { + "description": "Metadata about the index current state", + "type": "object", + "properties": { + "indexed_until": { + "description": "Datetime of the most recently indexed job", + "type": "string", + "format": "date-time" + }, + "lost_lock_ownership": { + "description": "Is the current indexer service being replaced", + "type": "boolean" + } + } } } } @@ -15737,14 +20600,6 @@ "type": "string" } }, - { - "name": "hosts", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, { "name": "min_ts", "in": "query", @@ -15790,6 +20645,41 @@ } } } + }, + "/srch/index/delete/{idx_name}": { + "delete": { + "summary": "Restart container and delete the index to recreate it.", + "operationId": "clearIndex", + "tags": [ + "indexSearch" + ], + "parameters": [ + { + "name": "idx_name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "JobIndex", + "ServiceLogIndex" + ] + } + } + ], + "responses": { + "200": { + "description": "idx to be deleted and container restarting", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } } }, "components": { @@ -15805,6 +20695,14 @@ } }, "parameters": { + "Id": { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, "Key": { "name": "key", "in": "path", @@ -15821,6 +20719,14 @@ "type": "string" } }, + "PublicationName": { + "name": "publication", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, "VersionId": { "name": "version", "in": "path", @@ -15886,6 +20792,14 @@ "type": "string" } }, + "CustomPath": { + "name": "custom_path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, "PathId": { "name": "id", "in": "path", @@ -15950,6 +20864,14 @@ "type": "string" } }, + "Worker": { + "name": "worker", + "description": "worker this job was ran on", + "in": "query", + "schema": { + "type": "string" + } + }, "ParentJob": { "name": "parent_job", "description": "The parent job that is at the origin and responsible for the execution of this script if any", @@ -16144,6 +21066,14 @@ "type": "boolean" } }, + "AllowWildcards": { + "name": "allow_wildcards", + "description": "allow wildcards (*) in the filter of label, tag, worker", + "in": "query", + "schema": { + "type": "boolean" + } + }, "ArgsFilter": { "name": "args", "description": "filter on jobs containing those args as a json subset (@> in postgres)", @@ -16259,24 +21189,135 @@ "schema": { "type": "string" } + }, + "RunnableKind": { + "name": "runnable_kind", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "script", + "flow" + ] + } } }, "schemas": { - "AiResource": { + "InputTransform": { + "allOf": [ + { + "$ref": "#/components/schemas/schemas-InputTransform" + } + ] + }, + "AIProvider": { + "type": "string", + "enum": [ + "openai", + "azure_openai", + "anthropic", + "mistral", + "deepseek", + "googleai", + "groq", + "openrouter", + "togetherai", + "customai" + ] + }, + "AIProviderModel": { "type": "object", "properties": { - "path": { + "model": { "type": "string" }, "provider": { - "type": "string" + "$ref": "#/components/schemas/AIProvider" } }, "required": [ - "path", + "model", "provider" ] }, + "AIProviderConfig": { + "type": "object", + "properties": { + "resource_path": { + "type": "string" + }, + "models": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "resource_path", + "models" + ] + }, + "AIConfig": { + "type": "object", + "properties": { + "providers": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/AIProviderConfig" + } + }, + "default_model": { + "$ref": "#/components/schemas/AIProviderModel" + }, + "code_completion_model": { + "$ref": "#/components/schemas/AIProviderModel" + } + } + }, + "Alert": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "tags_to_monitor": { + "type": "array", + "items": { + "type": "string" + } + }, + "jobs_num_threshold": { + "type": "integer" + }, + "alert_cooldown_seconds": { + "type": "integer" + }, + "alert_time_threshold_seconds": { + "type": "integer" + } + }, + "required": [ + "name", + "tags_to_monitor", + "jobs_num_threshold", + "alert_cooldown_seconds", + "alert_time_threshold_seconds" + ] + }, + "Configs": { + "type": "object", + "nullable": true, + "properties": { + "alerts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Alert" + } + } + } + }, "Script": { "type": "object", "properties": { @@ -16337,25 +21378,7 @@ "type": "string" }, "language": { - "type": "string", - "enum": [ - "python3", - "deno", - "go", - "bash", - "powershell", - "postgresql", - "mysql", - "bigquery", - "snowflake", - "mssql", - "graphql", - "nativets", - "bun", - "php", - "rust", - "ansible" - ] + "$ref": "#/components/schemas/ScriptLang" }, "kind": { "type": "string", @@ -16364,7 +21387,8 @@ "failure", "trigger", "command", - "approval" + "approval", + "preprocessor" ] }, "starred": { @@ -16426,6 +21450,9 @@ }, "has_preprocessor": { "type": "boolean" + }, + "on_behalf_of_email": { + "type": "string" } }, "required": [ @@ -16475,25 +21502,7 @@ "type": "string" }, "language": { - "type": "string", - "enum": [ - "python3", - "deno", - "go", - "bash", - "powershell", - "postgresql", - "mysql", - "bigquery", - "snowflake", - "mssql", - "graphql", - "nativets", - "bun", - "php", - "rust", - "ansible" - ] + "$ref": "#/components/schemas/ScriptLang" }, "kind": { "type": "string", @@ -16502,7 +21511,8 @@ "failure", "trigger", "command", - "approval" + "approval", + "preprocessor" ] }, "tag": { @@ -16561,6 +21571,9 @@ }, "has_preprocessor": { "type": "boolean" + }, + "on_behalf_of_email": { + "type": "string" } }, "required": [ @@ -16758,7 +21771,10 @@ "script_hub", "identity", "deploymentcallback", - "singlescriptflow" + "singlescriptflow", + "flowscript", + "flownode", + "appscript" ] }, "schedule_path": { @@ -16766,7 +21782,7 @@ }, "permissioned_as": { "type": "string", - "description": "The user (u/userfoo) or group (g/groupfoo) whom \nthe execution of this script will be permissioned_as and by extension its DT_TOKEN.\n" + "description": "The user (u/userfoo) or group (g/groupfoo) whom\nthe execution of this script will be permissioned_as and by extension its DT_TOKEN.\n" }, "flow_status": { "$ref": "#/components/schemas/FlowStatus" @@ -16778,25 +21794,7 @@ "type": "boolean" }, "language": { - "type": "string", - "enum": [ - "python3", - "deno", - "go", - "bash", - "powershell", - "postgresql", - "mysql", - "bigquery", - "snowflake", - "mssql", - "graphql", - "nativets", - "bun", - "php", - "rust", - "ansible" - ] + "$ref": "#/components/schemas/ScriptLang" }, "email": { "type": "string" @@ -16821,6 +21819,12 @@ }, "suspend": { "type": "number" + }, + "preprocessed": { + "type": "boolean" + }, + "worker": { + "type": "string" } }, "required": [ @@ -16907,7 +21911,10 @@ "script_hub", "identity", "deploymentcallback", - "singlescriptflow" + "singlescriptflow", + "flowscript", + "flownode", + "appscript" ] }, "schedule_path": { @@ -16915,7 +21922,7 @@ }, "permissioned_as": { "type": "string", - "description": "The user (u/userfoo) or group (g/groupfoo) whom \nthe execution of this script will be permissioned_as and by extension its DT_TOKEN.\n" + "description": "The user (u/userfoo) or group (g/groupfoo) whom\nthe execution of this script will be permissioned_as and by extension its DT_TOKEN.\n" }, "flow_status": { "$ref": "#/components/schemas/FlowStatus" @@ -16927,25 +21934,7 @@ "type": "boolean" }, "language": { - "type": "string", - "enum": [ - "python3", - "deno", - "go", - "bash", - "powershell", - "postgresql", - "mysql", - "bigquery", - "snowflake", - "mssql", - "graphql", - "nativets", - "bun", - "php", - "rust", - "ansible" - ] + "$ref": "#/components/schemas/ScriptLang" }, "is_skipped": { "type": "boolean" @@ -16976,6 +21965,12 @@ }, "aggregate_wait_time_ms": { "type": "number" + }, + "preprocessed": { + "type": "boolean" + }, + "worker": { + "type": "string" } }, "required": [ @@ -17065,6 +22060,9 @@ "is_admin": { "type": "boolean" }, + "name": { + "type": "string" + }, "is_super_admin": { "type": "boolean" }, @@ -17670,6 +22668,31 @@ "has_preprocessor" ] }, + "ScriptLang": { + "type": "string", + "enum": [ + "python3", + "deno", + "go", + "bash", + "powershell", + "postgresql", + "mysql", + "bigquery", + "snowflake", + "mssql", + "oracledb", + "graphql", + "nativets", + "bun", + "php", + "rust", + "ansible", + "csharp", + "nu", + "java" + ] + }, "Preview": { "type": "object", "properties": { @@ -17679,29 +22702,14 @@ "path": { "type": "string" }, + "script_hash": { + "type": "string" + }, "args": { "$ref": "#/components/schemas/ScriptArgs" }, "language": { - "type": "string", - "enum": [ - "python3", - "deno", - "go", - "bash", - "powershell", - "postgresql", - "mysql", - "bigquery", - "snowflake", - "mssql", - "graphql", - "nativets", - "bun", - "php", - "rust", - "ansible" - ] + "$ref": "#/components/schemas/ScriptLang" }, "tag": { "type": "string" @@ -18004,6 +23012,9 @@ "summary": { "type": "string" }, + "description": { + "type": "string" + }, "no_flow_overlap": { "type": "boolean" }, @@ -18013,6 +23024,9 @@ "paused_until": { "type": "string", "format": "date-time" + }, + "cron_version": { + "type": "string" } }, "required": [ @@ -18125,12 +23139,18 @@ "summary": { "type": "string" }, + "description": { + "type": "string" + }, "tag": { "type": "string" }, "paused_until": { "type": "string", "format": "date-time" + }, + "cron_version": { + "type": "string" } }, "required": [ @@ -18193,12 +23213,18 @@ "summary": { "type": "string" }, + "description": { + "type": "string" + }, "tag": { "type": "string" }, "paused_until": { "type": "string", "format": "date-time" + }, + "cron_version": { + "type": "string" } }, "required": [ @@ -18209,12 +23235,27 @@ "args" ] }, - "HttpTrigger": { + "TriggerExtraProperty": { "type": "object", "properties": { "path": { "type": "string" }, + "script_path": { + "type": "string" + }, + "email": { + "type": "string" + }, + "extra_perms": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, + "workspace_id": { + "type": "string" + }, "edited_by": { "type": "string" }, @@ -18222,9 +23263,40 @@ "type": "string", "format": "date-time" }, - "script_path": { - "type": "string" - }, + "is_flow": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "email", + "extra_perms", + "workspace_id", + "edited_by", + "edited_at", + "is_flow" + ] + }, + "AuthenticationMethod": { + "type": "string", + "enum": [ + "none", + "windmill", + "api_key", + "basic_http", + "custom_script", + "signature" + ] + }, + "HttpTrigger": { + "allOf": [ + { + "$ref": "#/components/schemas/TriggerExtraProperty" + } + ], + "type": "object", + "properties": { "route_path": { "type": "string" }, @@ -18245,21 +23317,6 @@ "s3" ] }, - "is_flow": { - "type": "boolean" - }, - "extra_perms": { - "type": "object", - "additionalProperties": { - "type": "boolean" - } - }, - "email": { - "type": "string" - }, - "workspace_id": { - "type": "string" - }, "http_method": { "type": "string", "enum": [ @@ -18270,26 +23327,37 @@ "patch" ] }, + "authentication_resource_path": { + "type": "string" + }, "is_async": { "type": "boolean" }, - "requires_auth": { + "authentication_method": { + "$ref": "#/components/schemas/AuthenticationMethod" + }, + "is_static_website": { + "type": "boolean" + }, + "workspaced_route": { + "type": "boolean" + }, + "wrap_body": { + "type": "boolean" + }, + "raw_string": { "type": "boolean" } }, "required": [ - "path", - "edited_by", - "edited_at", - "script_path", "route_path", - "extra_perms", - "is_flow", - "email", - "workspace_id", "is_async", - "requires_auth", - "http_method" + "authentication_method", + "http_method", + "is_static_website", + "workspaced_route", + "wrap_body", + "raw_string" ] }, "NewHttpTrigger": { @@ -18304,6 +23372,9 @@ "route_path": { "type": "string" }, + "workspaced_route": { + "type": "boolean" + }, "static_asset_config": { "type": "object", "properties": { @@ -18334,10 +23405,22 @@ "patch" ] }, + "authentication_resource_path": { + "type": "string" + }, "is_async": { "type": "boolean" }, - "requires_auth": { + "authentication_method": { + "$ref": "#/components/schemas/AuthenticationMethod" + }, + "is_static_website": { + "type": "boolean" + }, + "wrap_body": { + "type": "boolean" + }, + "raw_string": { "type": "boolean" } }, @@ -18347,8 +23430,9 @@ "route_path", "is_flow", "is_async", - "requires_auth", - "http_method" + "authentication_method", + "http_method", + "is_static_website" ] }, "EditHttpTrigger": { @@ -18363,6 +23447,9 @@ "route_path": { "type": "string" }, + "workspaced_route": { + "type": "boolean" + }, "static_asset_config": { "type": "object", "properties": { @@ -18380,6 +23467,9 @@ "s3" ] }, + "authentication_resource_path": { + "type": "string" + }, "is_flow": { "type": "boolean" }, @@ -18396,7 +23486,16 @@ "is_async": { "type": "boolean" }, - "requires_auth": { + "authentication_method": { + "$ref": "#/components/schemas/AuthenticationMethod" + }, + "is_static_website": { + "type": "boolean" + }, + "wrap_body": { + "type": "boolean" + }, + "raw_string": { "type": "boolean" } }, @@ -18406,8 +23505,9 @@ "is_flow", "kind", "is_async", - "requires_auth", - "http_method" + "authentication_method", + "http_method", + "is_static_website" ] }, "TriggersCount": { @@ -18435,43 +23535,38 @@ }, "websocket_count": { "type": "number" + }, + "postgres_count": { + "type": "number" + }, + "kafka_count": { + "type": "number" + }, + "nats_count": { + "type": "number" + }, + "mqtt_count": { + "type": "number" + }, + "gcp_count": { + "type": "number" + }, + "sqs_count": { + "type": "number" } } }, "WebsocketTrigger": { + "allOf": [ + { + "$ref": "#/components/schemas/TriggerExtraProperty" + } + ], "type": "object", "properties": { - "path": { - "type": "string" - }, - "edited_by": { - "type": "string" - }, - "edited_at": { - "type": "string", - "format": "date-time" - }, - "script_path": { - "type": "string" - }, "url": { "type": "string" }, - "is_flow": { - "type": "boolean" - }, - "extra_perms": { - "type": "object", - "additionalProperties": { - "type": "boolean" - } - }, - "email": { - "type": "string" - }, - "workspace_id": { - "type": "string" - }, "server_id": { "type": "string" }, @@ -18509,22 +23604,16 @@ }, "url_runnable_args": { "$ref": "#/components/schemas/ScriptArgs" + }, + "can_return_message": { + "type": "boolean" } }, "required": [ - "path", - "edited_by", - "edited_at", - "script_path", "url", - "extra_perms", - "is_flow", - "email", - "workspace_id", "enabled", "filters", - "initial_messages", - "url_runnable_args" + "can_return_message" ] }, "NewWebsocketTrigger": { @@ -18569,6 +23658,9 @@ }, "url_runnable_args": { "$ref": "#/components/schemas/ScriptArgs" + }, + "can_return_message": { + "type": "boolean" } }, "required": [ @@ -18577,8 +23669,7 @@ "url", "is_flow", "filters", - "initial_messages", - "url_runnable_args" + "can_return_message" ] }, "EditWebsocketTrigger": { @@ -18620,6 +23711,9 @@ }, "url_runnable_args": { "$ref": "#/components/schemas/ScriptArgs" + }, + "can_return_message": { + "type": "boolean" } }, "required": [ @@ -18628,8 +23722,7 @@ "url", "is_flow", "filters", - "initial_messages", - "url_runnable_args" + "can_return_message" ] }, "WebsocketTriggerInitialMessage": { @@ -18674,6 +23767,936 @@ } ] }, + "MqttQoS": { + "type": "string", + "enum": [ + "qos0", + "qos1", + "qos2" + ] + }, + "MqttV3Config": { + "type": "object", + "properties": { + "clean_session": { + "type": "boolean" + } + } + }, + "MqttV5Config": { + "type": "object", + "properties": { + "clean_start": { + "type": "boolean" + }, + "topic_alias": { + "type": "number" + }, + "session_expiry_interval": { + "type": "number" + } + } + }, + "MqttSubscribeTopic": { + "type": "object", + "properties": { + "qos": { + "$ref": "#/components/schemas/MqttQoS" + }, + "topic": { + "type": "string" + } + }, + "required": [ + "qos", + "topic" + ] + }, + "MqttClientVersion": { + "type": "string", + "enum": [ + "v3", + "v5" + ] + }, + "MqttTrigger": { + "allOf": [ + { + "$ref": "#/components/schemas/TriggerExtraProperty" + } + ], + "type": "object", + "properties": { + "mqtt_resource_path": { + "type": "string" + }, + "subscribe_topics": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MqttSubscribeTopic" + } + }, + "v3_config": { + "$ref": "#/components/schemas/MqttV3Config" + }, + "v5_config": { + "$ref": "#/components/schemas/MqttV5Config" + }, + "client_id": { + "type": "string" + }, + "client_version": { + "$ref": "#/components/schemas/MqttClientVersion" + }, + "server_id": { + "type": "string" + }, + "last_server_ping": { + "type": "string", + "format": "date-time" + }, + "error": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled", + "subscribe_topics", + "mqtt_resource_path" + ] + }, + "NewMqttTrigger": { + "type": "object", + "properties": { + "mqtt_resource_path": { + "type": "string" + }, + "subscribe_topics": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MqttSubscribeTopic" + } + }, + "client_id": { + "type": "string" + }, + "v3_config": { + "$ref": "#/components/schemas/MqttV3Config" + }, + "v5_config": { + "$ref": "#/components/schemas/MqttV5Config" + }, + "client_version": { + "$ref": "#/components/schemas/MqttClientVersion" + }, + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "is_flow", + "subscribe_topics", + "mqtt_resource_path" + ] + }, + "EditMqttTrigger": { + "type": "object", + "properties": { + "mqtt_resource_path": { + "type": "string" + }, + "subscribe_topics": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MqttSubscribeTopic" + } + }, + "client_id": { + "type": "string" + }, + "v3_config": { + "$ref": "#/components/schemas/MqttV3Config" + }, + "v5_config": { + "$ref": "#/components/schemas/MqttV5Config" + }, + "client_version": { + "$ref": "#/components/schemas/MqttClientVersion" + }, + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "is_flow", + "enabled", + "subscribe_topics", + "mqtt_resource_path" + ] + }, + "DeliveryType": { + "type": "string", + "enum": [ + "push", + "pull" + ] + }, + "PushConfig": { + "type": "object", + "properties": { + "audience": { + "type": "string" + }, + "authenticate": { + "type": "boolean" + } + }, + "required": [ + "authenticate", + "base_endpoint" + ] + }, + "GcpTrigger": { + "allOf": [ + { + "$ref": "#/components/schemas/TriggerExtraProperty" + } + ], + "type": "object", + "properties": { + "gcp_resource_path": { + "type": "string" + }, + "topic_id": { + "type": "string" + }, + "subscription_id": { + "type": "string" + }, + "server_id": { + "type": "string" + }, + "delivery_type": { + "$ref": "#/components/schemas/DeliveryType" + }, + "delivery_config": { + "$ref": "#/components/schemas/PushConfig" + }, + "subscription_mode": { + "$ref": "#/components/schemas/SubscriptionMode" + }, + "last_server_ping": { + "type": "string", + "format": "date-time" + }, + "error": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "gcp_resource_path", + "topic_id", + "subscription_id", + "enabled", + "delivery_type", + "subscription_mode" + ] + }, + "SubscriptionMode": { + "type": "string", + "enum": [ + "existing", + "create_update" + ], + "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": { + "gcp_resource_path": { + "type": "string" + }, + "subscription_mode": { + "$ref": "#/components/schemas/SubscriptionMode" + }, + "topic_id": { + "type": "string" + }, + "subscription_id": { + "type": "string" + }, + "base_endpoint": { + "type": "string" + }, + "delivery_type": { + "$ref": "#/components/schemas/DeliveryType" + }, + "delivery_config": { + "$ref": "#/components/schemas/PushConfig" + }, + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "is_flow", + "gcp_resource_path", + "topic_id", + "subscription_mode" + ] + }, + "GetAllTopicSubscription": { + "type": "object", + "properties": { + "topic_id": { + "type": "string" + } + }, + "required": [ + "topic_id" + ] + }, + "DeleteGcpSubscription": { + "type": "object", + "properties": { + "subscription_id": { + "type": "string" + } + }, + "required": [ + "subscription_id" + ] + }, + "AwsAuthResourceType": { + "type": "string", + "enum": [ + "oidc", + "credentials" + ] + }, + "SqsTrigger": { + "allOf": [ + { + "$ref": "#/components/schemas/TriggerExtraProperty" + } + ], + "type": "object", + "properties": { + "queue_url": { + "type": "string" + }, + "aws_auth_resource_type": { + "$ref": "#/components/schemas/AwsAuthResourceType" + }, + "aws_resource_path": { + "type": "string" + }, + "message_attributes": { + "type": "array", + "items": { + "type": "string" + } + }, + "server_id": { + "type": "string" + }, + "last_server_ping": { + "type": "string", + "format": "date-time" + }, + "error": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "queue_url", + "aws_resource_path", + "enabled", + "aws_auth_resource_type" + ] + }, + "NewSqsTrigger": { + "type": "object", + "properties": { + "queue_url": { + "type": "string" + }, + "aws_auth_resource_type": { + "$ref": "#/components/schemas/AwsAuthResourceType" + }, + "aws_resource_path": { + "type": "string" + }, + "message_attributes": { + "type": "array", + "items": { + "type": "string" + } + }, + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "queue_url", + "aws_resource_path", + "path", + "script_path", + "is_flow", + "aws_auth_resource_type" + ] + }, + "EditSqsTrigger": { + "type": "object", + "properties": { + "queue_url": { + "type": "string" + }, + "aws_auth_resource_type": { + "$ref": "#/components/schemas/AwsAuthResourceType" + }, + "aws_resource_path": { + "type": "string" + }, + "message_attributes": { + "type": "array", + "items": { + "type": "string" + } + }, + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "queue_url", + "aws_resource_path", + "path", + "script_path", + "is_flow", + "enabled", + "aws_auth_resource_type" + ] + }, + "Slot": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "SlotList": { + "type": "object", + "properties": { + "slot_name": { + "type": "string" + }, + "active": { + "type": "boolean" + } + } + }, + "PublicationData": { + "type": "object", + "properties": { + "table_to_track": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Relations" + } + }, + "transaction_to_track": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "transaction_to_track" + ] + }, + "TableToTrack": { + "type": "array", + "items": { + "type": "object", + "properties": { + "table_name": { + "type": "string" + }, + "columns_name": { + "type": "array", + "items": { + "type": "string" + } + }, + "where_clause": { + "type": "string" + } + }, + "required": [ + "table_name" + ] + } + }, + "Relations": { + "type": "object", + "properties": { + "schema_name": { + "type": "string" + }, + "table_to_track": { + "$ref": "#/components/schemas/TableToTrack" + } + }, + "required": [ + "schema_name", + "table_to_track" + ] + }, + "Language": { + "type": "string", + "enum": [ + "Typescript" + ] + }, + "TemplateScript": { + "type": "object", + "properties": { + "postgres_resource_path": { + "type": "string" + }, + "relations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Relations" + } + }, + "language": { + "$ref": "#/components/schemas/Language" + } + }, + "required": [ + "postgres_resource_path", + "relations", + "language" + ] + }, + "PostgresTrigger": { + "allOf": [ + { + "$ref": "#/components/schemas/TriggerExtraProperty" + } + ], + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "postgres_resource_path": { + "type": "string" + }, + "publication_name": { + "type": "string" + }, + "server_id": { + "type": "string" + }, + "replication_slot_name": { + "type": "string" + }, + "error": { + "type": "string" + }, + "last_server_ping": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "enabled", + "postgres_resource_path", + "replication_slot_name", + "publication_name" + ] + }, + "NewPostgresTrigger": { + "type": "object", + "properties": { + "replication_slot_name": { + "type": "string" + }, + "publication_name": { + "type": "string" + }, + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "postgres_resource_path": { + "type": "string" + }, + "publication": { + "$ref": "#/components/schemas/PublicationData" + } + }, + "required": [ + "path", + "script_path", + "is_flow", + "enabled", + "postgres_resource_path" + ] + }, + "EditPostgresTrigger": { + "type": "object", + "properties": { + "replication_slot_name": { + "type": "string" + }, + "publication_name": { + "type": "string" + }, + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "postgres_resource_path": { + "type": "string" + }, + "publication": { + "$ref": "#/components/schemas/PublicationData" + } + }, + "required": [ + "path", + "script_path", + "is_flow", + "enabled", + "postgres_resource_path", + "publication_name", + "replication_slot_name" + ] + }, + "KafkaTrigger": { + "allOf": [ + { + "$ref": "#/components/schemas/TriggerExtraProperty" + } + ], + "type": "object", + "properties": { + "kafka_resource_path": { + "type": "string" + }, + "group_id": { + "type": "string" + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + }, + "server_id": { + "type": "string" + }, + "last_server_ping": { + "type": "string", + "format": "date-time" + }, + "error": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "kafka_resource_path", + "group_id", + "topics", + "enabled" + ] + }, + "NewKafkaTrigger": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "kafka_resource_path": { + "type": "string" + }, + "group_id": { + "type": "string" + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "is_flow", + "kafka_resource_path", + "group_id", + "topics" + ] + }, + "EditKafkaTrigger": { + "type": "object", + "properties": { + "kafka_resource_path": { + "type": "string" + }, + "group_id": { + "type": "string" + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + }, + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "kafka_resource_path", + "group_id", + "topics", + "is_flow" + ] + }, + "NatsTrigger": { + "allOf": [ + { + "$ref": "#/components/schemas/TriggerExtraProperty" + } + ], + "type": "object", + "properties": { + "nats_resource_path": { + "type": "string" + }, + "use_jetstream": { + "type": "boolean" + }, + "stream_name": { + "type": "string" + }, + "consumer_name": { + "type": "string" + }, + "subjects": { + "type": "array", + "items": { + "type": "string" + } + }, + "server_id": { + "type": "string" + }, + "last_server_ping": { + "type": "string", + "format": "date-time" + }, + "error": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "nats_resource_path", + "use_jetstream", + "subjects", + "enabled" + ] + }, + "NewNatsTrigger": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "nats_resource_path": { + "type": "string" + }, + "use_jetstream": { + "type": "boolean" + }, + "stream_name": { + "type": "string" + }, + "consumer_name": { + "type": "string" + }, + "subjects": { + "type": "array", + "items": { + "type": "string" + } + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "is_flow", + "nats_resource_path", + "use_jetstream", + "subjects" + ] + }, + "EditNatsTrigger": { + "type": "object", + "properties": { + "nats_resource_path": { + "type": "string" + }, + "use_jetstream": { + "type": "boolean" + }, + "stream_name": { + "type": "string" + }, + "consumer_name": { + "type": "string" + }, + "subjects": { + "type": "array", + "items": { + "type": "string" + } + }, + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "nats_resource_path", + "use_jetstream", + "subjects", + "is_flow" + ] + }, "Group": { "type": "object", "properties": { @@ -18850,12 +24873,19 @@ }, "username": { "type": "string" + }, + "color": { + "type": "string" + }, + "operator_settings": { + "$ref": "#/components/schemas/OperatorSettings" } }, "required": [ "id", "name", - "username" + "username", + "color" ] } } @@ -18876,6 +24906,9 @@ }, "username": { "type": "string" + }, + "color": { + "type": "string" } }, "required": [ @@ -18897,6 +24930,9 @@ }, "domain": { "type": "string" + }, + "color": { + "type": "string" } }, "required": [ @@ -18944,6 +24980,9 @@ "super_admin": { "type": "boolean" }, + "devops": { + "type": "boolean" + }, "verified": { "type": "boolean" }, @@ -18974,6 +25013,14 @@ }, { "$ref": "#/components/schemas/FlowMetadata" + }, + { + "type": "object", + "properties": { + "lock_error_logs": { + "type": "string" + } + } } ] }, @@ -19028,6 +25075,9 @@ }, "visible_to_runner_only": { "type": "boolean" + }, + "on_behalf_of_email": { + "type": "string" } }, "required": [ @@ -19066,6 +25116,9 @@ }, "visible_to_runner_only": { "type": "boolean" + }, + "on_behalf_of_email": { + "type": "string" } }, "required": [ @@ -19135,6 +25188,20 @@ "type": "object" } }, + "allowed_s3_keys": { + "type": "array", + "items": { + "type": "object", + "properties": { + "s3_path": { + "type": "string" + }, + "resource": { + "type": "string" + } + } + } + }, "execution_mode": { "type": "string", "enum": [ @@ -19189,6 +25256,9 @@ "publisher", "anonymous" ] + }, + "raw_app": { + "type": "boolean" } }, "required": [ @@ -19287,6 +25357,9 @@ "additionalProperties": { "type": "boolean" } + }, + "custom_path": { + "type": "string" } }, "required": [ @@ -19404,16 +25477,13 @@ ] }, "HubScriptKind": { - "name": "kind", - "schema": { - "type": "string", - "enum": [ - "script", - "failure", - "trigger", - "approval" - ] - } + "type": "string", + "enum": [ + "script", + "failure", + "trigger", + "approval" + ] }, "PolarsClientKwargs": { "type": "object", @@ -19588,7 +25658,8 @@ "resourcetype", "schedule", "user", - "group" + "group", + "trigger" ] } }, @@ -19619,7 +25690,8 @@ "app", "resource", "variable", - "secret" + "secret", + "trigger" ] } } @@ -19677,7 +25749,8 @@ "resourcetype", "schedule", "user", - "group" + "group", + "trigger" ] } } @@ -19775,25 +25848,7 @@ "type": "string" }, "language": { - "type": "string", - "enum": [ - "python3", - "deno", - "go", - "bash", - "powershell", - "postgresql", - "mysql", - "bigquery", - "snowflake", - "mssql", - "graphql", - "nativets", - "bun", - "php", - "rust", - "ansible" - ] + "$ref": "#/components/schemas/ScriptLang" } }, "required": [ @@ -20000,6 +26055,286 @@ "type": "boolean", "nullable": true, "description": "Acknowledgment status of the alert, can be true, false, or null if not set" + }, + "workspace_id": { + "type": "string", + "nullable": true, + "description": "Workspace id if the alert is in the scope of a workspace" + } + } + }, + "CaptureTriggerKind": { + "type": "string", + "enum": [ + "webhook", + "http", + "websocket", + "kafka", + "email", + "nats", + "postgres", + "sqs", + "mqtt", + "gcp" + ] + }, + "Capture": { + "type": "object", + "properties": { + "trigger_kind": { + "$ref": "#/components/schemas/CaptureTriggerKind" + }, + "main_args": {}, + "preprocessor_args": {}, + "id": { + "type": "integer" + }, + "created_at": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "trigger_kind", + "main_args", + "preprocessor_args", + "id", + "created_at" + ] + }, + "CaptureConfig": { + "type": "object", + "properties": { + "trigger_config": {}, + "trigger_kind": { + "$ref": "#/components/schemas/CaptureTriggerKind" + }, + "error": { + "type": "string" + }, + "last_server_ping": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "trigger_kind" + ] + }, + "OperatorSettings": { + "nullable": true, + "type": "object", + "required": [ + "runs", + "schedules", + "resources", + "variables", + "triggers", + "audit_logs", + "groups", + "folders", + "workers" + ], + "properties": { + "runs": { + "type": "boolean", + "description": "Whether operators can view runs" + }, + "schedules": { + "type": "boolean", + "description": "Whether operators can view schedules" + }, + "resources": { + "type": "boolean", + "description": "Whether operators can view resources" + }, + "variables": { + "type": "boolean", + "description": "Whether operators can view variables" + }, + "audit_logs": { + "type": "boolean", + "description": "Whether operators can view audit logs" + }, + "triggers": { + "type": "boolean", + "description": "Whether operators can view triggers" + }, + "groups": { + "type": "boolean", + "description": "Whether operators can view groups page" + }, + "folders": { + "type": "boolean", + "description": "Whether operators can view folders page" + }, + "workers": { + "type": "boolean", + "description": "Whether operators can view workers page" + } + } + }, + "TeamInfo": { + "type": "object", + "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": { + "$ref": "#/components/schemas/ChannelInfo" + } + } + } + }, + "ChannelInfo": { + "type": "object", + "required": [ + "channel_id", + "channel_name", + "tenant_id", + "service_url" + ], + "properties": { + "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/" + } + } + }, + "GithubInstallations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string" + }, + "installation_id": { + "type": "number" + }, + "account_id": { + "type": "string" + }, + "repositories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "url" + ] + } + } + }, + "required": [ + "installation_id", + "account_id", + "repositories" + ] + } + }, + "WorkspaceGithubInstallation": { + "type": "object", + "properties": { + "account_id": { + "type": "string" + }, + "installation_id": { + "type": "number" + } + }, + "required": [ + "account_id", + "installation_id" + ] + }, + "S3Object": { + "type": "object", + "properties": { + "s3": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "storage": { + "type": "string" + }, + "presigned": { + "type": "string" + } + }, + "required": [ + "s3" + ] + }, + "TeamsChannel": { + "type": "object", + "required": [ + "team_id", + "team_name", + "channel_id", + "channel_name" + ], + "properties": { + "team_id": { + "type": "string", + "description": "Microsoft Teams team ID", + "minLength": 1 + }, + "team_name": { + "type": "string", + "description": "Microsoft Teams team name", + "minLength": 1 + }, + "channel_id": { + "type": "string", + "description": "Microsoft Teams channel ID", + "minLength": 1 + }, + "channel_name": { + "type": "string", + "description": "Microsoft Teams channel name", + "minLength": 1 } } }, @@ -20037,7 +26372,7 @@ "type" ] }, - "InputTransform": { + "schemas-InputTransform": { "oneOf": [ { "$ref": "#/components/schemas/StaticTransform" @@ -20060,7 +26395,7 @@ "input_transforms": { "type": "object", "additionalProperties": { - "$ref": "#/components/schemas/InputTransform" + "$ref": "#/components/schemas/schemas-InputTransform" } }, "content": { @@ -20080,6 +26415,7 @@ "bigquery", "snowflake", "mssql", + "oracledb", "graphql", "nativets", "php" @@ -20126,7 +26462,7 @@ "input_transforms": { "type": "object", "additionalProperties": { - "$ref": "#/components/schemas/InputTransform" + "$ref": "#/components/schemas/schemas-InputTransform" } }, "path": { @@ -20160,7 +26496,7 @@ "input_transforms": { "type": "object", "additionalProperties": { - "$ref": "#/components/schemas/InputTransform" + "$ref": "#/components/schemas/schemas-InputTransform" } }, "path": { @@ -20189,32 +26525,10 @@ "$ref": "#/components/schemas/FlowModuleValue" }, "stop_after_if": { - "type": "object", - "properties": { - "skip_if_stopped": { - "type": "boolean" - }, - "expr": { - "type": "string" - } - }, - "required": [ - "expr" - ] + "$ref": "#/components/schemas/StopAfterIf" }, "stop_after_all_iters_if": { - "type": "object", - "properties": { - "skip_if_stopped": { - "type": "boolean" - }, - "expr": { - "type": "string" - } - }, - "required": [ - "expr" - ] + "$ref": "#/components/schemas/StopAfterIf" }, "skip_if": { "type": "object", @@ -20228,7 +26542,7 @@ ] }, "sleep": { - "$ref": "#/components/schemas/InputTransform" + "$ref": "#/components/schemas/schemas-InputTransform" }, "cache_ttl": { "type": "number" @@ -20272,7 +26586,7 @@ "type": "boolean" }, "user_groups_required": { - "$ref": "#/components/schemas/InputTransform" + "$ref": "#/components/schemas/schemas-InputTransform" }, "self_approval_disabled": { "type": "boolean" @@ -20310,7 +26624,7 @@ } }, "iterator": { - "$ref": "#/components/schemas/InputTransform" + "$ref": "#/components/schemas/schemas-InputTransform" }, "skip_failures": { "type": "boolean" @@ -20515,6 +26829,23 @@ } } }, + "StopAfterIf": { + "type": "object", + "properties": { + "skip_if_stopped": { + "type": "boolean" + }, + "expr": { + "type": "string" + }, + "error_message": { + "type": "string" + } + }, + "required": [ + "expr" + ] + }, "Retry": { "type": "object", "properties": { diff --git a/backend/windmill-api/openapi-deref.yaml b/backend/windmill-api/openapi-deref.yaml index c8893f824c..4c13a9c7f8 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.423.2 + version: 1.492.1 title: Windmill API contact: name: Windmill Team @@ -87,7 +87,7 @@ paths: - name: id in: path required: true - schema: &ref_30 + schema: &ref_34 type: integer responses: '200': @@ -233,24 +233,24 @@ paths: - name: before description: filter on started before (inclusive) timestamp in: query - schema: &ref_120 + schema: &ref_183 type: string format: date-time - name: after description: filter on created after (exclusive) timestamp in: query - schema: &ref_121 + schema: &ref_184 type: string format: date-time - name: username description: filter on exact username of user in: query - schema: &ref_130 + schema: &ref_189 type: string - name: operation description: filter on exact or prefix name of operation in: query - schema: &ref_131 + schema: &ref_190 type: string - name: operations in: query @@ -265,18 +265,23 @@ paths: - name: resource description: filter on exact or prefix name of resource in: query - schema: &ref_132 + schema: &ref_191 type: string - name: action_kind description: filter on type of operation in: query - schema: &ref_133 + schema: &ref_192 type: string enum: - Create - Update - Delete - Execute + - name: all_workspaces + in: query + description: get audit logs for all workspaces + schema: + type: boolean responses: '200': description: a list of audit logs @@ -302,12 +307,12 @@ paths: application/json: schema: type: object - properties: &ref_145 + properties: &ref_210 email: type: string password: type: string - required: &ref_146 + required: &ref_211 - email - password responses: @@ -375,6 +380,8 @@ paths: type: string is_admin: type: boolean + name: + type: string is_super_admin: type: boolean created_at: @@ -430,7 +437,7 @@ paths: application/json: schema: type: object - properties: &ref_147 + properties: &ref_212 is_admin: type: boolean operator: @@ -458,7 +465,7 @@ paths: - name: path in: path required: true - schema: &ref_23 + schema: &ref_26 type: string responses: '200': @@ -611,6 +618,8 @@ paths: properties: is_super_admin: type: boolean + is_devops: + type: boolean name: type: string responses: @@ -792,6 +801,44 @@ paths: text/plain: schema: type: string + /github_app/connected_repositories: + get: + summary: get connected repositories + operationId: getGlobalConnectedRepositories + tags: + - git_sync + responses: + '200': + description: connected repositories + content: + application/json: + schema: + type: array + items: &ref_331 + type: object + properties: + workspace_id: + type: string + installation_id: + type: number + account_id: + type: string + repositories: + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + required: + - name + - url + required: + - installation_id + - account_id + - repositories /workspaces/list: get: summary: list all workspaces visible to me @@ -816,6 +863,8 @@ paths: type: string domain: type: string + color: + type: string required: &ref_8 - id - name @@ -846,7 +895,7 @@ paths: application/json: schema: type: object - properties: &ref_185 + properties: &ref_280 email: type: string workspaces: @@ -860,11 +909,55 @@ paths: type: string username: type: string + color: + type: string + operator_settings: + nullable: true + type: object + required: &ref_12 + - runs + - schedules + - resources + - variables + - triggers + - audit_logs + - groups + - folders + - workers + properties: &ref_13 + runs: + type: boolean + description: Whether operators can view runs + schedules: + type: boolean + description: Whether operators can view schedules + resources: + type: boolean + description: Whether operators can view resources + variables: + type: boolean + description: Whether operators can view variables + audit_logs: + type: boolean + description: Whether operators can view audit logs + triggers: + type: boolean + description: Whether operators can view triggers + groups: + type: boolean + description: Whether operators can view groups page + folders: + type: boolean + description: Whether operators can view folders page + workers: + type: boolean + description: Whether operators can view workers page required: - id - name - username - required: &ref_186 + - color + required: &ref_281 - email - workspaces /workspaces/list_as_superadmin: @@ -906,14 +999,16 @@ paths: application/json: schema: type: object - properties: &ref_187 + properties: &ref_282 id: type: string name: type: string username: type: string - required: &ref_188 + color: + type: string + required: &ref_283 - id - name responses: @@ -1143,29 +1238,46 @@ paths: content: application/json: schema: - type: array - items: - type: object - properties: &ref_230 - id: - type: integer - description: Unique identifier for the alert - alert_type: - type: string - description: Type of alert (e.g., critical_error) - message: - type: string - description: The message content of the alert - created_at: - type: string - format: date-time - description: Time when the alert was created - acknowledged: - type: boolean - nullable: true - description: >- - Acknowledgment status of the alert, can be true, false, - or null if not set + type: object + properties: + alerts: + type: array + items: + type: object + properties: &ref_29 + id: + type: integer + description: Unique identifier for the alert + alert_type: + type: string + description: Type of alert (e.g., critical_error) + message: + type: string + description: The message content of the alert + created_at: + type: string + format: date-time + description: Time when the alert was created + acknowledged: + type: boolean + nullable: true + description: >- + Acknowledgment status of the alert, can be true, + false, or null if not set + workspace_id: + type: string + nullable: true + description: >- + Workspace id if the alert is in the scope of a + workspace + total_rows: + type: integer + description: Total number of rows matching the query. + example: 100 + total_pages: + type: integer + description: Total number of pages based on the page size. + example: 10 /settings/critical_alerts/{id}/acknowledge: post: summary: Acknowledge a critical alert @@ -1356,12 +1468,12 @@ paths: type: array items: type: object - properties: &ref_223 + properties: &ref_318 name: type: string value: type: object - required: &ref_224 + required: &ref_319 - name - value /users/email: @@ -1383,9 +1495,15 @@ paths: operationId: refreshUserToken tags: - user + parameters: + - name: if_expiring_in_less_than_s + in: query + required: false + schema: + type: integer responses: '200': - description: free usage + description: new token content: text/plain: schema: @@ -1502,7 +1620,7 @@ paths: application/json: schema: type: object - properties: &ref_12 + properties: &ref_14 email: type: string login_type: @@ -1512,6 +1630,8 @@ paths: - github super_admin: type: boolean + devops: + type: boolean verified: type: boolean name: @@ -1522,7 +1642,7 @@ paths: type: string operator_only: type: boolean - required: &ref_13 + required: &ref_15 - email - login_type - super_admin @@ -1542,7 +1662,7 @@ paths: type: array items: type: object - properties: &ref_14 + properties: &ref_16 workspace_id: type: string email: @@ -1551,7 +1671,7 @@ paths: type: boolean operator: type: boolean - required: &ref_15 + required: &ref_17 - workspace_id - email - is_admin @@ -1576,6 +1696,154 @@ paths: type: object properties: *ref_10 required: *ref_11 + /w/{workspace}/github_app/token: + post: + summary: get github app token + operationId: getGithubAppToken + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: jwt job token + required: true + content: + application/json: + schema: + type: object + properties: + job_token: + type: string + required: + - job_token + responses: + '200': + description: github app token + content: + application/json: + schema: + type: object + properties: + token: + type: string + required: + - token + /w/{workspace}/github_app/install_from_workspace: + post: + tags: + - Git Sync + summary: Install a GitHub installation from another workspace + operationId: installFromWorkspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + source_workspace_id: + type: string + description: The ID of the workspace containing the installation to copy + installation_id: + type: number + description: The ID of the GitHub installation to copy + required: + - source_workspace_id + - installation_id + responses: + '200': + description: Installation successfully copied + /w/{workspace}/github_app/installation/{installation_id}: + delete: + summary: Delete a GitHub installation from a workspace + operationId: deleteFromWorkspace + description: >- + Removes a GitHub installation from the specified workspace. Requires + admin privileges. + tags: + - Git Sync + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: installation_id + in: path + required: true + schema: + type: integer + format: int64 + description: The ID of the GitHub installation to delete + responses: + '200': + description: Installation successfully deleted + /w/{workspace}/github_app/export/{installationId}: + get: + summary: Export GitHub installation JWT token + description: >- + Exports the JWT token for a specific GitHub installation in the + workspace + operationId: exportInstallation + tags: + - Git Sync + parameters: + - name: workspace + in: path + required: true + schema: + type: string + - name: installationId + in: path + required: true + schema: + type: integer + responses: + '200': + description: Successfully exported the JWT token + content: + application/json: + schema: + type: object + properties: + jwt_token: + type: string + /w/{workspace}/github_app/import: + post: + summary: Import GitHub installation from JWT token + description: >- + Imports a GitHub installation from a JWT token exported from another + instance + operationId: importInstallation + tags: + - Git Sync + parameters: + - name: workspace + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - jwt_token + properties: + jwt_token: + type: string + responses: + '200': + description: Successfully imported the installation /users/accept_invite: post: summary: accept invite to workspace @@ -1886,6 +2154,32 @@ paths: text/plain: schema: type: string + /w/{workspace}/workspaces/change_workspace_color: + post: + summary: change workspace id + operationId: changeWorkspaceColor + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + content: + application/json: + schema: + type: object + properties: + color: + type: string + responses: + '200': + description: status + content: + text/plain: + schema: + type: string /w/{workspace}/users/whois/{username}: get: summary: whois @@ -1911,6 +2205,36 @@ paths: type: object properties: *ref_10 required: *ref_11 + /w/{workspace}/workspaces/operator_settings: + post: + operationId: updateOperatorSettings + summary: Update operator settings for a workspace + description: >- + Updates the operator settings for a specific workspace. Requires + workspace admin privileges. + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + required: true + content: + application/json: + schema: + nullable: true + type: object + required: *ref_12 + properties: *ref_13 + responses: + '200': + description: Operator settings updated successfully + content: + text/plain: + schema: + type: string /users/exists/{email}: get: summary: exists email @@ -1959,8 +2283,8 @@ paths: type: array items: type: object - properties: *ref_12 - required: *ref_13 + properties: *ref_14 + required: *ref_15 /w/{workspace}/workspaces/list_pending_invites: get: summary: list pending invites for a workspace @@ -1981,8 +2305,8 @@ paths: type: array items: type: object - properties: *ref_14 - required: *ref_15 + properties: *ref_16 + required: *ref_17 /w/{workspace}/workspaces/get_settings: get: summary: get settings @@ -2010,6 +2334,12 @@ paths: type: string slack_command_script: type: string + teams_team_id: + type: string + teams_command_script: + type: string + teams_team_name: + type: string auto_invite_domain: type: string auto_invite_operator: @@ -2018,36 +2348,64 @@ paths: type: boolean plan: type: string - automatic_billing: - type: boolean customer_id: type: string webhook: type: string deploy_to: type: string - ai_resource: + ai_config: type: object - properties: &ref_16 - path: - type: string - provider: - type: string - required: &ref_17 - - path - - provider - code_completion_enabled: - type: boolean + properties: &ref_20 + providers: + type: object + additionalProperties: + type: object + properties: &ref_197 + resource_path: + type: string + models: + type: array + items: + type: string + required: &ref_198 + - resource_path + - models + default_model: + type: object + properties: &ref_18 + model: + type: string + provider: + type: string + enum: &ref_196 + - openai + - azure_openai + - anthropic + - mistral + - deepseek + - googleai + - groq + - openrouter + - togetherai + - customai + required: &ref_19 + - model + - provider + code_completion_model: + type: object + properties: *ref_18 + required: *ref_19 error_handler: type: string error_handler_extra_args: type: object - additionalProperties: &ref_18 {} + additionalProperties: &ref_21 {} error_handler_muted_on_cancel: type: boolean large_file_storage: type: object - properties: &ref_19 + properties: &ref_22 type: type: string enum: @@ -2081,7 +2439,7 @@ paths: type: boolean git_sync: type: object - properties: &ref_20 + properties: &ref_23 include_path: type: array items: @@ -2102,11 +2460,12 @@ paths: - schedule - user - group + - trigger repositories: type: array items: type: object - properties: &ref_207 + properties: &ref_302 script_path: type: string git_repo_resource_path: @@ -2131,12 +2490,13 @@ paths: - schedule - user - group - required: &ref_208 + - trigger + required: &ref_303 - script_path - git_repo_resource_path deploy_ui: type: object - properties: &ref_21 + properties: &ref_24 include_path: type: array items: @@ -2152,11 +2512,12 @@ paths: - resource - variable - secret + - trigger default_app: type: string default_scripts: type: object - properties: &ref_22 + properties: &ref_25 order: type: array items: @@ -2168,9 +2529,16 @@ paths: default_script_content: additionalProperties: type: string + mute_critical_alerts: + type: boolean + color: + type: string + operator_settings: + nullable: true + type: object + required: *ref_12 + properties: *ref_13 required: - - code_completion_enabled - - automatic_billing - error_handler_muted_on_cancel /w/{workspace}/workspaces/get_deploy_to: get: @@ -2234,17 +2602,40 @@ paths: type: boolean usage: type: number - seats: - type: number - automatic_billing: - type: boolean + owner: + type: string + status: + type: string required: - premium - - automatic_billing - /w/{workspace}/workspaces/set_automatic_billing: + - owner + /w/{workspace}/workspaces/threshold_alert: + get: + summary: get threshold alert info + operationId: getThresholdAlert + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: status + content: + application/json: + schema: + type: object + properties: + threshold_alert_amount: + type: number + last_alert_sent: + type: string + format: date-time post: - summary: set automatic billing - operationId: setAutomaticBilling + summary: set threshold alert info + operationId: setThresholdAlert tags: - workspace parameters: @@ -2253,19 +2644,15 @@ paths: required: true schema: *ref_0 requestBody: - description: automatic billing + description: threshold alert info required: true content: application/json: schema: type: object properties: - automatic_billing: - type: boolean - seats: + threshold_alert_amount: type: number - required: - - automatic_billing responses: '200': description: status @@ -2301,6 +2688,118 @@ paths: text/plain: schema: type: string + /w/{workspace}/workspaces/edit_teams_command: + post: + summary: edit teams command + operationId: editTeamsCommand + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: WorkspaceInvite + required: true + content: + application/json: + schema: + type: object + properties: + slack_command_script: + type: string + responses: + '200': + description: status + content: + text/plain: + schema: + type: string + /w/{workspace}/workspaces/available_teams_ids: + get: + summary: list available teams ids + operationId: listAvailableTeamsIds + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: status + content: + application/json: + schema: + type: array + items: + type: object + properties: + team_name: + type: string + team_id: + type: string + /w/{workspace}/workspaces/available_teams_channels: + get: + summary: list available teams channels + operationId: listAvailableTeamsChannels + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: status + 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 + /w/{workspace}/workspaces/connect_teams: + post: + summary: connect teams + operationId: connectTeams + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: connect teams + required: true + content: + application/json: + schema: + type: object + properties: + team_id: + type: string + team_name: + type: string + responses: + '200': + description: status + content: + text/plain: + schema: + type: string /w/{workspace}/workspaces/run_slack_message_test_job: post: summary: run a job that sends a message to Slack @@ -2336,6 +2835,41 @@ paths: properties: job_uuid: type: string + /w/{workspace}/workspaces/run_teams_message_test_job: + post: + summary: run a job that sends a message to Teams + operationId: runTeamsMessageTestJob + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: path to hub script to run and its corresponding args + required: true + content: + application/json: + schema: + type: object + properties: + hub_script_path: + type: string + channel: + type: string + test_msg: + type: string + responses: + '200': + description: status + content: + text/json: + schema: + type: object + properties: + job_uuid: + type: string /w/{workspace}/workspaces/edit_deploy_to: post: summary: edit deploy to @@ -2441,15 +2975,7 @@ paths: application/json: schema: type: object - required: - - code_completion_enabled - properties: - ai_resource: - type: object - properties: *ref_16 - required: *ref_17 - code_completion_enabled: - type: boolean + properties: *ref_20 responses: '200': description: status @@ -2472,20 +2998,10 @@ paths: '200': description: status content: - text/plain: + application/json: schema: type: object - properties: - ai_provider: - type: string - exists_ai_resource: - type: boolean - code_completion_enabled: - type: boolean - required: - - ai_provider - - exists_ai_resource - - code_completion_enabled + properties: *ref_20 /w/{workspace}/workspaces/edit_error_handler: post: summary: edit error handler @@ -2509,7 +3025,7 @@ paths: type: string error_handler_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 error_handler_muted_on_cancel: type: boolean responses: @@ -2540,7 +3056,7 @@ paths: properties: large_file_storage: type: object - properties: *ref_19 + properties: *ref_22 responses: '200': description: status @@ -2568,7 +3084,7 @@ paths: properties: git_sync_settings: type: object - properties: *ref_20 + properties: *ref_23 responses: '200': description: status @@ -2596,7 +3112,7 @@ paths: properties: deploy_ui_settings: type: object - properties: *ref_21 + properties: *ref_24 responses: '200': description: status @@ -2648,7 +3164,7 @@ paths: application/json: schema: type: object - properties: *ref_22 + properties: *ref_25 responses: '200': description: status @@ -2673,7 +3189,7 @@ paths: application/json: schema: type: object - properties: *ref_22 + properties: *ref_25 /w/{workspace}/workspaces/set_environment_variable: post: summary: set environment variable @@ -2799,7 +3315,7 @@ paths: application/json: schema: type: object - properties: *ref_19 + properties: *ref_22 /w/{workspace}/workspaces/usage: get: summary: get usage @@ -2841,9 +3357,27 @@ paths: type: boolean websocket_used: type: boolean + kafka_used: + type: boolean + nats_used: + type: boolean + postgres_used: + type: boolean + mqtt_used: + type: boolean + gcp_used: + type: boolean + sqs_used: + type: boolean required: - http_routes_used - websocket_used + - kafka_used + - nats_used + - postgres_used + - mqtt_used + - gcp_used + - sqs_used /w/{workspace}/users/list: get: summary: list users @@ -2886,7 +3420,7 @@ paths: type: array items: type: object - properties: &ref_144 + properties: &ref_209 email: type: string executions: @@ -2947,7 +3481,7 @@ paths: application/json: schema: type: object - properties: &ref_148 + properties: &ref_213 label: type: string expiration: @@ -2979,7 +3513,7 @@ paths: application/json: schema: type: object - properties: &ref_149 + properties: &ref_214 label: type: string expiration: @@ -2989,7 +3523,7 @@ paths: type: string workspace_id: type: string - required: &ref_150 + required: &ref_215 - impersonate_email responses: '201': @@ -3045,7 +3579,7 @@ paths: type: array items: type: object - properties: &ref_40 + properties: &ref_47 label: type: string expiration: @@ -3065,7 +3599,7 @@ paths: type: string email: type: string - required: &ref_41 + required: &ref_48 - token_prefix - created_at - last_used_at @@ -3114,7 +3648,7 @@ paths: application/json: schema: type: object - properties: &ref_153 + properties: &ref_218 path: type: string value: @@ -3130,7 +3664,7 @@ paths: expires_at: type: string format: date-time - required: &ref_154 + required: &ref_219 - path - value - is_secret @@ -3181,7 +3715,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: variable deleted @@ -3203,7 +3737,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 - name: already_encrypted in: query schema: @@ -3215,7 +3749,7 @@ paths: application/json: schema: type: object - properties: &ref_155 + properties: &ref_220 path: type: string value: @@ -3245,7 +3779,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 - name: decrypt_secret description: | ask to decrypt secret if this variable is secret @@ -3267,7 +3801,7 @@ paths: application/json: schema: type: object - properties: &ref_24 + properties: &ref_27 workspace_id: type: string path: @@ -3297,7 +3831,7 @@ paths: expires_at: type: string format: date-time - required: &ref_25 + required: &ref_28 - workspace_id - path - is_secret @@ -3316,7 +3850,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: variable @@ -3338,7 +3872,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: variable @@ -3378,8 +3912,8 @@ paths: type: array items: type: object - properties: *ref_24 - required: *ref_25 + properties: *ref_27 + required: *ref_28 /w/{workspace}/variables/list_contextual: get: summary: list contextual variables @@ -3400,7 +3934,7 @@ paths: type: array items: type: object - properties: &ref_151 + properties: &ref_216 name: type: string value: @@ -3409,11 +3943,141 @@ paths: type: string is_custom: type: boolean - required: &ref_152 + required: &ref_217 - name - value - description - is_custom + /w/{workspace}/workspaces/critical_alerts: + get: + summary: Get all critical alerts for this workspace + operationId: workspaceGetCriticalAlerts + tags: + - setting + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - in: query + name: page + schema: + type: integer + default: 1 + description: The page number to retrieve (minimum value is 1) + - in: query + name: page_size + schema: + type: integer + default: 10 + maximum: 100 + description: Number of alerts per page (maximum is 100) + - in: query + name: acknowledged + schema: + type: boolean + nullable: true + description: >- + Filter by acknowledgment status; true for acknowledged, false for + unacknowledged, and omit for all alerts + responses: + '200': + description: Successfully retrieved all critical alerts + content: + application/json: + schema: + type: object + properties: + alerts: + type: array + items: + type: object + properties: *ref_29 + total_rows: + type: integer + description: Total number of rows matching the query. + example: 100 + total_pages: + type: integer + description: Total number of pages based on the page size. + example: 10 + /w/{workspace}/workspaces/critical_alerts/{id}/acknowledge: + post: + summary: Acknowledge a critical alert for this workspace + operationId: workspaceAcknowledgeCriticalAlert + tags: + - setting + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - in: path + name: id + required: true + schema: + type: integer + description: The ID of the critical alert to acknowledge + responses: + '200': + description: Successfully acknowledged the critical alert + content: + application/json: + schema: + type: string + example: Critical alert acknowledged + /w/{workspace}/workspaces/critical_alerts/acknowledge_all: + post: + summary: Acknowledge all unacknowledged critical alerts for this workspace + operationId: workspaceAcknowledgeAllCriticalAlerts + tags: + - setting + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: Successfully acknowledged all unacknowledged critical alerts. + content: + application/json: + schema: + type: string + example: All unacknowledged critical alerts acknowledged + /w/{workspace}/workspaces/critical_alerts/mute: + post: + summary: Mute critical alert UI for this workspace + operationId: workspaceMuteCriticalAlertsUI + tags: + - setting + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: Boolean flag to mute critical alerts. + required: true + content: + application/json: + schema: + type: object + properties: + mute_critical_alerts: + type: boolean + description: Whether critical alerts should be muted. + example: true + responses: + '200': + description: Successfully updated mute critical alert settings. + content: + application/json: + schema: + type: string + example: >- + Updated mute critical alert UI settings for workspace: + workspace_id /oauth/login_callback/{client_name}: post: security: [] @@ -3425,7 +4089,7 @@ paths: - name: client_name in: path required: true - schema: &ref_26 + schema: &ref_30 type: string requestBody: description: Partially filled script @@ -3526,7 +4190,7 @@ paths: - name: client_name in: path required: true - schema: *ref_26 + schema: *ref_30 requestBody: description: code endpoint required: true @@ -3549,7 +4213,7 @@ paths: application/json: schema: type: object - properties: &ref_200 + properties: &ref_295 access_token: type: string expires_in: @@ -3560,7 +4224,7 @@ paths: type: array items: type: string - required: &ref_201 + required: &ref_296 - access_token /w/{workspace}/oauth/create_account: post: @@ -3611,7 +4275,7 @@ paths: - name: id in: path required: true - schema: &ref_27 + schema: &ref_31 type: integer requestBody: description: variable path @@ -3646,7 +4310,7 @@ paths: - name: id in: path required: true - schema: *ref_27 + schema: *ref_31 responses: '200': description: disconnected client @@ -3672,6 +4336,24 @@ paths: text/plain: schema: type: string + /w/{workspace}/oauth/disconnect_teams: + post: + summary: disconnect teams + operationId: disconnectTeams + tags: + - oauth + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: disconnected teams + content: + text/plain: + schema: + type: string /oauth/list_logins: get: summary: list oauth logins @@ -3743,6 +4425,95 @@ 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_327 + - team_id + - team_name + - channels + properties: &ref_328 + 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_329 + - channel_id + - channel_name + - tenant_id + - service_url + properties: &ref_330 + 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 + description: Respond to a Microsoft Teams activity after a workspace command is run + operationId: sendMessageToConversation + tags: + - teams + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - conversation_id + - text + properties: + conversation_id: + type: string + description: The ID of the Teams conversation/activity + success: + type: boolean + description: Used for styling the card conditionally + default: true + text: + type: string + description: The message text to be sent in the Teams card + card_block: + type: object + description: The card block to be sent in the Teams card + responses: + '200': + description: Activity processed successfully /w/{workspace}/resources/create: post: summary: create resource @@ -3765,7 +4536,7 @@ paths: application/json: schema: type: object - properties: &ref_162 + properties: &ref_227 path: type: string value: {} @@ -3773,7 +4544,7 @@ paths: type: string resource_type: type: string - required: &ref_163 + required: &ref_228 - path - value - resource_type @@ -3798,7 +4569,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: resource deleted @@ -3820,7 +4591,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 requestBody: description: updated resource required: true @@ -3828,7 +4599,7 @@ paths: application/json: schema: type: object - properties: &ref_164 + properties: &ref_229 path: type: string description: @@ -3855,7 +4626,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 requestBody: description: updated resource required: true @@ -3886,7 +4657,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: resource @@ -3894,7 +4665,7 @@ paths: application/json: schema: type: object - properties: &ref_165 + properties: &ref_230 workspace_id: type: string path: @@ -3915,7 +4686,7 @@ paths: edited_at: type: string format: date-time - required: &ref_166 + required: &ref_231 - path - resource_type - is_oauth @@ -3933,7 +4704,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 - name: job_id description: job id in: query @@ -3960,7 +4731,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: resource value @@ -3981,7 +4752,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: does resource exists @@ -4031,7 +4802,7 @@ paths: type: array items: type: object - properties: &ref_167 + properties: &ref_232 workspace_id: type: string path: @@ -4062,7 +4833,7 @@ paths: edited_at: type: string format: date-time - required: &ref_168 + required: &ref_233 - path - resource_type - is_oauth @@ -4109,7 +4880,7 @@ paths: - name: name in: path required: true - schema: &ref_103 + schema: &ref_163 type: string responses: '200': @@ -4146,7 +4917,7 @@ paths: application/json: schema: type: object - properties: &ref_28 + properties: &ref_32 workspace_id: type: string name: @@ -4161,7 +4932,7 @@ paths: format: date-time format_extension: type: string - required: &ref_29 + required: &ref_33 - name responses: '201': @@ -4201,7 +4972,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: resource_type deleted @@ -4223,7 +4994,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 requestBody: description: updated resource_type required: true @@ -4231,7 +5002,7 @@ paths: application/json: schema: type: object - properties: &ref_169 + properties: &ref_234 schema: {} description: type: string @@ -4256,7 +5027,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: resource_type deleted @@ -4264,8 +5035,8 @@ paths: application/json: schema: type: object - properties: *ref_28 - required: *ref_29 + properties: *ref_32 + required: *ref_33 /w/{workspace}/resources/type/exists/{path}: get: summary: does resource_type exists @@ -4280,7 +5051,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: does resource_type exist @@ -4308,8 +5079,8 @@ paths: type: array items: type: object - properties: *ref_28 - required: *ref_29 + properties: *ref_32 + required: *ref_33 /w/{workspace}/resources/type/listnames: get: summary: list resource_types names @@ -4448,7 +5219,7 @@ paths: - name: id in: path required: true - schema: *ref_30 + schema: *ref_34 responses: '200': description: flow @@ -4459,51 +5230,51 @@ paths: properties: flow: type: object - properties: &ref_54 + properties: &ref_61 summary: type: string description: type: string value: type: object - properties: &ref_66 + properties: &ref_78 modules: type: array items: type: object - properties: &ref_33 + properties: &ref_37 id: type: string value: - oneOf: &ref_251 + oneOf: &ref_352 - type: object - properties: &ref_235 + properties: &ref_336 input_transforms: type: object additionalProperties: - oneOf: &ref_31 + oneOf: &ref_35 - type: object - properties: &ref_231 + properties: &ref_332 value: {} type: type: string enum: - javascript - required: &ref_232 + required: &ref_333 - expr - type - type: object - properties: &ref_233 + properties: &ref_334 expr: type: string type: type: string enum: - javascript - required: &ref_234 + required: &ref_335 - expr - type - discriminator: &ref_32 + discriminator: &ref_36 propertyName: type mapping: static: '#/components/schemas/StaticTransform' @@ -4524,6 +5295,7 @@ paths: - bigquery - snowflake - mssql + - oracledb - graphql - nativets - php @@ -4545,18 +5317,18 @@ paths: type: string is_trigger: type: boolean - required: &ref_236 + required: &ref_337 - type - content - language - input_transforms - type: object - properties: &ref_237 + properties: &ref_338 input_transforms: type: object additionalProperties: - oneOf: *ref_31 - discriminator: *ref_32 + oneOf: *ref_35 + discriminator: *ref_36 path: type: string hash: @@ -4569,40 +5341,40 @@ paths: type: string is_trigger: type: boolean - required: &ref_238 + required: &ref_339 - type - path - input_transforms - type: object - properties: &ref_239 + properties: &ref_340 input_transforms: type: object additionalProperties: - oneOf: *ref_31 - discriminator: *ref_32 + oneOf: *ref_35 + discriminator: *ref_36 path: type: string type: type: string enum: - flow - required: &ref_240 + required: &ref_341 - type - path - input_transforms - type: object - properties: &ref_241 + properties: &ref_342 modules: type: array items: type: object - properties: *ref_33 - required: &ref_34 + properties: *ref_37 + required: &ref_38 - value - id iterator: - oneOf: *ref_31 - discriminator: *ref_32 + oneOf: *ref_35 + discriminator: *ref_36 skip_failures: type: boolean type: @@ -4613,19 +5385,19 @@ paths: type: boolean parallelism: type: integer - required: &ref_242 + required: &ref_343 - modules - iterator - skip_failures - type - type: object - properties: &ref_243 + properties: &ref_344 modules: type: array items: type: object - properties: *ref_33 - required: *ref_34 + properties: *ref_37 + required: *ref_38 skip_failures: type: boolean type: @@ -4636,12 +5408,12 @@ paths: type: boolean parallelism: type: integer - required: &ref_244 + required: &ref_345 - modules - skip_failures - type - type: object - properties: &ref_245 + properties: &ref_346 branches: type: array items: @@ -4655,8 +5427,8 @@ paths: type: array items: type: object - properties: *ref_33 - required: *ref_34 + properties: *ref_37 + required: *ref_38 required: - modules - expr @@ -4664,20 +5436,20 @@ paths: type: array items: type: object - properties: *ref_33 - required: *ref_34 + properties: *ref_37 + required: *ref_38 required: - modules type: type: string enum: - branchone - required: &ref_246 + required: &ref_347 - branches - default - type - type: object - properties: &ref_247 + properties: &ref_348 branches: type: array items: @@ -4691,8 +5463,8 @@ paths: type: array items: type: object - properties: *ref_33 - required: *ref_34 + properties: *ref_37 + required: *ref_38 required: - modules - expr @@ -4702,20 +5474,20 @@ paths: - branchall parallel: type: boolean - required: &ref_248 + required: &ref_349 - branches - type - type: object - properties: &ref_249 + properties: &ref_350 type: type: string enum: - identity flow: type: boolean - required: &ref_250 + required: &ref_351 - type - discriminator: &ref_252 + discriminator: &ref_353 propertyName: type mapping: rawscript: '#/components/schemas/RawScript' @@ -4728,22 +5500,19 @@ paths: identity: '#/components/schemas/Identity' stop_after_if: type: object - properties: + properties: &ref_39 skip_if_stopped: type: boolean expr: type: string - required: + error_message: + type: string + required: &ref_40 - expr stop_after_all_iters_if: type: object - properties: - skip_if_stopped: - type: boolean - expr: - type: string - required: - - expr + properties: *ref_39 + required: *ref_40 skip_if: type: object properties: @@ -4752,8 +5521,8 @@ paths: required: - expr sleep: - oneOf: *ref_31 - discriminator: *ref_32 + oneOf: *ref_35 + discriminator: *ref_36 cache_ttl: type: number timeout: @@ -4783,8 +5552,8 @@ paths: user_auth_required: type: boolean user_groups_required: - oneOf: *ref_31 - discriminator: *ref_32 + oneOf: *ref_35 + discriminator: *ref_36 self_approval_disabled: type: boolean hide_cancel: @@ -4797,7 +5566,7 @@ paths: type: boolean retry: type: object - properties: &ref_95 + properties: &ref_114 constant: type: object properties: @@ -4818,15 +5587,15 @@ paths: type: integer minimum: 0 maximum: 100 - required: *ref_34 + required: *ref_38 failure_module: type: object - properties: *ref_33 - required: *ref_34 + properties: *ref_37 + required: *ref_38 preprocessor_module: type: object - properties: *ref_33 - required: *ref_34 + properties: *ref_37 + required: *ref_38 same_worker: type: boolean concurrent_limit: @@ -4843,11 +5612,11 @@ paths: type: number early_return: type: string - required: &ref_67 + required: &ref_79 - modules schema: type: object - required: &ref_55 + required: &ref_62 - summary - value /apps/hub/list: @@ -4900,7 +5669,7 @@ paths: - name: id in: path required: true - schema: *ref_30 + schema: *ref_34 responses: '200': description: app @@ -4920,6 +5689,108 @@ paths: - value required: - app + /apps_u/public_app_by_custom_path/{custom_path}: + get: + summary: get public app by custom path + operationId: getPublicAppByCustomPath + tags: + - app + parameters: + - name: custom_path + in: path + required: true + schema: &ref_74 + type: string + responses: + '200': + description: app details + content: + application/json: + schema: + allOf: + - type: object + properties: &ref_69 + id: + type: integer + workspace_id: + type: string + path: + type: string + summary: + type: string + versions: + type: array + items: + type: integer + created_by: + type: string + created_at: + type: string + format: date-time + value: + type: object + policy: + type: object + properties: &ref_68 + triggerables: + type: object + additionalProperties: + type: object + triggerables_v2: + type: object + additionalProperties: + type: object + s3_inputs: + type: array + items: + type: object + allowed_s3_keys: + type: array + items: + type: object + properties: + s3_path: + type: string + resource: + type: string + execution_mode: + type: string + enum: + - viewer + - publisher + - anonymous + on_behalf_of: + type: string + on_behalf_of_email: + type: string + execution_mode: + type: string + enum: + - viewer + - publisher + - anonymous + extra_perms: + type: object + additionalProperties: + type: boolean + custom_path: + type: string + required: &ref_70 + - id + - workspace_id + - path + - summary + - versions + - created_by + - created_at + - value + - policy + - execution_mode + - extra_perms + - type: object + properties: + workspace_id: + type: string /scripts/hub/get/{path}: get: summary: get hub script content by path @@ -4930,7 +5801,7 @@ paths: - name: path in: path required: true - schema: &ref_35 + schema: &ref_41 type: string responses: '200': @@ -4949,7 +5820,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: script details @@ -5019,14 +5890,12 @@ paths: version_id: type: number kind: - name: kind - schema: &ref_36 - type: string - enum: - - script - - failure - - trigger - - approval + type: string + enum: &ref_42 + - script + - failure + - trigger + - approval votes: type: number views: @@ -5092,8 +5961,8 @@ paths: app: type: string kind: - name: kind - schema: *ref_36 + type: string + enum: *ref_42 score: type: number required: @@ -5154,12 +6023,12 @@ paths: - name: order_desc description: order by desc order (default true) in: query - schema: &ref_52 + schema: &ref_59 type: boolean - name: created_by description: mask to filter exact matching user creator in: query - schema: &ref_53 + schema: &ref_60 type: string - name: path_start description: mask to filter matching starting path @@ -5178,8 +6047,7 @@ paths: type: string - name: last_parent_hash description: > - mask to filter scripts whom last parent in the chain has exact - hash. + mask to filter scripts whom last parent in the chain has exact hash. Beware that each script stores only a limited number of parents. Hence @@ -5214,7 +6082,7 @@ paths: when multiple archived hash share the same path, only the ones with the latest create_at - are + are ed. in: query @@ -5273,7 +6141,7 @@ paths: type: array items: type: object - properties: &ref_37 + properties: &ref_44 workspace_id: type: string hash: @@ -5316,7 +6184,7 @@ paths: type: string language: type: string - enum: + enum: &ref_43 - python3 - deno - go @@ -5327,12 +6195,16 @@ paths: - bigquery - snowflake - mssql + - oracledb - graphql - nativets - bun - php - rust - ansible + - csharp + - nu + - java kind: type: string enum: @@ -5341,6 +6213,7 @@ paths: - trigger - command - approval + - preprocessor starred: type: boolean tag: @@ -5381,7 +6254,9 @@ paths: type: string has_preprocessor: type: boolean - required: &ref_38 + on_behalf_of_email: + type: string + required: &ref_45 - hash - path - summary @@ -5479,7 +6354,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: draft deleted @@ -5505,7 +6380,7 @@ paths: application/json: schema: type: object - properties: &ref_42 + properties: &ref_49 path: type: string parent_hash: @@ -5524,23 +6399,7 @@ paths: type: string language: type: string - enum: - - python3 - - deno - - go - - bash - - powershell - - postgresql - - mysql - - bigquery - - snowflake - - mssql - - graphql - - nativets - - bun - - php - - rust - - ansible + enum: *ref_43 kind: type: string enum: @@ -5549,6 +6408,7 @@ paths: - trigger - command - approval + - preprocessor tag: type: string draft_only: @@ -5587,7 +6447,9 @@ paths: type: string has_preprocessor: type: boolean - required: &ref_43 + on_behalf_of_email: + type: string + required: &ref_50 - path - summary - description @@ -5614,7 +6476,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 requestBody: description: Workspace error handler enabled required: true @@ -5640,6 +6502,17 @@ paths: operationId: getCustomTags tags: - worker + parameters: + - name: workspace + in: query + schema: + type: string + required: false + - name: show_workspace_restriction + in: query + schema: + type: boolean + required: false responses: '200': description: list of custom tags @@ -5691,7 +6564,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: script archived @@ -5713,7 +6586,7 @@ paths: - name: hash in: path required: true - schema: &ref_39 + schema: &ref_46 type: string responses: '200': @@ -5722,8 +6595,8 @@ paths: application/json: schema: type: object - properties: *ref_37 - required: *ref_38 + properties: *ref_44 + required: *ref_45 /w/{workspace}/scripts/delete/h/{hash}: post: summary: delete script by hash (erase content but keep hash, require admin) @@ -5738,7 +6611,7 @@ paths: - name: hash in: path required: true - schema: *ref_39 + schema: *ref_46 responses: '200': description: script details @@ -5746,11 +6619,11 @@ paths: application/json: schema: type: object - properties: *ref_37 - required: *ref_38 + properties: *ref_44 + required: *ref_45 /w/{workspace}/scripts/delete/p/{path}: post: - summary: delete all scripts at a given path (require admin) + summary: delete script at a given path (require admin) operationId: deleteScriptByPath tags: - script @@ -5762,7 +6635,12 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 + - name: keep_captures + description: keep captures + in: query + schema: + type: boolean responses: '200': description: script path @@ -5784,7 +6662,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - name: with_starred_info in: query schema: @@ -5796,8 +6674,8 @@ paths: application/json: schema: type: object - properties: *ref_37 - required: *ref_38 + properties: *ref_44 + required: *ref_45 /w/{workspace}/scripts/get_triggers_count/{path}: get: summary: get triggers count of script @@ -5812,7 +6690,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: triggers count @@ -5820,7 +6698,7 @@ paths: application/json: schema: type: object - properties: &ref_59 + properties: &ref_66 primary_schedule: type: object properties: @@ -5836,6 +6714,18 @@ paths: type: number websocket_count: type: number + postgres_count: + type: number + kafka_count: + type: number + nats_count: + type: number + mqtt_count: + type: number + gcp_count: + type: number + sqs_count: + type: number /w/{workspace}/scripts/list_tokens/{path}: get: summary: get tokens with script scope @@ -5850,7 +6740,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: tokens list @@ -5860,8 +6750,8 @@ paths: type: array items: type: object - properties: *ref_40 - required: *ref_41 + properties: *ref_47 + required: *ref_48 /w/{workspace}/scripts/get/draft/{path}: get: summary: get script by path with draft @@ -5876,23 +6766,23 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: script details content: application/json: schema: - allOf: &ref_137 + allOf: &ref_202 - type: object - properties: *ref_42 - required: *ref_43 + properties: *ref_49 + required: *ref_50 - type: object properties: draft: type: object - properties: *ref_42 - required: *ref_43 + properties: *ref_49 + required: *ref_50 hash: type: string required: @@ -5911,7 +6801,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: script history @@ -5921,13 +6811,37 @@ paths: type: array items: type: object - properties: &ref_44 + properties: &ref_51 script_hash: type: string deployment_msg: type: string - required: &ref_45 + required: &ref_52 - script_hash + /w/{workspace}/scripts/list_paths_from_workspace_runnable/{path}: + get: + summary: list script paths using provided script as a relative import + operationId: listScriptPathsFromWorkspaceRunnable + tags: + - script + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_41 + responses: + '200': + description: list of script paths + content: + application/json: + schema: + type: array + items: + type: string /w/{workspace}/scripts/get_latest_version/{path}: get: summary: get scripts's latest version (hash) @@ -5940,7 +6854,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 tags: - script responses: @@ -5948,11 +6862,10 @@ paths: description: Script version/hash content: application/json: - required: false schema: type: object - properties: *ref_44 - required: *ref_45 + properties: *ref_51 + required: *ref_52 /w/{workspace}/scripts/history_update/h/{hash}/p/{path}: post: summary: update history of a script @@ -5967,11 +6880,11 @@ paths: - name: hash in: path required: true - schema: *ref_39 + schema: *ref_46 - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 requestBody: description: Script deployment message required: true @@ -6003,7 +6916,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: script content @@ -6027,12 +6940,12 @@ paths: - name: token in: path required: true - schema: &ref_126 + schema: &ref_187 type: string - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: script content @@ -6054,7 +6967,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: does it exists @@ -6076,7 +6989,7 @@ paths: - name: hash in: path required: true - schema: *ref_39 + schema: *ref_46 - name: with_starred_info in: query schema: @@ -6088,8 +7001,8 @@ paths: application/json: schema: type: object - properties: *ref_37 - required: *ref_38 + properties: *ref_44 + required: *ref_45 /w/{workspace}/scripts/raw/h/{path}: get: summary: raw script by hash @@ -6104,7 +7017,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: script content @@ -6126,7 +7039,7 @@ paths: - name: hash in: path required: true - schema: *ref_39 + schema: *ref_46 responses: '200': description: script details @@ -6139,6 +7052,68 @@ paths: type: string lock_error_logs: type: string + /w/{workspace}/jobs/list_selected_job_groups: + post: + summary: list selected jobs script/flow schemas grouped by (kind, path) + operationId: listSelectedJobGroups + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: script args + required: true + content: + application/json: + schema: + type: array + items: + type: string + format: uuid + responses: + '200': + description: result + content: + text/plain: + schema: + type: array + items: + type: object + properties: + kind: + type: string + enum: + - script + - flow + script_path: + type: string + latest_schema: + type: object + schemas: + type: array + items: + type: object + properties: + schema: + type: object + script_hash: + type: string + job_ids: + type: array + items: + type: string + required: + - schema + - script_hash + - job_ids + required: + - kind + - script_path + - latest_schema + - schemas /w/{workspace}/jobs/run/p/{path}: post: summary: run script by path @@ -6153,7 +7128,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - name: scheduled_for description: when to schedule this job (leave empty for immediate run) in: query @@ -6175,20 +7150,20 @@ paths: The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: &ref_46 + schema: &ref_53 type: string format: uuid - name: tag description: Override the tag to use in: query - schema: &ref_48 + schema: &ref_55 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_49 + schema: &ref_56 type: string - name: job_id description: >- @@ -6197,7 +7172,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: &ref_47 + schema: &ref_54 type: string format: uuid - name: invisible_to_owner @@ -6212,7 +7187,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 responses: '201': description: job created @@ -6235,13 +7210,13 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - 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_46 + schema: *ref_53 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -6249,7 +7224,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -6258,14 +7233,14 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: &ref_50 + schema: &ref_57 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_51 + schema: &ref_58 type: string requestBody: description: script args @@ -6274,7 +7249,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 responses: '200': description: job result @@ -6295,23 +7270,23 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - 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_46 + schema: *ref_53 - name: tag description: Override the tag to use in: query - schema: *ref_48 + schema: *ref_55 - 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_49 + schema: *ref_56 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -6319,7 +7294,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -6328,13 +7303,13 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 - 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_51 + schema: *ref_58 requestBody: description: script args required: true @@ -6342,7 +7317,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 responses: '200': description: job result @@ -6362,23 +7337,23 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - 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_46 + schema: *ref_53 - name: tag description: Override the tag to use in: query - schema: *ref_48 + schema: *ref_55 - 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_49 + schema: *ref_56 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -6386,7 +7361,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -6395,13 +7370,13 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 - 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_51 + schema: *ref_58 - name: payload description: > The base64 encoded payload that has been encoded as a JSON. e.g how @@ -6409,7 +7384,7 @@ paths: `encodeURIComponent(btoa(JSON.stringify({a: 2})))` in: query - schema: &ref_94 + schema: &ref_113 type: string responses: '200': @@ -6431,7 +7406,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -6440,13 +7415,13 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 - 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_51 + schema: *ref_58 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -6454,7 +7429,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 requestBody: description: script args required: true @@ -6462,7 +7437,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 responses: '200': description: job result @@ -6483,7 +7458,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -6492,13 +7467,13 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 - 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_51 + schema: *ref_58 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -6506,7 +7481,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 requestBody: description: script args required: true @@ -6514,7 +7489,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 responses: '200': description: job result @@ -6617,11 +7592,11 @@ paths: - name: order_desc description: order by desc order (default true) in: query - schema: *ref_52 + schema: *ref_59 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_53 + schema: *ref_60 - name: path_start description: mask to filter matching starting path in: query @@ -6675,12 +7650,12 @@ paths: type: array items: allOf: - - allOf: &ref_58 + - allOf: &ref_65 - type: object - properties: *ref_54 - required: *ref_55 + properties: *ref_61 + required: *ref_62 - type: object - properties: &ref_190 + properties: &ref_285 workspace_id: type: string path: @@ -6694,7 +7669,7 @@ paths: type: boolean extra_perms: type: object - additionalProperties: &ref_189 + additionalProperties: &ref_284 type: boolean starred: type: boolean @@ -6712,12 +7687,18 @@ paths: type: number visible_to_runner_only: type: boolean - required: &ref_191 + on_behalf_of_email: + type: string + required: &ref_286 - path - edited_by - edited_at - archived - extra_perms + - type: object + properties: + lock_error_logs: + type: string - type: object properties: has_draft: @@ -6736,7 +7717,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 tags: - flow responses: @@ -6748,7 +7729,7 @@ paths: type: array items: type: object - properties: &ref_56 + properties: &ref_63 id: type: integer created_at: @@ -6756,7 +7737,7 @@ paths: format: date-time deployment_msg: type: string - required: &ref_57 + required: &ref_64 - id - created_at /w/{workspace}/flows/get_latest_version/{path}: @@ -6771,7 +7752,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 tags: - flow responses: @@ -6779,11 +7760,42 @@ paths: description: Flow version content: application/json: - required: false schema: type: object - properties: *ref_56 - required: *ref_57 + properties: *ref_63 + required: *ref_64 + /w/{workspace}/flows/list_paths_from_workspace_runnable/{runnable_kind}/{path}: + get: + summary: list flow paths from workspace runnable + operationId: listFlowPathsFromWorkspaceRunnable + tags: + - flow + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: runnable_kind + in: path + required: true + schema: &ref_73 + type: string + enum: + - script + - flow + - name: path + in: path + required: true + schema: *ref_41 + responses: + '200': + description: list of flow paths + content: + application/json: + schema: + type: array + items: + type: string /w/{workspace}/flows/get/v/{version}/p/{path}: get: summary: get flow version @@ -6793,8 +7805,7 @@ paths: in: path required: true schema: *ref_0 - - type: string - name: version + - name: version in: path required: true schema: @@ -6802,7 +7813,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 tags: - flow responses: @@ -6811,7 +7822,7 @@ paths: content: application/json: schema: - allOf: *ref_58 + allOf: *ref_65 /w/{workspace}/flows/history_update/v/{version}/p/{path}: post: summary: update flow history @@ -6821,8 +7832,7 @@ paths: in: path required: true schema: *ref_0 - - type: string - name: version + - name: version in: path required: true schema: @@ -6830,7 +7840,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 requestBody: description: Flow deployment message required: true @@ -6866,7 +7876,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - name: with_starred_info in: query schema: @@ -6877,7 +7887,32 @@ paths: content: application/json: schema: - allOf: *ref_58 + allOf: *ref_65 + /w/{workspace}/flows/deployment_status/p/{path}: + get: + summary: get flow deployment status + operationId: getFlowDeploymentStatus + tags: + - flow + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_41 + responses: + '200': + description: flow status + content: + application/json: + schema: + type: object + properties: + lock_error_logs: + type: string /w/{workspace}/flows/get_triggers_count/{path}: get: summary: get triggers count of flow @@ -6892,7 +7927,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: triggers count @@ -6900,7 +7935,7 @@ paths: application/json: schema: type: object - properties: *ref_59 + properties: *ref_66 /w/{workspace}/flows/list_tokens/{path}: get: summary: get tokens with flow scope @@ -6915,7 +7950,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: tokens list @@ -6925,8 +7960,8 @@ paths: type: array items: type: object - properties: *ref_40 - required: *ref_41 + properties: *ref_47 + required: *ref_48 /w/{workspace}/flows/toggle_workspace_error_handler/{path}: post: summary: Toggle ON and OFF the workspace error handler for a given flow @@ -6941,7 +7976,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 requestBody: description: Workspace error handler enabled required: true @@ -6973,7 +8008,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: flow details with draft @@ -6981,11 +8016,11 @@ paths: application/json: schema: allOf: - - allOf: *ref_58 + - allOf: *ref_65 - type: object properties: draft: - allOf: *ref_58 + allOf: *ref_65 /w/{workspace}/flows/exists/{path}: get: summary: exists flow by path @@ -7000,7 +8035,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: flow details @@ -7026,10 +8061,10 @@ paths: application/json: schema: allOf: - - allOf: &ref_60 + - allOf: &ref_67 - type: object - properties: *ref_54 - required: *ref_55 + properties: *ref_61 + required: *ref_62 - type: object properties: path: @@ -7046,6 +8081,8 @@ paths: type: number visible_to_runner_only: type: boolean + on_behalf_of_email: + type: string required: - path - type: object @@ -7075,7 +8112,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 requestBody: description: Partially filled flow required: true @@ -7083,7 +8120,7 @@ paths: application/json: schema: allOf: - - allOf: *ref_60 + - allOf: *ref_67 - type: object properties: deployment_message: @@ -7109,7 +8146,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 requestBody: description: archiveFlow required: true @@ -7141,7 +8178,12 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 + - name: keep_captures + description: keep captures + in: query + schema: + type: boolean responses: '200': description: flow delete @@ -7171,11 +8213,11 @@ paths: - name: order_desc description: order by desc order (default true) in: query - schema: *ref_52 + schema: *ref_59 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_53 + schema: *ref_60 - name: path_start description: mask to filter matching starting path in: query @@ -7202,7 +8244,7 @@ paths: type: array items: type: object - properties: &ref_197 + properties: &ref_292 workspace_id: type: string path: @@ -7220,7 +8262,7 @@ paths: edited_at: type: string format: date-time - required: &ref_198 + required: &ref_293 - workspace_id - path - summary @@ -7241,7 +8283,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: app exists @@ -7263,12 +8305,12 @@ paths: - name: version in: path required: true - schema: &ref_125 + schema: &ref_186 type: number - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: app details @@ -7325,11 +8367,11 @@ paths: - name: order_desc description: order by desc order (default true) in: query - schema: *ref_52 + schema: *ref_59 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_53 + schema: *ref_60 - name: path_start description: mask to filter matching starting path in: query @@ -7370,7 +8412,7 @@ paths: type: array items: type: object - properties: &ref_195 + properties: &ref_290 id: type: integer workspace_id: @@ -7396,7 +8438,9 @@ paths: - viewer - publisher - anonymous - required: &ref_196 + raw_app: + type: boolean + required: &ref_291 - id - workspace_id - path @@ -7431,33 +8475,13 @@ paths: type: string policy: type: object - properties: &ref_61 - triggerables: - type: object - additionalProperties: - type: object - triggerables_v2: - type: object - additionalProperties: - type: object - s3_inputs: - type: array - items: - type: object - execution_mode: - type: string - enum: - - viewer - - publisher - - anonymous - on_behalf_of: - type: string - on_behalf_of_email: - type: string + properties: *ref_68 draft_only: type: boolean deployment_message: type: string + custom_path: + type: string required: - path - value @@ -7470,6 +8494,58 @@ paths: text/plain: schema: type: string + /w/{workspace}/apps/create_raw: + post: + summary: create app raw + operationId: createAppRaw + tags: + - app + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: new app + required: true + content: + multipart/form-data: + schema: + type: object + properties: + app: + type: object + properties: + path: + type: string + value: {} + summary: + type: string + policy: + type: object + properties: *ref_68 + draft_only: + type: boolean + deployment_message: + type: string + custom_path: + type: string + required: + - path + - value + - summary + - policy + js: + type: string + css: + type: string + responses: + '201': + description: app created + content: + text/plain: + schema: + type: string /w/{workspace}/apps/exists/{path}: get: summary: does an app exisst at path @@ -7484,7 +8560,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: app exists @@ -7506,7 +8582,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - name: with_starred_info in: query schema: @@ -7518,51 +8594,32 @@ paths: application/json: schema: type: object - properties: &ref_62 - id: - type: integer - workspace_id: - type: string - path: - type: string - summary: - type: string - versions: - type: array - items: - type: integer - created_by: - type: string - created_at: - type: string - format: date-time - value: - type: object - policy: - type: object - properties: *ref_61 - execution_mode: - type: string - enum: - - viewer - - publisher - - anonymous - extra_perms: - type: object - additionalProperties: - type: boolean - required: &ref_63 - - id - - workspace_id - - path - - summary - - versions - - created_by - - created_at - - value - - policy - - execution_mode - - extra_perms + properties: *ref_69 + required: *ref_70 + /w/{workspace}/apps/get/lite/{path}: + get: + summary: get app lite by path + operationId: getAppLiteByPath + tags: + - app + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_41 + responses: + '200': + description: app lite details + content: + application/json: + schema: + type: object + properties: *ref_69 + required: *ref_70 /w/{workspace}/apps/get/draft/{path}: get: summary: get app by path with draft @@ -7577,17 +8634,17 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: app details with draft content: application/json: schema: - allOf: &ref_199 + allOf: &ref_294 - type: object - properties: *ref_62 - required: *ref_63 + properties: *ref_69 + required: *ref_70 - type: object properties: draft_only: @@ -7607,7 +8664,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 responses: '200': description: app history @@ -7617,12 +8674,12 @@ paths: type: array items: type: object - properties: &ref_64 + properties: &ref_71 version: type: integer deployment_msg: type: string - required: &ref_65 + required: &ref_72 - version /w/{workspace}/apps/get_latest_version/{path}: get: @@ -7636,7 +8693,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 tags: - app responses: @@ -7644,11 +8701,38 @@ paths: description: App version content: application/json: - required: false schema: type: object - properties: *ref_64 - required: *ref_65 + properties: *ref_71 + required: *ref_72 + /w/{workspace}/apps/list_paths_from_workspace_runnable/{runnable_kind}/{path}: + get: + summary: list app paths from workspace runnable + operationId: listAppPathsFromWorkspaceRunnable + tags: + - app + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: runnable_kind + in: path + required: true + schema: *ref_73 + - name: path + in: path + required: true + schema: *ref_41 + responses: + '200': + description: list of app paths + content: + application/json: + schema: + type: array + items: + type: string /w/{workspace}/apps/history_update/a/{id}/v/{version}: post: summary: update app history @@ -7663,11 +8747,11 @@ paths: - name: id in: path required: true - schema: *ref_30 + schema: *ref_34 - name: version in: path required: true - schema: &ref_127 + schema: &ref_188 type: integer requestBody: description: App deployment message @@ -7700,7 +8784,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: app details @@ -7708,8 +8792,8 @@ paths: application/json: schema: type: object - properties: *ref_62 - required: *ref_63 + properties: *ref_69 + required: *ref_70 /w/{workspace}/apps_u/public_resource/{path}: get: summary: get public resource @@ -7724,7 +8808,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: resource value @@ -7745,7 +8829,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: app secret @@ -7767,7 +8851,7 @@ paths: - name: id in: path required: true - schema: *ref_30 + schema: *ref_34 responses: '200': description: app details @@ -7775,8 +8859,8 @@ paths: application/json: schema: type: object - properties: *ref_62 - required: *ref_63 + properties: *ref_69 + required: *ref_70 /w/{workspace}/raw_apps/create: post: summary: create raw app @@ -7827,7 +8911,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 requestBody: description: updateraw app required: true @@ -7863,7 +8947,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: app deleted @@ -7885,7 +8969,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: app deleted @@ -7907,7 +8991,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 requestBody: description: update app required: true @@ -7923,9 +9007,11 @@ paths: value: {} policy: type: object - properties: *ref_61 + properties: *ref_68 deployment_message: type: string + custom_path: + type: string responses: '200': description: app updated @@ -7933,6 +9019,124 @@ paths: text/plain: schema: type: string + /w/{workspace}/apps/update_raw/{path}: + post: + summary: update app + operationId: updateAppRaw + tags: + - app + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_41 + requestBody: + description: update app + required: true + content: + multipart/form-data: + schema: + type: object + properties: + app: + type: object + properties: + path: + type: string + summary: + type: string + value: {} + policy: + type: object + properties: *ref_68 + deployment_message: + type: string + custom_path: + type: string + js: + type: string + css: + type: string + responses: + '200': + description: app updated + content: + text/plain: + schema: + type: string + /w/{workspace}/apps/custom_path_exists/{custom_path}: + get: + summary: check if custom path exists + operationId: customPathExists + tags: + - app + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: custom_path + in: path + required: true + schema: *ref_74 + responses: + '200': + description: custom path exists + content: + application/json: + schema: + type: boolean + /w/{workspace}/apps/sign_s3_objects: + post: + summary: sign s3 objects, to be used by anonymous users in public apps + operationId: signS3Objects + tags: + - app + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: s3 objects to sign + required: true + content: + application/json: + schema: + type: object + properties: + s3_objects: + type: array + items: + type: object + properties: &ref_75 + s3: + type: string + filename: + type: string + storage: + type: string + presigned: + type: string + required: &ref_76 + - s3 + required: + - s3_objects + responses: + '200': + description: signed s3 objects + content: + application/json: + schema: + type: array + items: + type: object + properties: *ref_75 + required: *ref_76 /w/{workspace}/apps_u/execute_component/{path}: post: summary: executeComponent @@ -7947,7 +9151,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 requestBody: description: update app required: true @@ -7960,6 +9164,8 @@ paths: type: string path: type: string + version: + type: integer args: {} raw_code: type: object @@ -7977,6 +9183,8 @@ paths: required: - content - language + id: + type: integer force_viewer_static_fields: type: object force_viewer_one_of_fields: @@ -7995,6 +9203,99 @@ paths: text/plain: schema: type: string + /w/{workspace}/apps_u/upload_s3_file/{path}: + post: + summary: upload s3 file from app + operationId: uploadS3FileFromApp + tags: + - app + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + - 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 uploaded + content: + application/json: + schema: + type: object + properties: + file_key: + type: string + delete_token: + type: string + required: + - file_key + - delete_token + /w/{workspace}/apps_u/delete_s3_file: + delete: + summary: delete s3 file from app + operationId: deleteS3FileFromApp + tags: + - app + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: delete_token + in: query + required: true + schema: + type: string + responses: + '200': + description: file deleted + content: + text/plain: + schema: + type: string /w/{workspace}/jobs/run/f/{path}: post: summary: run flow by path @@ -8009,7 +9310,7 @@ paths: - name: path in: path required: true - schema: *ref_35 + schema: *ref_41 - name: scheduled_for description: when to schedule this job (leave empty for immediate run) in: query @@ -8031,11 +9332,11 @@ paths: The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_46 + schema: *ref_53 - name: tag description: Override the tag to use in: query - schema: *ref_48 + schema: *ref_55 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -8043,7 +9344,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -8052,7 +9353,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 - name: invisible_to_owner description: make the run invisible to the the flow owner (default false) in: query @@ -8065,7 +9366,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 responses: '201': description: job created @@ -8074,6 +9375,66 @@ paths: schema: type: string format: uuid + /w/{workspace}/jobs/run/batch_rerun_jobs: + post: + summary: re-run multiple jobs + operationId: batchReRunJobs + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: list of job ids to re run and arg tranforms + required: true + content: + application/json: + schema: + type: object + required: + - job_ids + - script_options_by_path + - flow_options_by_path + properties: + job_ids: + type: array + items: + type: string + script_options_by_path: + type: object + additionalProperties: + type: object + properties: + input_transforms: + type: object + additionalProperties: + allOf: &ref_77 + - oneOf: *ref_35 + discriminator: *ref_36 + use_latest_version: + type: boolean + flow_options_by_path: + type: object + additionalProperties: + type: object + properties: + input_transforms: + type: object + additionalProperties: + allOf: *ref_77 + use_latest_version: + type: boolean + responses: + '201': + description: >- + stream of created job uuids separated by \n. Lines may start with + 'Error:' + content: + text/event-stream: + schema: + type: string /w/{workspace}/jobs/restart/f/{id}/from/{step_id}/{branch_or_iteration_n}: post: summary: restart a completed flow at a given step @@ -8088,7 +9449,7 @@ paths: - name: id in: path required: true - schema: &ref_91 + schema: &ref_110 type: string format: uuid - name: step_id @@ -8121,11 +9482,11 @@ paths: The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_46 + schema: *ref_53 - name: tag description: Override the tag to use in: query - schema: *ref_48 + schema: *ref_55 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -8133,7 +9494,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -8142,7 +9503,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 - name: invisible_to_owner description: make the run invisible to the the flow owner (default false) in: query @@ -8155,7 +9516,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 responses: '201': description: job created @@ -8178,7 +9539,7 @@ paths: - name: hash in: path required: true - schema: *ref_39 + schema: *ref_46 - name: scheduled_for description: when to schedule this job (leave empty for immediate run) in: query @@ -8200,17 +9561,17 @@ paths: The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_46 + schema: *ref_53 - name: tag description: Override the tag to use in: query - schema: *ref_48 + schema: *ref_55 - 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_49 + schema: *ref_56 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -8218,7 +9579,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -8227,7 +9588,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 - name: invisible_to_owner description: make the run invisible to the the script owner (default false) in: query @@ -8267,7 +9628,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 - name: invisible_to_owner description: make the run invisible to the the script owner (default false) in: query @@ -8280,7 +9641,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 requestBody: description: preview required: true @@ -8288,33 +9649,19 @@ paths: application/json: schema: type: object - properties: &ref_156 + properties: &ref_221 content: type: string path: type: string + script_hash: + type: string args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 language: type: string - enum: - - python3 - - deno - - go - - bash - - powershell - - postgresql - - mysql - - bigquery - - snowflake - - mssql - - graphql - - nativets - - bun - - php - - rust - - ansible + enum: *ref_43 tag: type: string kind: @@ -8327,7 +9674,7 @@ paths: type: boolean lock: type: string - required: &ref_157 + required: &ref_222 - args responses: '201': @@ -8365,11 +9712,11 @@ paths: application/json: schema: type: object - properties: &ref_158 + properties: &ref_223 args: type: object - additionalProperties: *ref_18 - required: &ref_159 + additionalProperties: *ref_21 + required: &ref_224 - args responses: '201': @@ -8402,31 +9749,15 @@ paths: type: array items: type: object - properties: &ref_217 + properties: &ref_312 raw_code: type: string path: type: string language: type: string - enum: - - python3 - - deno - - go - - bash - - powershell - - postgresql - - mysql - - bigquery - - snowflake - - mssql - - graphql - - nativets - - bun - - php - - rust - - ansible - required: &ref_218 + enum: *ref_43 + required: &ref_313 - raw_code - path - language @@ -8466,7 +9797,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 - name: invisible_to_owner description: make the run invisible to the the script owner (default false) in: query @@ -8479,7 +9810,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_47 + schema: *ref_54 requestBody: description: preview required: true @@ -8487,21 +9818,21 @@ paths: application/json: schema: type: object - properties: &ref_192 + properties: &ref_287 value: type: object - properties: *ref_66 - required: *ref_67 + properties: *ref_78 + required: *ref_79 path: type: string args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 tag: type: string restarted_from: type: object - properties: &ref_194 + properties: &ref_289 flow_job_id: type: string format: uuid @@ -8509,7 +9840,7 @@ paths: type: string branch_or_iteration_n: type: integer - required: &ref_193 + required: &ref_288 - value - content - args @@ -8535,94 +9866,104 @@ paths: - name: order_desc description: order by desc order (default true) in: query - schema: *ref_52 + schema: *ref_59 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_53 + schema: *ref_60 - 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_46 + schema: *ref_53 + - name: worker + description: worker this job was ran on + in: query + schema: &ref_82 + type: string - name: script_path_exact description: mask to filter exact matching path in: query - schema: &ref_70 + schema: &ref_83 type: string - name: script_path_start description: mask to filter matching starting path in: query - schema: &ref_71 + schema: &ref_84 type: string - name: schedule_path description: mask to filter by schedule path in: query - schema: &ref_72 + schema: &ref_85 type: string - name: script_hash description: mask to filter exact matching path in: query - schema: &ref_73 + schema: &ref_86 type: string - name: started_before description: filter on started before (inclusive) timestamp in: query - schema: &ref_74 + schema: &ref_87 type: string format: date-time - name: started_after description: filter on started after (exclusive) timestamp in: query - schema: &ref_75 + schema: &ref_88 type: string format: date-time - name: success description: filter on successful jobs in: query - schema: &ref_76 + schema: &ref_96 type: boolean - name: scheduled_for_before_now description: filter on jobs scheduled_for before now (hence waitinf for a worker) in: query - schema: &ref_77 + schema: &ref_90 type: boolean - name: job_kinds description: >- filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: &ref_78 + schema: &ref_91 type: string - name: suspended description: filter on suspended jobs in: query - schema: &ref_79 + schema: &ref_92 type: boolean - name: running description: filter on running jobs in: query - schema: &ref_80 + schema: &ref_89 type: boolean - name: args description: >- filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: &ref_81 + schema: &ref_93 type: string - name: result description: >- filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: &ref_82 + schema: &ref_95 type: string + - name: allow_wildcards + description: allow wildcards (*) in the filter of label, tag, worker + in: query + schema: &ref_97 + type: boolean - name: tag description: filter on jobs with a given tag/worker group in: query - schema: &ref_83 + schema: &ref_94 type: string - name: page description: which page to return (start at 1, default 1) @@ -8653,7 +9994,7 @@ paths: type: array items: type: object - properties: &ref_89 + properties: &ref_108 workspace_id: type: string id: @@ -8681,7 +10022,7 @@ paths: type: string args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 logs: type: string raw_code: @@ -8717,20 +10058,20 @@ paths: permissioned_as: type: string description: > - The user (u/userfoo) or group (g/groupfoo) whom + The user (u/userfoo) or group (g/groupfoo) whom the execution of this script will be permissioned_as and by extension its DT_TOKEN. flow_status: type: object - properties: &ref_84 + properties: &ref_99 step: type: integer modules: type: array items: type: object - properties: &ref_68 + properties: &ref_80 type: type: string enum: @@ -8807,20 +10148,20 @@ paths: format: uuid skipped: type: boolean - required: &ref_69 + required: &ref_81 - type user_states: additionalProperties: true preprocessor_module: allOf: - type: object - properties: *ref_68 - required: *ref_69 + properties: *ref_80 + required: *ref_81 failure_module: allOf: - type: object - properties: *ref_68 - required: *ref_69 + properties: *ref_80 + required: *ref_81 - type: object properties: parent_module: @@ -8835,35 +10176,19 @@ paths: items: type: string format: uuid - required: &ref_85 + required: &ref_100 - step - modules - failure_module raw_flow: type: object - properties: *ref_66 - required: *ref_67 + properties: *ref_78 + required: *ref_79 is_flow_step: type: boolean language: type: string - enum: - - python3 - - deno - - go - - bash - - powershell - - postgresql - - mysql - - bigquery - - snowflake - - mssql - - graphql - - nativets - - bun - - php - - rust - - ansible + enum: *ref_43 email: type: string visible_to_owner: @@ -8880,7 +10205,11 @@ paths: type: number suspend: type: number - required: &ref_90 + preprocessed: + type: boolean + worker: + type: string + required: &ref_109 - id - running - canceled @@ -8945,10 +10274,221 @@ paths: type: integer required: - database_length - /w/{workspace}/jobs/queue/list_filtered_uuids: + /w/{workspace}/jobs/completed/count_jobs: + get: + summary: count number of completed jobs with filter + operationId: countCompletedJobs + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: completed_after_s_ago + in: query + schema: + type: integer + - name: success + in: query + schema: + type: boolean + - name: tags + in: query + schema: + type: string + - name: all_workspaces + in: query + schema: + type: boolean + responses: + '200': + description: Count of completed jobs + content: + application/json: + schema: + type: integer + /w/{workspace}/jobs/list_filtered_uuids: get: summary: get the ids of all jobs matching the given filters - operationId: listFilteredUuids + operationId: listFilteredJobsUuids + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: created_by + description: mask to filter exact matching user creator + in: query + schema: *ref_60 + - 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_98 + type: string + - name: worker + description: worker this job was ran on + in: query + schema: *ref_82 + - 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_53 + - name: script_path_exact + description: mask to filter exact matching path + in: query + schema: *ref_83 + - name: script_path_start + description: mask to filter matching starting path + in: query + schema: *ref_84 + - name: schedule_path + description: mask to filter by schedule path + in: query + schema: *ref_85 + - name: script_hash + description: mask to filter exact matching path + in: query + schema: *ref_86 + - name: started_before + description: filter on started before (inclusive) timestamp + in: query + schema: *ref_87 + - name: started_after + description: filter on started after (exclusive) timestamp + in: query + schema: *ref_88 + - name: created_before + description: filter on created before (inclusive) timestamp + in: query + schema: &ref_101 + type: string + format: date-time + - name: created_after + description: filter on created after (exclusive) timestamp + in: query + schema: &ref_102 + 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 + in: query + schema: &ref_103 + type: string + format: date-time + - name: running + description: filter on running jobs + in: query + schema: *ref_89 + - name: scheduled_for_before_now + description: filter on jobs scheduled_for before now (hence waitinf for a worker) + in: query + schema: *ref_90 + - 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_104 + 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_105 + type: string + format: date-time + - name: job_kinds + description: >- + filter on job kind (values 'preview', 'script', 'dependencies', + 'flow') separated by, + in: query + schema: *ref_91 + - name: suspended + description: filter on suspended jobs + in: query + schema: *ref_92 + - name: args + description: >- + filter on jobs containing those args as a json subset (@> in + postgres) + in: query + schema: *ref_93 + - name: tag + description: filter on jobs with a given tag/worker group + in: query + schema: *ref_94 + - name: result + description: >- + filter on jobs containing those result as a json subset (@> in + postgres) + in: query + schema: *ref_95 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - name: is_skipped + description: is the job skipped + in: query + schema: + type: boolean + - name: is_flow_step + description: is the job a flow step + in: query + schema: + type: boolean + - name: has_null_parent + description: has null parent + in: query + schema: + type: boolean + - name: success + description: filter on successful jobs + in: query + schema: + type: boolean + - name: all_workspaces + description: >- + get jobs from all workspaces (only valid if request come from the + `admins` workspace) + in: query + schema: + type: boolean + - name: is_not_schedule + description: is not a scheduled job + in: query + schema: + type: boolean + responses: + '200': + description: uuids of jobs + content: + application/json: + schema: + type: array + items: + type: string + /w/{workspace}/jobs/queue/list_filtered_uuids: + get: + summary: get the ids of all queued jobs matching the given filters + operationId: listFilteredQueueUuids tags: - job parameters: @@ -8959,79 +10499,83 @@ paths: - name: order_desc description: order by desc order (default true) in: query - schema: *ref_52 + schema: *ref_59 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_53 + schema: *ref_60 - 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_46 + schema: *ref_53 - name: script_path_exact description: mask to filter exact matching path in: query - schema: *ref_70 + schema: *ref_83 - name: script_path_start description: mask to filter matching starting path in: query - schema: *ref_71 + schema: *ref_84 - name: schedule_path description: mask to filter by schedule path in: query - schema: *ref_72 + schema: *ref_85 - name: script_hash description: mask to filter exact matching path in: query - schema: *ref_73 + schema: *ref_86 - name: started_before description: filter on started before (inclusive) timestamp in: query - schema: *ref_74 + schema: *ref_87 - name: started_after description: filter on started after (exclusive) timestamp in: query - schema: *ref_75 + schema: *ref_88 - name: success description: filter on successful jobs in: query - schema: *ref_76 + schema: *ref_96 - name: scheduled_for_before_now description: filter on jobs scheduled_for before now (hence waitinf for a worker) in: query - schema: *ref_77 + schema: *ref_90 - name: job_kinds description: >- filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: *ref_78 + schema: *ref_91 - name: suspended description: filter on suspended jobs in: query - schema: *ref_79 + schema: *ref_92 - name: running description: filter on running jobs in: query - schema: *ref_80 + schema: *ref_89 - name: args description: >- filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: *ref_81 + schema: *ref_93 - name: result description: >- filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: *ref_82 + schema: *ref_95 + - name: allow_wildcards + description: allow wildcards (*) in the filter of label, tag, worker + in: query + schema: *ref_97 - name: tag description: filter on jobs with a given tag/worker group in: query - schema: *ref_83 + schema: *ref_94 - name: page description: which page to return (start at 1, default 1) in: query @@ -9109,75 +10653,82 @@ paths: - name: order_desc description: order by desc order (default true) in: query - schema: *ref_52 + schema: *ref_59 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_53 + schema: *ref_60 - 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_86 - type: string + schema: *ref_98 + - name: worker + description: worker this job was ran on + in: query + schema: *ref_82 - 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_46 + schema: *ref_53 - name: script_path_exact description: mask to filter exact matching path in: query - schema: *ref_70 + schema: *ref_83 - name: script_path_start description: mask to filter matching starting path in: query - schema: *ref_71 + schema: *ref_84 - name: schedule_path description: mask to filter by schedule path in: query - schema: *ref_72 + schema: *ref_85 - name: script_hash description: mask to filter exact matching path in: query - schema: *ref_73 + schema: *ref_86 - name: started_before description: filter on started before (inclusive) timestamp in: query - schema: *ref_74 + schema: *ref_87 - name: started_after description: filter on started after (exclusive) timestamp in: query - schema: *ref_75 + schema: *ref_88 - name: success description: filter on successful jobs in: query - schema: *ref_76 + schema: *ref_96 - name: job_kinds description: >- filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: *ref_78 + schema: *ref_91 - name: args description: >- filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: *ref_81 + schema: *ref_93 - name: result description: >- filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: *ref_82 + schema: *ref_95 + - name: allow_wildcards + description: allow wildcards (*) in the filter of label, tag, worker + in: query + schema: *ref_97 - name: tag description: filter on jobs with a given tag/worker group in: query - schema: *ref_83 + schema: *ref_94 - name: page description: which page to return (start at 1, default 1) in: query @@ -9215,7 +10766,7 @@ paths: type: array items: type: object - properties: &ref_87 + properties: &ref_106 workspace_id: type: string id: @@ -9242,7 +10793,7 @@ paths: type: string args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 result: {} logs: type: string @@ -9278,39 +10829,23 @@ paths: permissioned_as: type: string description: > - The user (u/userfoo) or group (g/groupfoo) whom + The user (u/userfoo) or group (g/groupfoo) whom the execution of this script will be permissioned_as and by extension its DT_TOKEN. flow_status: type: object - properties: *ref_84 - required: *ref_85 + properties: *ref_99 + required: *ref_100 raw_flow: type: object - properties: *ref_66 - required: *ref_67 + properties: *ref_78 + required: *ref_79 is_flow_step: type: boolean language: type: string - enum: - - python3 - - deno - - go - - bash - - powershell - - postgresql - - mysql - - bigquery - - snowflake - - mssql - - graphql - - nativets - - bun - - php - - rust - - ansible + enum: *ref_43 is_skipped: type: boolean email: @@ -9331,7 +10866,11 @@ paths: type: number aggregate_wait_time_ms: type: number - required: &ref_88 + preprocessed: + type: boolean + worker: + type: string + required: &ref_107 - id - created_by - duration_ms @@ -9360,115 +10899,113 @@ paths: - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_53 + schema: *ref_60 - 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_86 + schema: *ref_98 + - name: worker + description: worker this job was ran on + in: query + schema: *ref_82 - 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_46 + schema: *ref_53 - name: script_path_exact description: mask to filter exact matching path in: query - schema: *ref_70 + schema: *ref_83 - name: script_path_start description: mask to filter matching starting path in: query - schema: *ref_71 + schema: *ref_84 - name: schedule_path description: mask to filter by schedule path in: query - schema: *ref_72 + schema: *ref_85 - name: script_hash description: mask to filter exact matching path in: query - schema: *ref_73 + schema: *ref_86 - name: started_before description: filter on started before (inclusive) timestamp in: query - schema: *ref_74 + schema: *ref_87 - name: started_after description: filter on started after (exclusive) timestamp in: query - schema: *ref_75 + schema: *ref_88 - name: created_before description: filter on created before (inclusive) timestamp in: query - schema: &ref_128 - type: string - format: date-time + schema: *ref_101 - name: created_after description: filter on created after (exclusive) timestamp in: query - schema: &ref_129 - type: string - format: date-time + schema: *ref_102 - 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_122 - type: string - format: date-time + schema: *ref_103 - name: running description: filter on running jobs in: query - schema: *ref_80 + schema: *ref_89 - name: scheduled_for_before_now description: filter on jobs scheduled_for before now (hence waitinf for a worker) in: query - schema: *ref_77 + schema: *ref_90 - 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_123 - type: string - format: date-time + schema: *ref_104 - 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_124 - type: string - format: date-time + schema: *ref_105 - name: job_kinds description: >- filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: *ref_78 + schema: *ref_91 - name: suspended description: filter on suspended jobs in: query - schema: *ref_79 + schema: *ref_92 - name: args description: >- filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: *ref_81 + schema: *ref_93 - name: tag description: filter on jobs with a given tag/worker group in: query - schema: *ref_83 + schema: *ref_94 - name: result description: >- filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: *ref_82 + schema: *ref_95 + - name: allow_wildcards + description: allow wildcards (*) in the filter of label, tag, worker + in: query + schema: *ref_97 - name: page description: which page to return (start at 1, default 1) in: query @@ -9517,11 +11054,11 @@ paths: schema: type: array items: - oneOf: &ref_92 + oneOf: &ref_111 - allOf: - type: object - properties: *ref_87 - required: *ref_88 + properties: *ref_106 + required: *ref_107 - type: object properties: type: @@ -9530,15 +11067,15 @@ paths: - CompletedJob - allOf: - type: object - properties: *ref_89 - required: *ref_90 + properties: *ref_108 + required: *ref_109 - type: object properties: type: type: string enum: - QueuedJob - discriminator: &ref_93 + discriminator: &ref_112 propertyName: type /jobs/db_clock: get: @@ -9605,7 +11142,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: no_logs in: query schema: @@ -9616,8 +11153,8 @@ paths: content: application/json: schema: - oneOf: *ref_92 - discriminator: *ref_93 + oneOf: *ref_111 + discriminator: *ref_112 /w/{workspace}/jobs_u/get_root_job_id/{id}: get: summary: get root job id @@ -9632,7 +11169,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 responses: '200': description: get root job id @@ -9654,7 +11191,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 responses: '200': description: job details @@ -9676,7 +11213,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 responses: '200': description: job args @@ -9697,7 +11234,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: running in: query schema: @@ -9732,9 +11269,9 @@ paths: type: integer flow_status: type: object - additionalProperties: &ref_160 + additionalProperties: &ref_225 type: object - properties: &ref_161 + properties: &ref_226 scheduled_for: type: string format: date-time @@ -9766,7 +11303,8 @@ paths: description: job log content: text/plain: - type: string + schema: + type: string /w/{workspace}/jobs_u/get_flow_debug_info/{id}: get: summary: get flow debug info @@ -9781,7 +11319,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 responses: '200': description: flow debug info details @@ -9802,7 +11340,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 responses: '200': description: job details @@ -9810,8 +11348,8 @@ paths: application/json: schema: type: object - properties: *ref_87 - required: *ref_88 + properties: *ref_106 + required: *ref_107 /w/{workspace}/jobs_u/completed/get_result/{id}: get: summary: get completed job result @@ -9826,7 +11364,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: suspended_job in: query schema: @@ -9863,10 +11401,10 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: get_started in: query - schema: &ref_135 + schema: &ref_194 type: boolean responses: '200': @@ -9900,7 +11438,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 responses: '200': description: job details @@ -9908,8 +11446,8 @@ paths: application/json: schema: type: object - properties: *ref_87 - required: *ref_88 + properties: *ref_106 + required: *ref_107 /w/{workspace}/jobs_u/queue/cancel/{id}: post: summary: cancel queued or running job @@ -9924,7 +11462,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 requestBody: description: reason required: true @@ -9956,7 +11494,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 requestBody: description: reason required: true @@ -9988,7 +11526,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 requestBody: description: reason required: true @@ -10020,7 +11558,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: resume_id in: path required: true @@ -10051,7 +11589,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: resume_id in: path required: true @@ -10079,6 +11617,108 @@ paths: - approvalPage - resume - cancel + /w/{workspace}/jobs/slack_approval/{id}: + get: + summary: generate interactive slack approval for suspended job + operationId: getSlackApprovalPayload + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: id + in: path + required: true + schema: *ref_110 + - name: approver + in: query + schema: + type: string + - name: message + in: query + schema: + type: string + - name: slack_resource_path + in: query + required: true + schema: + type: string + - name: channel_id + in: query + required: true + schema: + type: string + - name: flow_step_id + in: query + required: true + schema: + type: string + - name: default_args_json + in: query + required: false + schema: + type: string + - name: dynamic_enums_json + in: query + required: false + schema: + type: string + responses: + '200': + description: Interactive slack approval message sent successfully + /w/{workspace}/jobs/teams_approval/{id}: + get: + summary: generate interactive teams approval for suspended job + operationId: getTeamsApprovalPayload + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: id + in: path + required: true + schema: *ref_110 + - name: approver + in: query + schema: + type: string + - name: message + in: query + schema: + type: string + - name: team_name + in: query + required: true + schema: + type: string + - name: channel_name + in: query + required: true + schema: + type: string + - name: flow_step_id + in: query + required: true + schema: + type: string + - name: default_args_json + in: query + required: false + schema: + type: string + - name: dynamic_enums_json + in: query + required: false + schema: + type: string + responses: + '200': + description: Interactive slack approval message sent successfully /w/{workspace}/jobs_u/resume/{id}/{resume_id}/{signature}: get: summary: resume a job for a suspended flow @@ -10093,7 +11733,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: payload description: > The base64 encoded payload that has been encoded as a JSON. e.g how @@ -10101,7 +11741,7 @@ paths: `encodeURIComponent(btoa(JSON.stringify({a: 2})))` in: query - schema: *ref_94 + schema: *ref_113 - name: resume_id in: path required: true @@ -10136,7 +11776,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: resume_id in: path required: true @@ -10178,7 +11818,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: key in: path required: true @@ -10210,7 +11850,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: key in: path required: true @@ -10236,7 +11876,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 requestBody: required: true content: @@ -10264,7 +11904,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: resume_id in: path required: true @@ -10299,7 +11939,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: resume_id in: path required: true @@ -10341,7 +11981,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 - name: resume_id in: path required: true @@ -10365,8 +12005,8 @@ paths: type: object properties: job: - oneOf: *ref_92 - discriminator: *ref_93 + oneOf: *ref_111 + discriminator: *ref_112 approvers: type: array items: @@ -10400,6 +12040,8 @@ paths: type: string timezone: type: string + cron_version: + type: string required: - schedule - timezone @@ -10431,7 +12073,7 @@ paths: application/json: schema: type: object - properties: &ref_171 + properties: &ref_236 path: type: string schedule: @@ -10444,7 +12086,7 @@ paths: type: boolean args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 enabled: type: boolean on_failure: @@ -10455,34 +12097,38 @@ paths: type: boolean on_failure_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 on_recovery: type: string on_recovery_times: type: number on_recovery_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 on_success: type: string on_success_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 ws_error_handler_muted: type: boolean retry: type: object - properties: *ref_95 + properties: *ref_114 no_flow_overlap: type: boolean summary: type: string + description: + type: string tag: type: string paused_until: type: string format: date-time - required: &ref_172 + cron_version: + type: string + required: &ref_237 - path - schedule - timezone @@ -10510,7 +12156,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 requestBody: description: updated schedule required: true @@ -10518,14 +12164,14 @@ paths: application/json: schema: type: object - properties: &ref_173 + properties: &ref_238 schedule: type: string timezone: type: string args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 on_failure: type: string on_failure_times: @@ -10534,34 +12180,38 @@ paths: type: boolean on_failure_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 on_recovery: type: string on_recovery_times: type: number on_recovery_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 on_success: type: string on_success_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 ws_error_handler_muted: type: boolean retry: type: object - properties: *ref_95 + properties: *ref_114 no_flow_overlap: type: boolean summary: type: string + description: + type: string tag: type: string paused_until: type: string format: date-time - required: &ref_174 + cron_version: + type: string + required: &ref_239 - schedule - timezone - script_path @@ -10588,7 +12238,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 requestBody: description: updated schedule enable required: true @@ -10622,7 +12272,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: schedule deleted @@ -10644,7 +12294,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: schedule deleted @@ -10652,7 +12302,7 @@ paths: application/json: schema: type: object - properties: &ref_96 + properties: &ref_115 path: type: string edited_by: @@ -10672,7 +12322,7 @@ paths: type: boolean args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 extra_perms: type: object additionalProperties: @@ -10689,26 +12339,28 @@ paths: type: boolean on_failure_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 on_recovery: type: string on_recovery_times: type: number on_recovery_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 on_success: type: string on_success_extra_args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 ws_error_handler_muted: type: boolean retry: type: object - properties: *ref_95 + properties: *ref_114 summary: type: string + description: + type: string no_flow_overlap: type: boolean tag: @@ -10716,7 +12368,9 @@ paths: paused_until: type: string format: date-time - required: &ref_97 + cron_version: + type: string + required: &ref_116 - path - edited_by - edited_at @@ -10741,7 +12395,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: schedule exists @@ -10773,7 +12427,7 @@ paths: filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: *ref_81 + schema: *ref_93 - name: path description: filter by path in: query @@ -10796,8 +12450,8 @@ paths: type: array items: type: object - properties: *ref_96 - required: *ref_97 + properties: *ref_115 + required: *ref_116 /w/{workspace}/schedules/list_with_jobs: get: summary: list schedules with last 20 jobs @@ -10825,10 +12479,10 @@ paths: schema: type: array items: - allOf: &ref_170 + allOf: &ref_235 - type: object - properties: *ref_96 - required: *ref_97 + properties: *ref_115 + required: *ref_116 - type: object properties: jobs: @@ -10907,13 +12561,15 @@ paths: application/json: schema: type: object - properties: &ref_175 + properties: &ref_240 path: type: string script_path: type: string route_path: type: string + workspaced_route: + type: boolean static_asset_config: type: object properties: @@ -10935,18 +12591,34 @@ paths: - put - delete - patch + authentication_resource_path: + type: string is_async: type: boolean - requires_auth: + authentication_method: + type: string + enum: &ref_117 + - none + - windmill + - api_key + - basic_http + - custom_script + - signature + is_static_website: type: boolean - required: &ref_176 + wrap_body: + type: boolean + raw_string: + type: boolean + required: &ref_241 - path - script_path - route_path - is_flow - is_async - - requires_auth + - authentication_method - http_method + - is_static_website responses: '201': description: http trigger created @@ -10968,7 +12640,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 requestBody: description: updated trigger required: true @@ -10976,13 +12648,15 @@ paths: application/json: schema: type: object - properties: &ref_177 + properties: &ref_242 path: type: string script_path: type: string route_path: type: string + workspaced_route: + type: boolean static_asset_config: type: object properties: @@ -10994,6 +12668,8 @@ paths: type: string required: - s3 + authentication_resource_path: + type: string is_flow: type: boolean http_method: @@ -11006,16 +12682,24 @@ paths: - patch is_async: type: boolean - requires_auth: + authentication_method: + type: string + enum: *ref_117 + is_static_website: type: boolean - required: &ref_178 + wrap_body: + type: boolean + raw_string: + type: boolean + required: &ref_243 - path - script_path - is_flow - kind - is_async - - requires_auth + - authentication_method - http_method + - is_static_website responses: '200': description: http trigger updated @@ -11037,7 +12721,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: http trigger deleted @@ -11059,24 +12743,46 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: http trigger deleted content: application/json: schema: + allOf: &ref_118 + - type: object + properties: &ref_122 + path: + type: string + script_path: + type: string + email: + type: string + extra_perms: + type: object + additionalProperties: + type: boolean + workspace_id: + type: string + edited_by: + type: string + edited_at: + type: string + format: date-time + is_flow: + type: boolean + required: &ref_123 + - path + - script_path + - email + - extra_perms + - workspace_id + - edited_by + - edited_at + - is_flow type: object - properties: &ref_98 - path: - type: string - edited_by: - type: string - edited_at: - type: string - format: date-time - script_path: - type: string + properties: &ref_119 route_path: type: string static_asset_config: @@ -11090,16 +12796,6 @@ paths: type: string required: - s3 - is_flow: - type: boolean - extra_perms: - type: object - additionalProperties: - type: boolean - email: - type: string - workspace_id: - type: string http_method: type: string enum: @@ -11108,23 +12804,30 @@ paths: - put - delete - patch + authentication_resource_path: + type: string is_async: type: boolean - requires_auth: + authentication_method: + type: string + enum: *ref_117 + is_static_website: type: boolean - required: &ref_99 - - path - - edited_by - - edited_at - - script_path + workspaced_route: + type: boolean + wrap_body: + type: boolean + raw_string: + type: boolean + required: &ref_120 - route_path - - extra_perms - - is_flow - - email - - workspace_id - is_async - - requires_auth + - authentication_method - http_method + - is_static_website + - workspaced_route + - wrap_body + - raw_string /w/{workspace}/http_triggers/list: get: summary: list http triggers @@ -11165,9 +12868,10 @@ paths: schema: type: array items: + allOf: *ref_118 type: object - properties: *ref_98 - required: *ref_99 + properties: *ref_119 + required: *ref_120 /w/{workspace}/http_triggers/exists/{path}: get: summary: does http trigger exists @@ -11182,7 +12886,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: http trigger exists @@ -11219,8 +12923,11 @@ paths: - put - delete - patch + trigger_path: + type: string + workspaced_route: + type: boolean required: - - kind - route_path - http_method responses: @@ -11248,7 +12955,7 @@ paths: application/json: schema: type: object - properties: &ref_179 + properties: &ref_244 path: type: string script_path: @@ -11273,7 +12980,7 @@ paths: initial_messages: type: array items: - anyOf: &ref_100 + anyOf: &ref_121 - type: object properties: raw_message: @@ -11289,7 +12996,7 @@ paths: type: string args: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 is_flow: type: boolean required: @@ -11300,15 +13007,16 @@ paths: - runnable_result url_runnable_args: type: object - additionalProperties: *ref_18 - required: &ref_180 + additionalProperties: *ref_21 + can_return_message: + type: boolean + required: &ref_245 - path - script_path - url - is_flow - filters - - initial_messages - - url_runnable_args + - can_return_message responses: '201': description: websocket trigger created @@ -11330,7 +13038,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 requestBody: description: updated trigger required: true @@ -11338,7 +13046,7 @@ paths: application/json: schema: type: object - properties: &ref_181 + properties: &ref_246 url: type: string path: @@ -11361,18 +13069,19 @@ paths: initial_messages: type: array items: - anyOf: *ref_100 + anyOf: *ref_121 url_runnable_args: type: object - additionalProperties: *ref_18 - required: &ref_182 + additionalProperties: *ref_21 + can_return_message: + type: boolean + required: &ref_247 - path - script_path - url - is_flow - filters - - initial_messages - - url_runnable_args + - can_return_message responses: '200': description: websocket trigger updated @@ -11394,7 +13103,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: websocket trigger deleted @@ -11416,36 +13125,21 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: websocket trigger deleted content: application/json: schema: + allOf: &ref_124 + - type: object + properties: *ref_122 + required: *ref_123 type: object - properties: &ref_101 - path: - type: string - edited_by: - type: string - edited_at: - type: string - format: date-time - script_path: - type: string + properties: &ref_125 url: type: string - is_flow: - type: boolean - extra_perms: - type: object - additionalProperties: - type: boolean - email: - type: string - workspace_id: - type: string server_id: type: string last_server_ping: @@ -11469,24 +13163,17 @@ paths: initial_messages: type: array items: - anyOf: *ref_100 + anyOf: *ref_121 url_runnable_args: type: object - additionalProperties: *ref_18 - required: &ref_102 - - path - - edited_by - - edited_at - - script_path + additionalProperties: *ref_21 + can_return_message: + type: boolean + required: &ref_126 - url - - extra_perms - - is_flow - - email - - workspace_id - enabled - filters - - initial_messages - - url_runnable_args + - can_return_message /w/{workspace}/websocket_triggers/list: get: summary: list websocket triggers @@ -11527,9 +13214,10 @@ paths: schema: type: array items: + allOf: *ref_124 type: object - properties: *ref_101 - required: *ref_102 + properties: *ref_125 + required: *ref_126 /w/{workspace}/websocket_triggers/exists/{path}: get: summary: does websocket trigger exists @@ -11544,7 +13232,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: websocket trigger exists @@ -11566,7 +13254,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 requestBody: description: updated websocket trigger enable required: true @@ -11586,6 +13274,2400 @@ paths: text/plain: schema: type: string + /w/{workspace}/websocket_triggers/test: + post: + summary: test websocket connection + operationId: testWebsocketConnection + tags: + - websocket_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: test websocket connection + required: true + content: + application/json: + schema: + type: object + properties: + url: + type: string + url_runnable_args: + type: object + additionalProperties: *ref_21 + can_return_message: + type: boolean + required: + - url + - can_return_message + responses: + '200': + description: successfuly connected to websocket + content: + text/plain: + schema: + type: string + /w/{workspace}/kafka_triggers/create: + post: + summary: create kafka trigger + operationId: createKafkaTrigger + tags: + - kafka_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: new kafka trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_270 + path: + type: string + script_path: + type: string + is_flow: + type: boolean + kafka_resource_path: + type: string + group_id: + type: string + topics: + type: array + items: + type: string + enabled: + type: boolean + required: &ref_271 + - path + - script_path + - is_flow + - kafka_resource_path + - group_id + - topics + responses: + '201': + description: kafka trigger created + content: + text/plain: + schema: + type: string + /w/{workspace}/kafka_triggers/update/{path}: + post: + summary: update kafka trigger + operationId: updateKafkaTrigger + tags: + - kafka_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_272 + kafka_resource_path: + type: string + group_id: + type: string + topics: + type: array + items: + type: string + path: + type: string + script_path: + type: string + is_flow: + type: boolean + required: &ref_273 + - path + - script_path + - kafka_resource_path + - group_id + - topics + - is_flow + responses: + '200': + description: kafka trigger updated + content: + text/plain: + schema: + type: string + /w/{workspace}/kafka_triggers/delete/{path}: + delete: + summary: delete kafka trigger + operationId: deleteKafkaTrigger + tags: + - kafka_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: kafka trigger deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/kafka_triggers/get/{path}: + get: + summary: get kafka trigger + operationId: getKafkaTrigger + tags: + - kafka_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: kafka trigger deleted + content: + application/json: + schema: + allOf: &ref_127 + - type: object + properties: *ref_122 + required: *ref_123 + type: object + properties: &ref_128 + kafka_resource_path: + type: string + group_id: + type: string + topics: + type: array + items: + type: string + server_id: + type: string + last_server_ping: + type: string + format: date-time + error: + type: string + enabled: + type: boolean + required: &ref_129 + - kafka_resource_path + - group_id + - topics + - enabled + /w/{workspace}/kafka_triggers/list: + get: + summary: list kafka triggers + operationId: listKafkaTriggers + tags: + - kafka_trigger + parameters: + - required: true + name: workspace + in: path + schema: *ref_0 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - 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: kafka trigger list + content: + application/json: + schema: + type: array + items: + allOf: *ref_127 + type: object + properties: *ref_128 + required: *ref_129 + /w/{workspace}/kafka_triggers/exists/{path}: + get: + summary: does kafka trigger exists + operationId: existsKafkaTrigger + tags: + - kafka_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: kafka trigger exists + content: + application/json: + schema: + type: boolean + /w/{workspace}/kafka_triggers/setenabled/{path}: + post: + summary: set enabled kafka trigger + operationId: setKafkaTriggerEnabled + tags: + - kafka_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated kafka trigger enable + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + '200': + description: kafka trigger enabled set + content: + text/plain: + schema: + type: string + /w/{workspace}/kafka_triggers/test: + post: + summary: test kafka connection + operationId: testKafkaConnection + tags: + - kafka_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: test kafka connection + required: true + content: + application/json: + schema: + type: object + properties: + connection: + type: object + required: + - connection + responses: + '200': + description: successfuly connected to kafka brokers + content: + text/plain: + schema: + type: string + /w/{workspace}/nats_triggers/create: + post: + summary: create nats trigger + operationId: createNatsTrigger + tags: + - nats_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: new nats trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_274 + path: + type: string + script_path: + type: string + is_flow: + type: boolean + nats_resource_path: + type: string + use_jetstream: + type: boolean + stream_name: + type: string + consumer_name: + type: string + subjects: + type: array + items: + type: string + enabled: + type: boolean + required: &ref_275 + - path + - script_path + - is_flow + - nats_resource_path + - use_jetstream + - subjects + responses: + '201': + description: nats trigger created + content: + text/plain: + schema: + type: string + /w/{workspace}/nats_triggers/update/{path}: + post: + summary: update nats trigger + operationId: updateNatsTrigger + tags: + - nats_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_276 + nats_resource_path: + type: string + use_jetstream: + type: boolean + stream_name: + type: string + consumer_name: + type: string + subjects: + type: array + items: + type: string + path: + type: string + script_path: + type: string + is_flow: + type: boolean + required: &ref_277 + - path + - script_path + - nats_resource_path + - use_jetstream + - subjects + - is_flow + responses: + '200': + description: nats trigger updated + content: + text/plain: + schema: + type: string + /w/{workspace}/nats_triggers/delete/{path}: + delete: + summary: delete nats trigger + operationId: deleteNatsTrigger + tags: + - nats_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: nats trigger deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/nats_triggers/get/{path}: + get: + summary: get nats trigger + operationId: getNatsTrigger + tags: + - nats_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: nats trigger deleted + content: + application/json: + schema: + allOf: &ref_130 + - type: object + properties: *ref_122 + required: *ref_123 + type: object + properties: &ref_131 + nats_resource_path: + type: string + use_jetstream: + type: boolean + stream_name: + type: string + consumer_name: + type: string + subjects: + type: array + items: + type: string + server_id: + type: string + last_server_ping: + type: string + format: date-time + error: + type: string + enabled: + type: boolean + required: &ref_132 + - nats_resource_path + - use_jetstream + - subjects + - enabled + /w/{workspace}/nats_triggers/list: + get: + summary: list nats triggers + operationId: listNatsTriggers + tags: + - nats_trigger + parameters: + - required: true + name: workspace + in: path + schema: *ref_0 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - 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: nats trigger list + content: + application/json: + schema: + type: array + items: + allOf: *ref_130 + type: object + properties: *ref_131 + required: *ref_132 + /w/{workspace}/nats_triggers/exists/{path}: + get: + summary: does nats trigger exists + operationId: existsNatsTrigger + tags: + - nats_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: nats trigger exists + content: + application/json: + schema: + type: boolean + /w/{workspace}/nats_triggers/setenabled/{path}: + post: + summary: set enabled nats trigger + operationId: setNatsTriggerEnabled + tags: + - nats_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated nats trigger enable + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + '200': + description: nats trigger enabled set + content: + text/plain: + schema: + type: string + /w/{workspace}/nats_triggers/test: + post: + summary: test NATS connection + operationId: testNatsConnection + tags: + - nats_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: test nats connection + required: true + content: + application/json: + schema: + type: object + properties: + connection: + type: object + required: + - connection + responses: + '200': + description: successfuly connected to NATS servers + content: + text/plain: + schema: + type: string + /w/{workspace}/sqs_triggers/create: + post: + summary: create sqs trigger + operationId: createSqsTrigger + tags: + - sqs_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: new sqs trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_257 + queue_url: + type: string + aws_auth_resource_type: + type: string + enum: &ref_133 + - oidc + - credentials + aws_resource_path: + type: string + message_attributes: + type: array + items: + type: string + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + required: &ref_258 + - queue_url + - aws_resource_path + - path + - script_path + - is_flow + - aws_auth_resource_type + responses: + '201': + description: sqs trigger created + content: + text/plain: + schema: + type: string + /w/{workspace}/sqs_triggers/update/{path}: + post: + summary: update sqs trigger + operationId: updateSqsTrigger + tags: + - sqs_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_259 + queue_url: + type: string + aws_auth_resource_type: + type: string + enum: *ref_133 + aws_resource_path: + type: string + message_attributes: + type: array + items: + type: string + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + required: &ref_260 + - queue_url + - aws_resource_path + - path + - script_path + - is_flow + - enabled + - aws_auth_resource_type + responses: + '200': + description: sqs trigger updated + content: + text/plain: + schema: + type: string + /w/{workspace}/sqs_triggers/delete/{path}: + delete: + summary: delete sqs trigger + operationId: deleteSqsTrigger + tags: + - sqs_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: sqs trigger deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/sqs_triggers/get/{path}: + get: + summary: get sqs trigger + operationId: getSqsTrigger + tags: + - sqs_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: sqs trigger deleted + content: + application/json: + schema: + allOf: &ref_134 + - type: object + properties: *ref_122 + required: *ref_123 + type: object + properties: &ref_135 + queue_url: + type: string + aws_auth_resource_type: + type: string + enum: *ref_133 + aws_resource_path: + type: string + message_attributes: + type: array + items: + type: string + server_id: + type: string + last_server_ping: + type: string + format: date-time + error: + type: string + enabled: + type: boolean + required: &ref_136 + - queue_url + - aws_resource_path + - enabled + - aws_auth_resource_type + /w/{workspace}/sqs_triggers/list: + get: + summary: list sqs triggers + operationId: listSqsTriggers + tags: + - sqs_trigger + parameters: + - required: true + name: workspace + in: path + schema: *ref_0 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - 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: sqs trigger list + content: + application/json: + schema: + type: array + items: + allOf: *ref_134 + type: object + properties: *ref_135 + required: *ref_136 + /w/{workspace}/sqs_triggers/exists/{path}: + get: + summary: does sqs trigger exists + operationId: existsSqsTrigger + tags: + - sqs_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: sqs trigger exists + content: + application/json: + schema: + type: boolean + /w/{workspace}/sqs_triggers/setenabled/{path}: + post: + summary: set enabled sqs trigger + operationId: setSqsTriggerEnabled + tags: + - sqs_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated sqs trigger enable + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + '200': + description: sqs trigger enabled set + content: + text/plain: + schema: + type: string + /w/{workspace}/sqs_triggers/test: + post: + summary: test sqs connection + operationId: testSqsConnection + tags: + - sqs_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: test sqs connection + required: true + content: + application/json: + schema: + type: object + properties: + connection: + type: object + required: + - connection + responses: + '200': + description: successfuly connected to sqs + content: + text/plain: + schema: + type: string + /w/{workspace}/mqtt_triggers/create: + post: + summary: create mqtt trigger + operationId: createMqttTrigger + tags: + - mqtt_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: new mqtt trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_249 + mqtt_resource_path: + type: string + subscribe_topics: + type: array + items: + type: object + properties: &ref_137 + qos: + type: string + enum: &ref_248 + - qos0 + - qos1 + - qos2 + topic: + type: string + required: &ref_138 + - qos + - topic + client_id: + type: string + v3_config: + type: object + properties: &ref_139 + clean_session: + type: boolean + v5_config: + type: object + properties: &ref_140 + clean_start: + type: boolean + topic_alias: + type: number + session_expiry_interval: + type: number + client_version: + type: string + enum: &ref_141 + - v3 + - v5 + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + required: &ref_250 + - path + - script_path + - is_flow + - subscribe_topics + - mqtt_resource_path + responses: + '201': + description: mqtt trigger created + content: + text/plain: + schema: + type: string + /w/{workspace}/mqtt_triggers/update/{path}: + post: + summary: update mqtt trigger + operationId: updateMqttTrigger + tags: + - mqtt_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_251 + mqtt_resource_path: + type: string + subscribe_topics: + type: array + items: + type: object + properties: *ref_137 + required: *ref_138 + client_id: + type: string + v3_config: + type: object + properties: *ref_139 + v5_config: + type: object + properties: *ref_140 + client_version: + type: string + enum: *ref_141 + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + required: &ref_252 + - path + - script_path + - is_flow + - enabled + - subscribe_topics + - mqtt_resource_path + responses: + '200': + description: mqtt trigger updated + content: + text/plain: + schema: + type: string + /w/{workspace}/mqtt_triggers/delete/{path}: + delete: + summary: delete mqtt trigger + operationId: deleteMqttTrigger + tags: + - mqtt_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: mqtt trigger deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/mqtt_triggers/get/{path}: + get: + summary: get mqtt trigger + operationId: getMqttTrigger + tags: + - mqtt_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: mqtt trigger deleted + content: + application/json: + schema: + allOf: &ref_142 + - type: object + properties: *ref_122 + required: *ref_123 + type: object + properties: &ref_143 + mqtt_resource_path: + type: string + subscribe_topics: + type: array + items: + type: object + properties: *ref_137 + required: *ref_138 + v3_config: + type: object + properties: *ref_139 + v5_config: + type: object + properties: *ref_140 + client_id: + type: string + client_version: + type: string + enum: *ref_141 + server_id: + type: string + last_server_ping: + type: string + format: date-time + error: + type: string + enabled: + type: boolean + required: &ref_144 + - enabled + - subscribe_topics + - mqtt_resource_path + /w/{workspace}/mqtt_triggers/list: + get: + summary: list mqtt triggers + operationId: listMqttTriggers + tags: + - mqtt_trigger + parameters: + - required: true + name: workspace + in: path + schema: *ref_0 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - 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: mqtt trigger list + content: + application/json: + schema: + type: array + items: + allOf: *ref_142 + type: object + properties: *ref_143 + required: *ref_144 + /w/{workspace}/mqtt_triggers/exists/{path}: + get: + summary: does mqtt trigger exists + operationId: existsMqttTrigger + tags: + - mqtt_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: mqtt trigger exists + content: + application/json: + schema: + type: boolean + /w/{workspace}/mqtt_triggers/setenabled/{path}: + post: + summary: set enabled mqtt trigger + operationId: setMqttTriggerEnabled + tags: + - mqtt_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated mqtt trigger enable + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + '200': + description: mqtt trigger enabled set + content: + text/plain: + schema: + type: string + /w/{workspace}/mqtt_triggers/test: + post: + summary: test mqtt connection + operationId: testMqttConnection + tags: + - mqtt_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: test mqtt connection + required: true + content: + application/json: + schema: + type: object + properties: + connection: + type: object + required: + - connection + responses: + '200': + description: successfully connected to mqtt + content: + text/plain: + schema: + type: string + /w/{workspace}/gcp_triggers/create: + post: + summary: create gcp trigger + operationId: createGcpTrigger + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: new gcp trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_145 + gcp_resource_path: + type: string + subscription_mode: + type: string + enum: &ref_150 + - existing + - create_update + description: >- + The mode of subscription. 'existing' means using an existing + GCP subscription, while 'create_update' involves creating or + updating a new subscription. + topic_id: + type: string + subscription_id: + type: string + base_endpoint: + type: string + delivery_type: + type: string + enum: &ref_147 + - push + - pull + delivery_config: + type: object + properties: &ref_148 + audience: + type: string + authenticate: + type: boolean + required: &ref_149 + - authenticate + - base_endpoint + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + required: &ref_146 + - path + - script_path + - is_flow + - gcp_resource_path + - topic_id + - subscription_mode + responses: + '201': + description: gcp trigger created + content: + text/plain: + schema: + type: string + /w/{workspace}/gcp_triggers/update/{path}: + post: + summary: update gcp trigger + operationId: updateGcpTrigger + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + type: object + properties: *ref_145 + required: *ref_146 + responses: + '200': + description: gcp trigger updated + content: + text/plain: + schema: + type: string + /w/{workspace}/gcp_triggers/delete/{path}: + delete: + summary: delete gcp trigger + operationId: deleteGcpTrigger + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: gcp trigger deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/gcp_triggers/get/{path}: + get: + summary: get gcp trigger + operationId: getGcpTrigger + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: gcp trigger deleted + content: + application/json: + schema: + allOf: &ref_151 + - type: object + properties: *ref_122 + required: *ref_123 + type: object + properties: &ref_152 + gcp_resource_path: + type: string + topic_id: + type: string + subscription_id: + type: string + server_id: + type: string + delivery_type: + type: string + enum: *ref_147 + delivery_config: + type: object + properties: *ref_148 + required: *ref_149 + subscription_mode: + type: string + enum: *ref_150 + description: >- + The mode of subscription. 'existing' means using an + existing GCP subscription, while 'create_update' involves + creating or updating a new subscription. + last_server_ping: + type: string + format: date-time + error: + type: string + enabled: + type: boolean + required: &ref_153 + - gcp_resource_path + - topic_id + - subscription_id + - enabled + - delivery_type + - subscription_mode + /w/{workspace}/gcp_triggers/list: + get: + summary: list gcp triggers + operationId: listGcpTriggers + tags: + - gcp_trigger + parameters: + - required: true + name: workspace + in: path + schema: *ref_0 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - 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: gcp trigger list + content: + application/json: + schema: + type: array + items: + allOf: *ref_151 + type: object + properties: *ref_152 + required: *ref_153 + /w/{workspace}/gcp_triggers/exists/{path}: + get: + summary: does gcp trigger exists + operationId: existsGcpTrigger + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: gcp trigger exists + content: + application/json: + schema: + type: boolean + /w/{workspace}/gcp_triggers/setenabled/{path}: + post: + summary: set enabled gcp trigger + operationId: setGcpTriggerEnabled + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated gcp trigger enable + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + '200': + description: gcp trigger enabled set + content: + text/plain: + schema: + type: string + /w/{workspace}/gcp_triggers/test: + post: + summary: test gcp connection + operationId: testGcpConnection + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: test gcp connection + required: true + content: + application/json: + schema: + type: object + properties: + connection: + type: object + required: + - connection + responses: + '200': + description: try to connect to a gcp broker + content: + text/plain: + schema: + type: string + /w/{workspace}/gcp_triggers/subscriptions/delete/{path}: + delete: + summary: delete gcp trigger + operationId: deleteGcpSubscription + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: args to delete subscription from google cloud + required: true + content: + application/json: + schema: + type: object + properties: &ref_255 + subscription_id: + type: string + required: &ref_256 + - subscription_id + responses: + '200': + description: gcp trigger deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/gcp_triggers/topics/list/{path}: + get: + summary: list all topics of google cloud service + operationId: listGoogleTopics + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: get all google topics + content: + application/json: + schema: + type: array + items: + type: string + /w/{workspace}/gcp_triggers/subscriptions/list/{path}: + post: + summary: list all subscription of a give topic from google cloud service + operationId: listAllTGoogleTopicSubscriptions + tags: + - gcp_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: args to get subscription's topic from google cloud + required: true + content: + application/json: + schema: + type: object + properties: &ref_253 + topic_id: + type: string + required: &ref_254 + - topic_id + responses: + '200': + description: get all google topic subscriptions name + content: + application/json: + schema: + type: array + items: + type: string + /w/{workspace}/postgres_triggers/is_valid_postgres_configuration/{path}: + get: + summary: check if postgres configuration is set to logical + operationId: isValidPostgresConfiguration + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: boolean that indicates if postgres is set to logical level or not + content: + application/json: + schema: + type: boolean + /w/{workspace}/postgres_triggers/create_template_script: + post: + summary: create template script + operationId: createTemplateScript + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: template script + required: true + content: + application/json: + schema: + type: object + properties: &ref_264 + postgres_resource_path: + type: string + relations: + type: array + items: + type: object + properties: &ref_155 + schema_name: + type: string + table_to_track: + type: array + items: &ref_262 + type: object + properties: + table_name: + type: string + columns_name: + type: array + items: + type: string + where_clause: + type: string + required: + - table_name + required: &ref_156 + - schema_name + - table_to_track + language: + type: string + enum: &ref_263 + - Typescript + required: &ref_265 + - postgres_resource_path + - relations + - language + responses: + '200': + description: custom id to retrieve template script + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/get_template_script/{id}: + get: + summary: get template script + operationId: getTemplateScript + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: id + in: path + required: true + schema: &ref_185 + type: string + responses: + '200': + description: template script + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/slot/list/{path}: + get: + summary: list postgres replication slot + operationId: listPostgresReplicationSlot + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: list postgres slot + content: + application/json: + schema: + type: array + items: + type: object + properties: &ref_261 + slot_name: + type: string + active: + type: boolean + /w/{workspace}/postgres_triggers/slot/create/{path}: + post: + summary: create replication slot for postgres + operationId: createPostgresReplicationSlot + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: new slot for postgres + required: true + content: + application/json: + schema: + type: object + properties: &ref_154 + name: + type: string + responses: + '201': + description: slot created + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/slot/delete/{path}: + delete: + summary: delete postgres replication slot + operationId: deletePostgresReplicationSlot + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: replication slot of postgres + required: true + content: + application/json: + schema: + type: object + properties: *ref_154 + responses: + '200': + description: postgres replication slot deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/publication/list/{path}: + get: + summary: list postgres publication + operationId: listPostgresPublication + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: database publication list + content: + application/json: + schema: + type: array + items: + type: string + /w/{workspace}/postgres_triggers/publication/get/{publication}/{path}: + get: + summary: get postgres publication + operationId: getPostgresPublication + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + - name: publication + in: path + required: true + schema: &ref_157 + type: string + responses: + '200': + description: postgres publication get + content: + application/json: + schema: + type: object + properties: &ref_158 + table_to_track: + type: array + items: + type: object + properties: *ref_155 + required: *ref_156 + transaction_to_track: + type: array + items: + type: string + required: &ref_159 + - transaction_to_track + /w/{workspace}/postgres_triggers/publication/create/{publication}/{path}: + post: + summary: create publication for postgres + operationId: createPostgresPublication + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + - name: publication + in: path + required: true + schema: *ref_157 + requestBody: + description: new publication for postgres + required: true + content: + application/json: + schema: + type: object + properties: *ref_158 + required: *ref_159 + responses: + '201': + description: publication created + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/publication/update/{publication}/{path}: + post: + summary: update publication for postgres + operationId: updatePostgresPublication + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + - name: publication + in: path + required: true + schema: *ref_157 + requestBody: + description: update publication for postgres + required: true + content: + application/json: + schema: + type: object + properties: *ref_158 + required: *ref_159 + responses: + '201': + description: publication updated + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/publication/delete/{publication}/{path}: + delete: + summary: delete postgres publication + operationId: deletePostgresPublication + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + - name: publication + in: path + required: true + schema: *ref_157 + responses: + '200': + description: postgres publication deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/create: + post: + summary: create postgres trigger + operationId: createPostgresTrigger + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: new postgres trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_266 + replication_slot_name: + type: string + publication_name: + type: string + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + postgres_resource_path: + type: string + publication: + type: object + properties: *ref_158 + required: *ref_159 + required: &ref_267 + - path + - script_path + - is_flow + - enabled + - postgres_resource_path + responses: + '201': + description: postgres trigger created + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/update/{path}: + post: + summary: update postgres trigger + operationId: updatePostgresTrigger + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_268 + replication_slot_name: + type: string + publication_name: + type: string + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + postgres_resource_path: + type: string + publication: + type: object + properties: *ref_158 + required: *ref_159 + required: &ref_269 + - path + - script_path + - is_flow + - enabled + - postgres_resource_path + - publication_name + - replication_slot_name + responses: + '200': + description: postgres trigger updated + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/delete/{path}: + delete: + summary: delete postgres trigger + operationId: deletePostgresTrigger + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: postgres trigger deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/get/{path}: + get: + summary: get postgres trigger + operationId: getPostgresTrigger + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: get postgres trigger + content: + application/json: + schema: + allOf: &ref_160 + - type: object + properties: *ref_122 + required: *ref_123 + type: object + properties: &ref_161 + enabled: + type: boolean + postgres_resource_path: + type: string + publication_name: + type: string + server_id: + type: string + replication_slot_name: + type: string + error: + type: string + last_server_ping: + type: string + format: date-time + required: &ref_162 + - enabled + - postgres_resource_path + - replication_slot_name + - publication_name + /w/{workspace}/postgres_triggers/list: + get: + summary: list postgres triggers + operationId: listPostgresTriggers + tags: + - postgres_trigger + parameters: + - required: true + name: workspace + in: path + schema: *ref_0 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - 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: postgres trigger list + content: + application/json: + schema: + type: array + items: + allOf: *ref_160 + type: object + properties: *ref_161 + required: *ref_162 + /w/{workspace}/postgres_triggers/exists/{path}: + get: + summary: does postgres trigger exists + operationId: existsPostgresTrigger + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: postgres trigger exists + content: + application/json: + schema: + type: boolean + /w/{workspace}/postgres_triggers/setenabled/{path}: + post: + summary: set enabled postgres trigger + operationId: setPostgresTriggerEnabled + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: updated postgres trigger enable + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + '200': + description: postgres trigger enabled set + content: + text/plain: + schema: + type: string + /w/{workspace}/postgres_triggers/test: + post: + summary: test postgres connection + operationId: testPostgresConnection + tags: + - postgres_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: test postgres connection + required: true + content: + application/json: + schema: + type: object + properties: + database: + type: string + required: + - database + responses: + '200': + description: successfuly connected to postgres + content: + text/plain: + schema: + type: string /groups/list: get: summary: list instance groups @@ -11601,7 +15683,7 @@ paths: type: array items: type: object - properties: &ref_104 + properties: &ref_164 name: type: string summary: @@ -11610,7 +15692,7 @@ paths: type: array items: type: string - required: &ref_105 + required: &ref_165 - name /groups/get/{name}: get: @@ -11622,7 +15704,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 responses: '200': description: instance group @@ -11630,8 +15712,8 @@ paths: application/json: schema: type: object - properties: *ref_104 - required: *ref_105 + properties: *ref_164 + required: *ref_165 /groups/create: post: summary: create instance group @@ -11669,7 +15751,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: update instance group required: true @@ -11699,7 +15781,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 responses: '200': description: instance group deleted @@ -11717,7 +15799,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: user to add to instance group required: true @@ -11747,7 +15829,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: user to remove from instance group required: true @@ -11782,7 +15864,7 @@ paths: type: array items: type: object - properties: &ref_106 + properties: &ref_166 name: type: string summary: @@ -11797,7 +15879,7 @@ paths: type: string external_id: type: string - required: &ref_107 + required: &ref_167 - name /groups/overwrite: post: @@ -11814,8 +15896,8 @@ paths: type: array items: type: object - properties: *ref_106 - required: *ref_107 + properties: *ref_166 + required: *ref_167 responses: '200': description: success message @@ -11851,7 +15933,7 @@ paths: type: array items: type: object - properties: &ref_108 + properties: &ref_168 name: type: string summary: @@ -11864,7 +15946,7 @@ paths: type: object additionalProperties: type: boolean - required: &ref_109 + required: &ref_169 - name /w/{workspace}/groups/listnames: get: @@ -11937,7 +16019,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: updated group required: true @@ -11969,7 +16051,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 responses: '200': description: group deleted @@ -11991,7 +16073,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 responses: '200': description: group @@ -11999,8 +16081,8 @@ paths: application/json: schema: type: object - properties: *ref_108 - required: *ref_109 + properties: *ref_168 + required: *ref_169 /w/{workspace}/groups/adduser/{name}: post: summary: add user to group @@ -12015,7 +16097,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: added user to group required: true @@ -12047,7 +16129,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: added user to group required: true @@ -12093,7 +16175,7 @@ paths: type: array items: type: object - properties: &ref_110 + properties: &ref_170 name: type: string owners: @@ -12111,7 +16193,7 @@ paths: edited_at: type: string format: date-time - required: &ref_111 + required: &ref_171 - name - owners - extra_perms @@ -12193,7 +16275,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: update folder required: true @@ -12232,7 +16314,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 responses: '200': description: folder deleted @@ -12254,7 +16336,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 responses: '200': description: folder @@ -12262,8 +16344,30 @@ paths: application/json: schema: type: object - properties: *ref_110 - required: *ref_111 + properties: *ref_170 + required: *ref_171 + /w/{workspace}/folders/exists/{name}: + get: + summary: exists folder + operationId: existsFolder + tags: + - folder + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: name + in: path + required: true + schema: *ref_163 + responses: + '200': + description: folder exists + content: + application/json: + schema: + type: boolean /w/{workspace}/folders/getusage/{name}: get: summary: get folder usage @@ -12278,7 +16382,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 responses: '200': description: folder @@ -12320,7 +16424,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: owner user to folder required: true @@ -12354,7 +16458,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: added owner to folder required: true @@ -12408,7 +16512,7 @@ paths: type: array items: type: object - properties: &ref_183 + properties: &ref_278 worker: type: string worker_instance: @@ -12450,7 +16554,7 @@ paths: type: number wm_memory_usage: type: number - required: &ref_184 + required: &ref_279 - worker - worker_instance - ping_at @@ -12558,13 +16662,39 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 responses: '200': description: a config content: application/json: - schema: {} + schema: + type: object + nullable: true + properties: &ref_201 + alerts: + type: array + items: + type: object + properties: &ref_199 + name: + type: string + tags_to_monitor: + type: array + items: + type: string + jobs_num_threshold: + type: integer + alert_cooldown_seconds: + type: integer + alert_time_threshold_seconds: + type: integer + required: &ref_200 + - name + - tags_to_monitor + - jobs_num_threshold + - alert_cooldown_seconds + - alert_time_threshold_seconds /configs/update/{name}: post: summary: Update config @@ -12575,7 +16705,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 requestBody: description: worker group required: true @@ -12598,7 +16728,7 @@ paths: - name: name in: path required: true - schema: *ref_103 + schema: *ref_163 responses: '200': description: Delete config @@ -12621,12 +16751,12 @@ paths: type: array items: type: object - properties: &ref_225 + properties: &ref_320 name: type: string config: type: object - required: &ref_226 + required: &ref_321 - name /configs/list_autoscaling_events/{worker_group}: get: @@ -12649,7 +16779,7 @@ paths: type: array items: type: object - properties: &ref_229 + properties: &ref_324 id: type: integer format: int64 @@ -12664,6 +16794,54 @@ paths: applied_at: type: string format: date-time + /configs/list_available_python_versions: + get: + summary: Get currently available python versions provided by UV. + operationId: listAvailablePythonVersions + tags: + - config + responses: + '200': + description: List of python versions + content: + application/json: + schema: + type: array + items: + type: string + /agent_workers/create_agent_token: + post: + summary: create agent token + operationId: createAgentToken + tags: + - agent_workers + requestBody: + description: agent token + required: true + content: + application/json: + schema: + type: object + properties: + worker_group: + type: string + tags: + type: array + items: + type: string + exp: + type: integer + required: + - worker_group + - tags + - exp + responses: + '200': + description: agent token created + content: + application/json: + schema: + type: string /w/{workspace}/acls/get/{kind}/{path}: get: summary: get granular acls @@ -12678,7 +16856,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 - name: kind in: path required: true @@ -12696,6 +16874,12 @@ paths: - raw_app - http_trigger - websocket_trigger + - kafka_trigger + - nats_trigger + - postgres_trigger + - mqtt_trigger + - gcp_trigger + - sqs_trigger responses: '200': description: acls @@ -12719,7 +16903,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 - name: kind in: path required: true @@ -12737,6 +16921,12 @@ paths: - raw_app - http_trigger - websocket_trigger + - kafka_trigger + - nats_trigger + - postgres_trigger + - mqtt_trigger + - gcp_trigger + - sqs_trigger requestBody: description: acl to add required: true @@ -12772,7 +16962,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 - name: kind in: path required: true @@ -12790,6 +16980,12 @@ paths: - raw_app - http_trigger - websocket_trigger + - kafka_trigger + - nats_trigger + - postgres_trigger + - mqtt_trigger + - gcp_trigger + - sqs_trigger requestBody: description: acl to add required: true @@ -12809,10 +17005,10 @@ paths: text/plain: schema: type: string - /w/{workspace}/capture_u/{path}: + /w/{workspace}/capture/set_config: post: - summary: update flow preview capture - operationId: updateCapture + summary: set capture config + operationId: setCaptureConfig tags: - capture parameters: @@ -12820,17 +17016,48 @@ paths: in: path required: true schema: *ref_0 - - name: path - in: path - required: true - schema: *ref_23 + requestBody: + description: capture config + required: true + content: + application/json: + schema: + type: object + properties: + trigger_kind: + type: string + enum: &ref_172 + - webhook + - http + - websocket + - kafka + - email + - nats + - postgres + - sqs + - mqtt + - gcp + path: + type: string + is_flow: + type: boolean + trigger_config: + type: object + required: + - trigger_kind + - path + - is_flow responses: - '204': - description: flow preview captured - /w/{workspace}/capture/{path}: - put: - summary: create flow preview capture - operationId: createCapture + '200': + description: capture config set + content: + application/json: + schema: + type: object + /w/{workspace}/capture/ping_config/{trigger_kind}/{runnable_kind}/{path}: + post: + summary: ping capture config + operationId: pingCaptureConfig tags: - capture parameters: @@ -12838,15 +17065,160 @@ paths: in: path required: true schema: *ref_0 + - name: trigger_kind + in: path + required: true + schema: + type: string + enum: *ref_172 + - name: runnable_kind + in: path + required: true + schema: *ref_73 - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: - '201': - description: flow preview capture created + '200': + description: capture config pinged + /w/{workspace}/capture/get_configs/{runnable_kind}/{path}: get: - summary: get flow preview capture + summary: get capture configs for a script or flow + operationId: getCaptureConfigs + tags: + - capture + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: runnable_kind + in: path + required: true + schema: *ref_73 + - name: path + in: path + required: true + schema: *ref_26 + responses: + '200': + description: capture configs for a script or flow + content: + application/json: + schema: + type: array + items: + type: object + properties: &ref_325 + trigger_config: {} + trigger_kind: + type: string + enum: *ref_172 + error: + type: string + last_server_ping: + type: string + format: date-time + required: &ref_326 + - trigger_kind + /w/{workspace}/capture/list/{runnable_kind}/{path}: + get: + summary: list captures for a script or flow + operationId: listCaptures + tags: + - capture + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: runnable_kind + in: path + required: true + schema: *ref_73 + - name: path + in: path + required: true + schema: *ref_26 + - name: trigger_kind + in: query + schema: + type: string + enum: *ref_172 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + responses: + '200': + description: list of captures for a script or flow + content: + application/json: + schema: + type: array + items: + type: object + properties: &ref_173 + trigger_kind: + type: string + enum: *ref_172 + main_args: {} + preprocessor_args: {} + id: + type: integer + created_at: + type: string + format: date-time + required: &ref_174 + - trigger_kind + - main_args + - preprocessor_args + - id + - created_at + /w/{workspace}/capture/move/{runnable_kind}/{path}: + post: + summary: move captures and configs for a script or flow + operationId: moveCapturesAndConfigs + tags: + - capture + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: runnable_kind + in: path + required: true + schema: *ref_73 + - name: path + in: path + required: true + schema: *ref_26 + requestBody: + description: move captures and configs to a new path + required: true + content: + application/json: + schema: + type: object + properties: + new_path: + type: string + responses: + '200': + description: captures and configs moved + content: + text/plain: + schema: + type: string + /w/{workspace}/capture/{id}: + get: + summary: get a capture operationId: getCapture tags: - capture @@ -12855,18 +17227,38 @@ paths: in: path required: true schema: *ref_0 - - name: path + - name: id in: path required: true - schema: *ref_23 + schema: + type: integer responses: '200': - description: captured flow preview + description: capture content: application/json: - schema: {} - '404': - description: capture does not exist for this flow + schema: + type: object + properties: *ref_173 + required: *ref_174 + delete: + summary: delete a capture + operationId: deleteCapture + tags: + - capture + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: id + in: path + required: true + schema: + type: integer + responses: + '200': + description: capture deleted /w/{workspace}/favorites/star: post: summary: star item @@ -12938,13 +17330,13 @@ paths: schema: *ref_0 - name: runnable_id in: query - schema: &ref_112 + schema: &ref_175 type: string - name: runnable_type in: query - schema: &ref_113 + schema: &ref_176 type: string - enum: &ref_142 + enum: &ref_207 - ScriptHash - ScriptPath - FlowPath @@ -12956,6 +17348,16 @@ paths: description: number of items to return for a given page (default 30, max 100) in: query schema: *ref_6 + - name: args + description: >- + filter on jobs containing those args as a json subset (@> in + postgres) + in: query + schema: *ref_93 + - name: include_preview + in: query + schema: + type: boolean responses: '200': description: Input history for completed jobs @@ -12965,7 +17367,7 @@ paths: type: array items: type: object - properties: &ref_114 + properties: &ref_177 id: type: string name: @@ -12979,7 +17381,7 @@ paths: type: boolean success: type: boolean - required: &ref_115 + required: &ref_178 - id - name - args @@ -13029,10 +17431,10 @@ paths: schema: *ref_0 - name: runnable_id in: query - schema: *ref_112 + schema: *ref_175 - name: runnable_type in: query - schema: *ref_113 + schema: *ref_176 - name: page description: which page to return (start at 1, default 1) in: query @@ -13050,8 +17452,8 @@ paths: type: array items: type: object - properties: *ref_114 - required: *ref_115 + properties: *ref_177 + required: *ref_178 /w/{workspace}/inputs/create: post: summary: Create an Input for future use in a script or flow @@ -13065,10 +17467,10 @@ paths: schema: *ref_0 - name: runnable_id in: query - schema: *ref_112 + schema: *ref_175 - name: runnable_type in: query - schema: *ref_113 + schema: *ref_176 requestBody: description: Input required: true @@ -13076,12 +17478,12 @@ paths: application/json: schema: type: object - properties: &ref_138 + properties: &ref_203 name: type: string args: type: object - required: &ref_139 + required: &ref_204 - name - args - created_by @@ -13111,14 +17513,14 @@ paths: application/json: schema: type: object - properties: &ref_140 + properties: &ref_205 id: type: string name: type: string is_public: type: boolean - required: &ref_141 + required: &ref_206 - id - name - is_public @@ -13144,7 +17546,7 @@ paths: - name: input in: path required: true - schema: &ref_134 + schema: &ref_193 type: string responses: '200': @@ -13177,7 +17579,7 @@ paths: properties: s3_resource: type: object - properties: &ref_116 + properties: &ref_179 bucket: type: string region: @@ -13192,7 +17594,7 @@ paths: type: string pathStyle: type: boolean - required: &ref_117 + required: &ref_180 - bucket - region - endPoint @@ -13243,6 +17645,8 @@ paths: properties: connection_settings_str: type: string + azure_container_path: + type: string required: - connection_settings_str /w/{workspace}/job_helpers/polars_connection_settings: @@ -13268,8 +17672,8 @@ paths: properties: s3_resource: type: object - properties: *ref_116 - required: *ref_117 + properties: *ref_179 + required: *ref_180 responses: '200': description: Connection settings @@ -13290,10 +17694,10 @@ paths: type: boolean client_kwargs: type: object - properties: &ref_118 + properties: &ref_181 region_name: type: string - required: &ref_119 + required: &ref_182 - region_name required: - endpoint_url @@ -13348,8 +17752,8 @@ paths: type: boolean client_kwargs: type: object - properties: *ref_118 - required: *ref_119 + properties: *ref_181 + required: *ref_182 required: - endpoint_url - use_ssl @@ -13407,8 +17811,8 @@ paths: application/json: schema: type: object - properties: *ref_116 - required: *ref_117 + properties: *ref_179 + required: *ref_180 /w/{workspace}/job_helpers/test_connection: get: summary: Test connection to the workspace object storage @@ -13472,10 +17876,10 @@ paths: type: array items: type: object - properties: &ref_202 + properties: &ref_297 s3: type: string - required: &ref_203 + required: &ref_298 - s3 restricted_access: type: boolean @@ -13508,7 +17912,7 @@ paths: application/json: schema: type: object - properties: &ref_204 + properties: &ref_299 mime_type: type: string size_in_bytes: @@ -13572,7 +17976,7 @@ paths: application/json: schema: type: object - properties: &ref_205 + properties: &ref_300 msg: type: string content: @@ -13584,7 +17988,7 @@ paths: - Csv - Parquet - Unknown - required: &ref_206 + required: &ref_301 - content_type /w/{workspace}/job_helpers/load_parquet_preview/{path}: get: @@ -13600,7 +18004,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 - name: offset in: query schema: @@ -13649,7 +18053,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 - name: search_col in: query schema: @@ -13686,7 +18090,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 - name: offset in: query schema: @@ -13847,7 +18251,7 @@ paths: - file_key /w/{workspace}/job_helpers/download_s3_file: get: - summary: Download file to S3 bucket + summary: Download file from S3 bucket operationId: fileDownload tags: - helpers @@ -13930,7 +18334,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 requestBody: description: parameters for statistics retrieval required: true @@ -13959,46 +18363,46 @@ paths: type: array items: type: object - properties: &ref_209 + properties: &ref_304 id: type: string name: type: string - required: &ref_210 + required: &ref_305 - id scalar_metrics: type: array items: type: object - properties: &ref_211 + properties: &ref_306 metric_id: type: string value: type: number - required: &ref_212 + required: &ref_307 - id - value timeseries_metrics: type: array items: type: object - properties: &ref_213 + properties: &ref_308 metric_id: type: string values: type: array items: type: object - properties: &ref_215 + properties: &ref_310 timestamp: type: string format: date-time value: type: number - required: &ref_216 + required: &ref_311 - timestamp - value - required: &ref_214 + required: &ref_309 - id - values /w/{workspace}/job_metrics/set_progress/{id}: @@ -14015,7 +18419,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 requestBody: description: parameters for statistics retrieval required: true @@ -14049,7 +18453,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 responses: '200': description: job progress between 0 and 99 @@ -14067,11 +18471,11 @@ paths: - name: before description: filter on started before (inclusive) timestamp in: query - schema: *ref_120 + schema: *ref_183 - name: after description: filter on created after (exclusive) timestamp in: query - schema: *ref_121 + schema: *ref_184 - name: with_error in: query required: false @@ -14120,7 +18524,7 @@ paths: - name: path in: path required: true - schema: *ref_23 + schema: *ref_26 responses: '200': description: log stream @@ -14143,12 +18547,12 @@ paths: type: array items: type: object - properties: &ref_219 + properties: &ref_314 concurrency_key: type: string total_running: type: number - required: &ref_220 + required: &ref_315 - concurrency_key - total_running /concurrency_groups/prune/{concurrency_id}: @@ -14161,7 +18565,7 @@ paths: - name: concurrency_id in: path required: true - schema: &ref_136 + schema: &ref_195 type: string responses: '200': @@ -14181,7 +18585,7 @@ paths: - name: id in: path required: true - schema: *ref_91 + schema: *ref_110 responses: '200': description: concurrency key for given job @@ -14214,93 +18618,97 @@ paths: - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_53 + schema: *ref_60 - 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_86 + schema: *ref_98 - 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_46 + schema: *ref_53 - name: script_path_exact description: mask to filter exact matching path in: query - schema: *ref_70 + schema: *ref_83 - name: script_path_start description: mask to filter matching starting path in: query - schema: *ref_71 + schema: *ref_84 - name: schedule_path description: mask to filter by schedule path in: query - schema: *ref_72 + schema: *ref_85 - name: script_hash description: mask to filter exact matching path in: query - schema: *ref_73 + schema: *ref_86 - name: started_before description: filter on started before (inclusive) timestamp in: query - schema: *ref_74 + schema: *ref_87 - name: started_after description: filter on started after (exclusive) timestamp in: query - schema: *ref_75 + schema: *ref_88 - 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_122 + schema: *ref_103 - name: running description: filter on running jobs in: query - schema: *ref_80 + schema: *ref_89 - name: scheduled_for_before_now description: filter on jobs scheduled_for before now (hence waitinf for a worker) in: query - schema: *ref_77 + schema: *ref_90 - 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_123 + schema: *ref_104 - 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_124 + schema: *ref_105 - name: job_kinds description: >- filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: *ref_78 + schema: *ref_91 - name: args description: >- filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: *ref_81 + schema: *ref_93 - name: tag description: filter on jobs with a given tag/worker group in: query - schema: *ref_83 + schema: *ref_94 - name: result description: >- filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: *ref_82 + schema: *ref_95 + - name: allow_wildcards + description: allow wildcards (*) in the filter of label, tag, worker + in: query + schema: *ref_97 - name: page description: which page to return (start at 1, default 1) in: query @@ -14348,17 +18756,17 @@ paths: application/json: schema: type: object - properties: &ref_221 + properties: &ref_316 jobs: type: array items: - oneOf: *ref_92 - discriminator: *ref_93 + oneOf: *ref_111 + discriminator: *ref_112 obscured_jobs: type: array items: type: object - properties: &ref_143 + properties: &ref_208 typ: type: string started_at: @@ -14371,7 +18779,7 @@ paths: Obscured jobs omitted for security because of too specific filtering type: boolean - required: &ref_222 + required: &ref_317 - jobs - obscured_jobs /srch/w/{workspace}/index/search/job: @@ -14390,6 +18798,11 @@ paths: required: true schema: type: string + - name: pagination_offset + in: query + required: false + schema: + type: integer responses: '200': description: search results @@ -14404,18 +18817,29 @@ paths: ignored) type: array items: - type: object - properties: - dancer: - type: string + type: string hits: description: the jobs that matched the query type: array items: type: object - properties: &ref_227 + properties: &ref_322 dancer: type: string + hit_count: + description: how many jobs matched in total + type: number + index_metadata: + description: Metadata about the index current state + type: object + properties: + indexed_until: + description: Datetime of the most recently indexed job + type: string + format: date-time + lost_lock_ownership: + description: Is the current indexer service being replaced + type: boolean /srch/index/search/service_logs: get: summary: Search through service logs with a string query @@ -14475,7 +18899,7 @@ paths: type: array items: type: object - properties: &ref_228 + properties: &ref_323 dancer: type: string /srch/index/search/count_service_logs: @@ -14490,11 +18914,6 @@ paths: required: true schema: type: string - - name: hosts - in: query - required: true - schema: - type: string - name: min_ts in: query required: false @@ -14525,6 +18944,28 @@ paths: count_per_host: description: count of log lines that matched the query per hostname type: object + /srch/index/delete/{idx_name}: + delete: + summary: Restart container and delete the index to recreate it. + operationId: clearIndex + tags: + - indexSearch + parameters: + - name: idx_name + in: path + required: true + schema: + type: string + enum: + - JobIndex + - ServiceLogIndex + responses: + '200': + description: idx to be deleted and container restarting + content: + text/plain: + schema: + type: string components: securitySchemes: bearerAuth: @@ -14535,6 +18976,11 @@ components: in: cookie name: token parameters: + Id: + name: id + in: path + required: true + schema: *ref_185 Key: name: key in: path @@ -14545,61 +18991,71 @@ components: in: path required: true schema: *ref_0 + PublicationName: + name: publication + in: path + required: true + schema: *ref_157 VersionId: name: version in: path required: true - schema: *ref_125 + schema: *ref_186 Token: name: token in: path required: true - schema: *ref_126 + schema: *ref_187 AccountId: name: id in: path required: true - schema: *ref_27 + schema: *ref_31 ClientName: name: client_name in: path required: true - schema: *ref_26 + schema: *ref_30 ScriptPath: name: path in: path required: true - schema: *ref_35 + schema: *ref_41 ScriptHash: name: hash in: path required: true - schema: *ref_39 + schema: *ref_46 JobId: name: id in: path required: true - schema: *ref_91 + schema: *ref_110 Path: name: path in: path required: true - schema: *ref_23 + schema: *ref_26 + CustomPath: + name: custom_path + in: path + required: true + schema: *ref_74 PathId: name: id in: path required: true - schema: *ref_30 + schema: *ref_34 PathVersion: name: version in: path required: true - schema: *ref_127 + schema: *ref_188 Name: name: name in: path required: true - schema: *ref_103 + schema: *ref_163 Page: name: page description: which page to return (start at 1, default 1) @@ -14614,12 +19070,12 @@ components: name: order_desc description: order by desc order (default true) in: query - schema: *ref_52 + schema: *ref_59 CreatedBy: name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_53 + schema: *ref_60 Label: name: label description: >- @@ -14627,26 +19083,31 @@ components: with as a result an object containing a string in the array at key 'wm_labels') in: query - schema: *ref_86 + schema: *ref_98 + Worker: + name: worker + description: worker this job was ran on + in: query + schema: *ref_82 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_46 + schema: *ref_53 WorkerTag: name: tag description: Override the tag to use in: query - schema: *ref_48 + schema: *ref_55 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_49 + schema: *ref_56 NewJobId: name: job_id description: >- @@ -14654,7 +19115,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_47 + schema: *ref_54 IncludeHeader: name: include_header description: > @@ -14664,14 +19125,14 @@ components: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_50 + schema: *ref_57 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_51 + schema: *ref_58 Payload: name: payload description: > @@ -14680,253 +19141,283 @@ components: `encodeURIComponent(btoa(JSON.stringify({a: 2})))` in: query - schema: *ref_94 + schema: *ref_113 ScriptStartPath: name: script_path_start description: mask to filter matching starting path in: query - schema: *ref_71 + schema: *ref_84 SchedulePath: name: schedule_path description: mask to filter by schedule path in: query - schema: *ref_72 + schema: *ref_85 ScriptExactPath: name: script_path_exact description: mask to filter exact matching path in: query - schema: *ref_70 + schema: *ref_83 ScriptExactHash: name: script_hash description: mask to filter exact matching path in: query - schema: *ref_73 + schema: *ref_86 CreatedBefore: name: created_before description: filter on created before (inclusive) timestamp in: query - schema: *ref_128 + schema: *ref_101 CreatedAfter: name: created_after description: filter on created after (exclusive) timestamp in: query - schema: *ref_129 + schema: *ref_102 StartedBefore: name: started_before description: filter on started before (inclusive) timestamp in: query - schema: *ref_74 + schema: *ref_87 StartedAfter: name: started_after description: filter on started after (exclusive) timestamp in: query - schema: *ref_75 + schema: *ref_88 Before: name: before description: filter on started before (inclusive) timestamp in: query - schema: *ref_120 + schema: *ref_183 CreatedOrStartedAfter: 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_123 + schema: *ref_104 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 in: query - schema: *ref_124 + schema: *ref_105 CreatedOrStartedBefore: 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_122 + schema: *ref_103 Success: name: success description: filter on successful jobs in: query - schema: *ref_76 + schema: *ref_96 ScheduledForBeforeNow: name: scheduled_for_before_now description: filter on jobs scheduled_for before now (hence waitinf for a worker) in: query - schema: *ref_77 + schema: *ref_90 Suspended: name: suspended description: filter on suspended jobs in: query - schema: *ref_79 + schema: *ref_92 Running: name: running description: filter on running jobs in: query - schema: *ref_80 + schema: *ref_89 + AllowWildcards: + name: allow_wildcards + description: allow wildcards (*) in the filter of label, tag, worker + in: query + schema: *ref_97 ArgsFilter: name: args description: filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: *ref_81 + schema: *ref_93 Tag: name: tag description: filter on jobs with a given tag/worker group in: query - schema: *ref_83 + schema: *ref_94 ResultFilter: name: result description: filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: *ref_82 + schema: *ref_95 After: name: after description: filter on created after (exclusive) timestamp in: query - schema: *ref_121 + schema: *ref_184 Username: name: username description: filter on exact username of user in: query - schema: *ref_130 + schema: *ref_189 Operation: name: operation description: filter on exact or prefix name of operation in: query - schema: *ref_131 + schema: *ref_190 ResourceName: name: resource description: filter on exact or prefix name of resource in: query - schema: *ref_132 + schema: *ref_191 ActionKind: name: action_kind description: filter on type of operation in: query - schema: *ref_133 + schema: *ref_192 JobKinds: name: job_kinds description: >- filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: *ref_78 + schema: *ref_91 RunnableId: name: runnable_id in: query - schema: *ref_112 + schema: *ref_175 RunnableTypeQuery: name: runnable_type in: query - schema: *ref_113 + schema: *ref_176 InputId: name: input in: path required: true - schema: *ref_134 + schema: *ref_193 GetStarted: name: get_started in: query - schema: *ref_135 + schema: *ref_194 ConcurrencyId: name: concurrency_id in: path required: true - schema: *ref_136 + schema: *ref_195 + RunnableKind: + name: runnable_kind + in: path + required: true + schema: *ref_73 schemas: - AiResource: + InputTransform: + allOf: *ref_77 + AIProvider: + type: string + enum: *ref_196 + AIProviderModel: type: object - properties: *ref_16 - required: *ref_17 + properties: *ref_18 + required: *ref_19 + AIProviderConfig: + type: object + properties: *ref_197 + required: *ref_198 + AIConfig: + type: object + properties: *ref_20 + Alert: + type: object + properties: *ref_199 + required: *ref_200 + Configs: + type: object + nullable: true + properties: *ref_201 Script: - type: object - properties: *ref_37 - required: *ref_38 - NewScript: - type: object - properties: *ref_42 - required: *ref_43 - NewScriptWithDraft: - allOf: *ref_137 - ScriptHistory: type: object properties: *ref_44 required: *ref_45 + NewScript: + type: object + properties: *ref_49 + required: *ref_50 + NewScriptWithDraft: + allOf: *ref_202 + ScriptHistory: + type: object + properties: *ref_51 + required: *ref_52 ScriptArgs: type: object - additionalProperties: *ref_18 + additionalProperties: *ref_21 Input: type: object - properties: *ref_114 - required: *ref_115 + properties: *ref_177 + required: *ref_178 CreateInput: type: object - properties: *ref_138 - required: *ref_139 + properties: *ref_203 + required: *ref_204 UpdateInput: type: object - properties: *ref_140 - required: *ref_141 + properties: *ref_205 + required: *ref_206 RunnableType: type: string - enum: *ref_142 + enum: *ref_207 QueuedJob: type: object - properties: *ref_89 - required: *ref_90 + properties: *ref_108 + required: *ref_109 CompletedJob: type: object - properties: *ref_87 - required: *ref_88 + properties: *ref_106 + required: *ref_107 ObscuredJob: type: object - properties: *ref_143 + properties: *ref_208 Job: - oneOf: *ref_92 - discriminator: *ref_93 + oneOf: *ref_111 + discriminator: *ref_112 User: type: object properties: *ref_10 required: *ref_11 UserUsage: type: object - properties: *ref_144 + properties: *ref_209 Login: type: object - properties: *ref_145 - required: *ref_146 + properties: *ref_210 + required: *ref_211 EditWorkspaceUser: type: object - properties: *ref_147 + properties: *ref_212 TruncatedToken: type: object - properties: *ref_40 - required: *ref_41 + properties: *ref_47 + required: *ref_48 NewToken: type: object - properties: *ref_148 + properties: *ref_213 NewTokenImpersonate: type: object - properties: *ref_149 - required: *ref_150 + properties: *ref_214 + required: *ref_215 ListableVariable: type: object - properties: *ref_24 - required: *ref_25 + properties: *ref_27 + required: *ref_28 ContextualVariable: type: object - properties: *ref_151 - required: *ref_152 + properties: *ref_216 + required: *ref_217 CreateVariable: type: object - properties: *ref_153 - required: *ref_154 + properties: *ref_218 + required: *ref_219 EditVariable: type: object - properties: *ref_155 + properties: *ref_220 AuditLog: type: object properties: *ref_1 @@ -15056,164 +19547,315 @@ components: - error - no_main_func - has_preprocessor + ScriptLang: + type: string + enum: *ref_43 Preview: type: object - properties: *ref_156 - required: *ref_157 + properties: *ref_221 + required: *ref_222 WorkflowTask: + type: object + properties: *ref_223 + required: *ref_224 + WorkflowStatusRecord: + type: object + additionalProperties: *ref_225 + WorkflowStatus: + type: object + properties: *ref_226 + CreateResource: + type: object + properties: *ref_227 + required: *ref_228 + EditResource: + type: object + properties: *ref_229 + Resource: + type: object + properties: *ref_230 + required: *ref_231 + ListableResource: + type: object + properties: *ref_232 + required: *ref_233 + ResourceType: + type: object + properties: *ref_32 + required: *ref_33 + EditResourceType: + type: object + properties: *ref_234 + Schedule: + type: object + properties: *ref_115 + required: *ref_116 + ScheduleWJobs: + allOf: *ref_235 + NewSchedule: + type: object + properties: *ref_236 + required: *ref_237 + EditSchedule: + type: object + properties: *ref_238 + required: *ref_239 + TriggerExtraProperty: + type: object + properties: *ref_122 + required: *ref_123 + AuthenticationMethod: + type: string + enum: *ref_117 + HttpTrigger: + allOf: *ref_118 + type: object + properties: *ref_119 + required: *ref_120 + NewHttpTrigger: + type: object + properties: *ref_240 + required: *ref_241 + EditHttpTrigger: + type: object + properties: *ref_242 + required: *ref_243 + TriggersCount: + type: object + properties: *ref_66 + WebsocketTrigger: + allOf: *ref_124 + type: object + properties: *ref_125 + required: *ref_126 + NewWebsocketTrigger: + type: object + properties: *ref_244 + required: *ref_245 + EditWebsocketTrigger: + type: object + properties: *ref_246 + required: *ref_247 + WebsocketTriggerInitialMessage: + anyOf: *ref_121 + MqttQoS: + type: string + enum: *ref_248 + MqttV3Config: + type: object + properties: *ref_139 + MqttV5Config: + type: object + properties: *ref_140 + MqttSubscribeTopic: + type: object + properties: *ref_137 + required: *ref_138 + MqttClientVersion: + type: string + enum: *ref_141 + MqttTrigger: + allOf: *ref_142 + type: object + properties: *ref_143 + required: *ref_144 + NewMqttTrigger: + type: object + properties: *ref_249 + required: *ref_250 + EditMqttTrigger: + type: object + properties: *ref_251 + required: *ref_252 + DeliveryType: + type: string + enum: *ref_147 + PushConfig: + type: object + properties: *ref_148 + required: *ref_149 + GcpTrigger: + allOf: *ref_151 + type: object + properties: *ref_152 + required: *ref_153 + SubscriptionMode: + type: string + enum: *ref_150 + 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_145 + required: *ref_146 + GetAllTopicSubscription: + type: object + properties: *ref_253 + required: *ref_254 + DeleteGcpSubscription: + type: object + properties: *ref_255 + required: *ref_256 + AwsAuthResourceType: + type: string + enum: *ref_133 + SqsTrigger: + allOf: *ref_134 + type: object + properties: *ref_135 + required: *ref_136 + NewSqsTrigger: + type: object + properties: *ref_257 + required: *ref_258 + EditSqsTrigger: + type: object + properties: *ref_259 + required: *ref_260 + Slot: + type: object + properties: *ref_154 + SlotList: + type: object + properties: *ref_261 + PublicationData: type: object properties: *ref_158 required: *ref_159 - WorkflowStatusRecord: + TableToTrack: + type: array + items: *ref_262 + Relations: type: object - additionalProperties: *ref_160 - WorkflowStatus: + properties: *ref_155 + required: *ref_156 + Language: + type: string + enum: *ref_263 + TemplateScript: + type: object + properties: *ref_264 + required: *ref_265 + PostgresTrigger: + allOf: *ref_160 type: object properties: *ref_161 - CreateResource: + required: *ref_162 + NewPostgresTrigger: type: object - properties: *ref_162 - required: *ref_163 - EditResource: + properties: *ref_266 + required: *ref_267 + EditPostgresTrigger: type: object - properties: *ref_164 - Resource: + properties: *ref_268 + required: *ref_269 + KafkaTrigger: + allOf: *ref_127 type: object - properties: *ref_165 - required: *ref_166 - ListableResource: + properties: *ref_128 + required: *ref_129 + NewKafkaTrigger: type: object - properties: *ref_167 - required: *ref_168 - ResourceType: + properties: *ref_270 + required: *ref_271 + EditKafkaTrigger: type: object - properties: *ref_28 - required: *ref_29 - EditResourceType: + properties: *ref_272 + required: *ref_273 + NatsTrigger: + allOf: *ref_130 type: object - properties: *ref_169 - Schedule: + properties: *ref_131 + required: *ref_132 + NewNatsTrigger: type: object - properties: *ref_96 - required: *ref_97 - ScheduleWJobs: - allOf: *ref_170 - NewSchedule: + properties: *ref_274 + required: *ref_275 + EditNatsTrigger: type: object - properties: *ref_171 - required: *ref_172 - EditSchedule: - type: object - properties: *ref_173 - required: *ref_174 - HttpTrigger: - type: object - properties: *ref_98 - required: *ref_99 - NewHttpTrigger: - type: object - properties: *ref_175 - required: *ref_176 - EditHttpTrigger: - type: object - properties: *ref_177 - required: *ref_178 - TriggersCount: - type: object - properties: *ref_59 - WebsocketTrigger: - type: object - properties: *ref_101 - required: *ref_102 - NewWebsocketTrigger: - type: object - properties: *ref_179 - required: *ref_180 - EditWebsocketTrigger: - type: object - properties: *ref_181 - required: *ref_182 - WebsocketTriggerInitialMessage: - anyOf: *ref_100 + properties: *ref_276 + required: *ref_277 Group: type: object - properties: *ref_108 - required: *ref_109 + properties: *ref_168 + required: *ref_169 InstanceGroup: type: object - properties: *ref_104 - required: *ref_105 + properties: *ref_164 + required: *ref_165 Folder: type: object - properties: *ref_110 - required: *ref_111 + properties: *ref_170 + required: *ref_171 WorkerPing: type: object - properties: *ref_183 - required: *ref_184 + properties: *ref_278 + required: *ref_279 UserWorkspaceList: type: object - properties: *ref_185 - required: *ref_186 + properties: *ref_280 + required: *ref_281 CreateWorkspace: type: object - properties: *ref_187 - required: *ref_188 + properties: *ref_282 + required: *ref_283 Workspace: type: object properties: *ref_7 required: *ref_8 WorkspaceInvite: type: object - properties: *ref_14 - required: *ref_15 + properties: *ref_16 + required: *ref_17 GlobalUserInfo: type: object - properties: *ref_12 - required: *ref_13 + properties: *ref_14 + required: *ref_15 Flow: - allOf: *ref_58 + allOf: *ref_65 ExtraPerms: type: object - additionalProperties: *ref_189 + additionalProperties: *ref_284 FlowMetadata: type: object - properties: *ref_190 - required: *ref_191 + properties: *ref_285 + required: *ref_286 OpenFlowWPath: - allOf: *ref_60 + allOf: *ref_67 FlowPreview: type: object - properties: *ref_192 - required: *ref_193 + properties: *ref_287 + required: *ref_288 RestartedFrom: type: object - properties: *ref_194 + properties: *ref_289 Policy: type: object - properties: *ref_61 + properties: *ref_68 ListableApp: type: object - properties: *ref_195 - required: *ref_196 + properties: *ref_290 + required: *ref_291 ListableRawApp: type: object - properties: *ref_197 - required: *ref_198 + properties: *ref_292 + required: *ref_293 AppWithLastVersion: type: object - properties: *ref_62 - required: *ref_63 + properties: *ref_69 + required: *ref_70 AppWithLastVersionWDraft: - allOf: *ref_199 + allOf: *ref_294 AppHistory: type: object - properties: *ref_64 - required: *ref_65 + properties: *ref_71 + required: *ref_72 FlowVersion: type: object - properties: *ref_56 - required: *ref_57 + properties: *ref_63 + required: *ref_64 SlackToken: type: object properties: @@ -15235,46 +19877,46 @@ components: - bot TokenResponse: type: object - properties: *ref_200 - required: *ref_201 + properties: *ref_295 + required: *ref_296 HubScriptKind: - name: kind - schema: *ref_36 + type: string + enum: *ref_42 PolarsClientKwargs: type: object - properties: *ref_118 - required: *ref_119 + properties: *ref_181 + required: *ref_182 LargeFileStorage: type: object - properties: *ref_19 + properties: *ref_22 WindmillLargeFile: type: object - properties: *ref_202 - required: *ref_203 + properties: *ref_297 + required: *ref_298 WindmillFileMetadata: type: object - properties: *ref_204 + properties: *ref_299 WindmillFilePreview: type: object - properties: *ref_205 - required: *ref_206 + properties: *ref_300 + required: *ref_301 S3Resource: type: object - properties: *ref_116 - required: *ref_117 + properties: *ref_179 + required: *ref_180 WorkspaceGitSyncSettings: type: object - properties: *ref_20 + properties: *ref_23 WorkspaceDeployUISettings: type: object - properties: *ref_21 + properties: *ref_24 WorkspaceDefaultScripts: type: object - properties: *ref_22 + properties: *ref_25 GitRepositorySettings: type: object - properties: *ref_207 - required: *ref_208 + properties: *ref_302 + required: *ref_303 UploadFilePart: type: object properties: @@ -15287,126 +19929,195 @@ components: - tag MetricMetadata: type: object - properties: *ref_209 - required: *ref_210 + properties: *ref_304 + required: *ref_305 ScalarMetric: type: object - properties: *ref_211 - required: *ref_212 + properties: *ref_306 + required: *ref_307 TimeseriesMetric: type: object - properties: *ref_213 - required: *ref_214 + properties: *ref_308 + required: *ref_309 MetricDataPoint: type: object - properties: *ref_215 - required: *ref_216 + properties: *ref_310 + required: *ref_311 RawScriptForDependencies: type: object - properties: *ref_217 - required: *ref_218 + properties: *ref_312 + required: *ref_313 ConcurrencyGroup: type: object - properties: *ref_219 - required: *ref_220 + properties: *ref_314 + required: *ref_315 ExtendedJobs: type: object - properties: *ref_221 - required: *ref_222 + properties: *ref_316 + required: *ref_317 ExportedUser: type: object properties: *ref_3 required: *ref_4 GlobalSetting: type: object - properties: *ref_223 - required: *ref_224 + properties: *ref_318 + required: *ref_319 Config: type: object - properties: *ref_225 - required: *ref_226 + properties: *ref_320 + required: *ref_321 ExportedInstanceGroup: type: object - properties: *ref_106 - required: *ref_107 + properties: *ref_166 + required: *ref_167 JobSearchHit: type: object - properties: *ref_227 + properties: *ref_322 LogSearchHit: type: object - properties: *ref_228 + properties: *ref_323 AutoscalingEvent: type: object - properties: *ref_229 + properties: *ref_324 CriticalAlert: type: object - properties: *ref_230 + properties: *ref_29 + CaptureTriggerKind: + type: string + enum: *ref_172 + Capture: + type: object + properties: *ref_173 + required: *ref_174 + CaptureConfig: + type: object + properties: *ref_325 + required: *ref_326 + OperatorSettings: + nullable: true + type: object + required: *ref_12 + properties: *ref_13 + TeamInfo: + type: object + required: *ref_327 + properties: *ref_328 + ChannelInfo: + type: object + required: *ref_329 + properties: *ref_330 + GithubInstallations: + type: array + items: *ref_331 + WorkspaceGithubInstallation: + type: object + properties: + account_id: + type: string + installation_id: + type: number + required: + - account_id + - installation_id + S3Object: + type: object + properties: *ref_75 + required: *ref_76 + TeamsChannel: + type: object + required: + - team_id + - team_name + - channel_id + - channel_name + properties: + team_id: + type: string + description: Microsoft Teams team ID + minLength: 1 + team_name: + type: string + description: Microsoft Teams team name + minLength: 1 + channel_id: + type: string + description: Microsoft Teams channel ID + minLength: 1 + channel_name: + type: string + description: Microsoft Teams channel name + minLength: 1 StaticTransform: type: object - properties: *ref_231 - required: *ref_232 + properties: *ref_332 + required: *ref_333 JavascriptTransform: type: object - properties: *ref_233 - required: *ref_234 - InputTransform: - oneOf: *ref_31 - discriminator: *ref_32 + properties: *ref_334 + required: *ref_335 + schemas-InputTransform: + oneOf: *ref_35 + discriminator: *ref_36 RawScript: type: object - properties: *ref_235 - required: *ref_236 + properties: *ref_336 + required: *ref_337 PathScript: type: object - properties: *ref_237 - required: *ref_238 + properties: *ref_338 + required: *ref_339 PathFlow: type: object - properties: *ref_239 - required: *ref_240 + properties: *ref_340 + required: *ref_341 FlowModule: type: object - properties: *ref_33 - required: *ref_34 + properties: *ref_37 + required: *ref_38 ForloopFlow: type: object - properties: *ref_241 - required: *ref_242 + properties: *ref_342 + required: *ref_343 WhileloopFlow: type: object - properties: *ref_243 - required: *ref_244 + properties: *ref_344 + required: *ref_345 BranchOne: type: object - properties: *ref_245 - required: *ref_246 + properties: *ref_346 + required: *ref_347 BranchAll: type: object - properties: *ref_247 - required: *ref_248 + properties: *ref_348 + required: *ref_349 Identity: type: object - properties: *ref_249 - required: *ref_250 + properties: *ref_350 + required: *ref_351 FlowModuleValue: - oneOf: *ref_251 - discriminator: *ref_252 + oneOf: *ref_352 + discriminator: *ref_353 + StopAfterIf: + type: object + properties: *ref_39 + required: *ref_40 Retry: type: object - properties: *ref_95 + properties: *ref_114 FlowValue: type: object - properties: *ref_66 - required: *ref_67 + properties: *ref_78 + required: *ref_79 OpenFlow: type: object - properties: *ref_54 - required: *ref_55 + properties: *ref_61 + required: *ref_62 FlowStatusModule: type: object - properties: *ref_68 - required: *ref_69 + properties: *ref_80 + required: *ref_81 FlowStatus: type: object - properties: *ref_84 - required: *ref_85 + properties: *ref_99 + required: *ref_100 diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index fd3e81f209..e757d24432 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.492.1 + version: 1.494.0 title: Windmill API contact: @@ -377,6 +377,9 @@ paths: type: string company: type: string + skip_email: + type: boolean + description: Skip sending email notifications to the user required: - email - password @@ -4893,8 +4896,6 @@ paths: description: Script version/hash content: application/json: - required: false - schema: $ref: "#/components/schemas/ScriptHistory" @@ -5456,8 +5457,6 @@ paths: description: Flow version content: application/json: - required: false - schema: $ref: "#/components/schemas/FlowVersion" @@ -5487,8 +5486,7 @@ paths: operationId: getFlowVersion parameters: - $ref: "#/components/parameters/WorkspaceId" - - type: string - name: version + - name: version in: path required: true schema: @@ -5510,8 +5508,7 @@ paths: operationId: updateFlowHistory parameters: - $ref: "#/components/parameters/WorkspaceId" - - type: string - name: version + - name: version in: path required: true schema: @@ -6139,10 +6136,8 @@ paths: description: App version content: application/json: - required: false schema: $ref: "#/components/schemas/AppHistory" - /w/{workspace}/apps/list_paths_from_workspace_runnable/{runnable_kind}/{path}: get: summary: list app paths from workspace runnable @@ -6731,11 +6726,6 @@ paths: responses: "201": description: stream of created job uuids separated by \n. Lines may start with 'Error:' - example: | - a1a74c0d-708e-4539-9768-e8b3d37996bd - f0949132-5b30-48fe-bac8-873f047df810 - Error: Could not re-run 0b885808-ae89-4458-af95-c1ca3a13b0a5 - 52b9c01d-1125-4bbb-8bee-d41f26b70066 content: text/event-stream: schema: @@ -7592,7 +7582,8 @@ paths: description: job log content: text/plain: - type: string + schema: + type: string /w/{workspace}/jobs_u/get_flow_debug_info/{id}: get: @@ -9830,6 +9821,23 @@ paths: items: type: string + /w/{workspace}/postgres_triggers/postgres/version/{path}: + get: + summary: get postgres version + operationId: getPostgresVersion + tags: + - postgres_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: postgres version + content: + application/json: + schema: + type: string + /w/{workspace}/postgres_triggers/is_valid_postgres_configuration/{path}: get: summary: check if postgres configuration is set to logical @@ -12469,7 +12477,6 @@ paths: text/plain: schema: type: string - /concurrency_groups/list: get: summary: List all concurrency groups @@ -13175,7 +13182,47 @@ components: enum: [script, flow] schemas: - $ref: "../../openflow.openapi.yaml#/components/schemas" + # NOTE: Not so many generators and validators support this format: + # $ref: "../../openflow.openapi.yaml#/components/schemas" + # This is why it is better to inline each of schemas for better compat + OpenFlow: + $ref: "../../openflow.openapi.yaml#/components/schemas/OpenFlow" + FlowValue: + $ref: "../../openflow.openapi.yaml#/components/schemas/FlowValue" + Retry: + $ref: "../../openflow.openapi.yaml#/components/schemas/Retry" + StopAfterIf: + $ref: "../../openflow.openapi.yaml#/components/schemas/StopAfterIf" + FlowModule: + $ref: "../../openflow.openapi.yaml#/components/schemas/FlowModule" + InputTransform: + $ref: "../../openflow.openapi.yaml#/components/schemas/InputTransform" + StaticTransform: + $ref: "../../openflow.openapi.yaml#/components/schemas/StaticTransform" + JavascriptTransform: + $ref: "../../openflow.openapi.yaml#/components/schemas/JavascriptTransform" + FlowModuleValue: + $ref: "../../openflow.openapi.yaml#/components/schemas/FlowModuleValue" + RawScript: + $ref: "../../openflow.openapi.yaml#/components/schemas/RawScript" + PathScript: + $ref: "../../openflow.openapi.yaml#/components/schemas/PathScript" + PathFlow: + $ref: "../../openflow.openapi.yaml#/components/schemas/PathFlow" + ForloopFlow: + $ref: "../../openflow.openapi.yaml#/components/schemas/ForloopFlow" + WhileloopFlow: + $ref: "../../openflow.openapi.yaml#/components/schemas/WhileloopFlow" + BranchOne: + $ref: "../../openflow.openapi.yaml#/components/schemas/BranchOne" + BranchAll: + $ref: "../../openflow.openapi.yaml#/components/schemas/BranchAll" + Identity: + $ref: "../../openflow.openapi.yaml#/components/schemas/Identity" + FlowStatus: + $ref: "../../openflow.openapi.yaml#/components/schemas/FlowStatus" + FlowStatusModule: + $ref: "../../openflow.openapi.yaml#/components/schemas/FlowStatusModule" AIProvider: type: string @@ -14242,7 +14289,8 @@ components: ansible, csharp, nu, - java + java, + duckdb # for related places search: ADD_NEW_LANG ] @@ -16224,10 +16272,8 @@ components: - access_token HubScriptKind: - name: kind - schema: - type: string - enum: [script, failure, trigger, approval] + type: string + enum: [script, failure, trigger, approval] PolarsClientKwargs: type: object diff --git a/backend/windmill-api/src/capture.rs b/backend/windmill-api/src/capture.rs index 07127e53a1..3164ebe43f 100644 --- a/backend/windmill-api/src/capture.rs +++ b/backend/windmill-api/src/capture.rs @@ -23,7 +23,10 @@ use { http::HeaderMap, }; -#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +#[cfg(any( + all(feature = "enterprise", feature = "gcp_trigger"), + feature = "postgres_trigger" +))] use windmill_common::utils::empty_as_none; #[cfg(all(feature = "enterprise", feature = "sqs_trigger"))] @@ -33,7 +36,14 @@ use windmill_common::auth::aws::AwsAuthResourceType; feature = "http_trigger", all(feature = "enterprise", feature = "gcp_trigger") ))] -use {serde::de::DeserializeOwned, windmill_common::error::Error}; +use serde::de::DeserializeOwned; + +#[cfg(any( + feature = "http_trigger", + feature = "postgres_trigger", + all(feature = "enterprise", feature = "gcp_trigger") +))] +use windmill_common::error::Error; #[cfg(all(feature = "enterprise", feature = "kafka"))] use crate::kafka_triggers_ee::KafkaTriggerConfigConnection; @@ -47,11 +57,10 @@ use crate::nats_triggers_ee::NatsTriggerConfigConnection; #[cfg(feature = "postgres_trigger")] use { crate::postgres_triggers::{ - create_logical_replication_slot_query, create_publication_query, drop_publication_query, - generate_random_string, get_database_connection, PublicationData, + create_logical_replication_slot, create_pg_publication, generate_random_string, + get_pg_connection, PublicationData, }, - itertools::Itertools, - pg_escape::quote_literal, + sqlx::Connection, }; use crate::{ @@ -200,9 +209,12 @@ pub struct MqttTriggerConfig { #[derive(Serialize, Deserialize, Debug)] pub struct PostgresTriggerConfig { pub postgres_resource_path: String, + #[serde(default, deserialize_with = "empty_as_none")] pub publication_name: Option, + #[serde(default, deserialize_with = "empty_as_none")] pub replication_slot_name: Option, pub publication: PublicationData, + pub basic_mode: Option, } #[cfg(feature = "websocket")] @@ -292,57 +304,49 @@ async fn set_postgres_trigger_config( user_db: UserDB, mut capture_config: NewCaptureConfig, ) -> Result { - let Some(TriggerConfig::Postgres(mut postgres_config)) = capture_config.trigger_config else { - return Err(windmill_common::error::Error::BadRequest( - "Invalid postgres config".to_string(), - )); + let Some(TriggerConfig::Postgres(postgres_config)) = capture_config.trigger_config.as_mut() + else { + return Err(Error::BadRequest("Invalid postgres config".to_string())); }; - let mut connection = get_database_connection( - authed, - Some(user_db), - &db, - &postgres_config.postgres_resource_path, - &w_id, - ) - .await?; + if postgres_config.basic_mode.unwrap_or(false) { + let mut pg_connection = get_pg_connection( + authed, + Some(user_db), + &db, + &postgres_config.postgres_resource_path, + &w_id, + ) + .await?; - let publication_name = postgres_config - .publication_name - .get_or_insert(format!("windmill_capture_{}", generate_random_string())); - let replication_slot_name = postgres_config - .replication_slot_name - .get_or_insert(publication_name.clone()); + let mut tx = pg_connection.begin().await?; - let query = drop_publication_query(&publication_name); + let publication_name = format!("windmill_capture_{}", generate_random_string()); + let replication_slot_name = publication_name.clone(); - sqlx::query(&query).execute(&mut connection).await?; + create_logical_replication_slot(&mut tx, &replication_slot_name).await?; - let query = create_publication_query( - &publication_name, - postgres_config.publication.table_to_track.as_deref(), - &postgres_config - .publication - .transaction_to_track - .iter() - .map(AsRef::as_ref) - .collect_vec(), - ); + create_pg_publication( + &mut tx, + &publication_name, + postgres_config.publication.table_to_track.as_deref(), + &postgres_config.publication.transaction_to_track, + ) + .await?; - sqlx::query(&query).execute(&mut connection).await?; - - let query = format!( - "SELECT 1 from pg_replication_slots WHERE slot_name = {}", - quote_literal(replication_slot_name) - ); - - let row = sqlx::query(&query).fetch_optional(&mut connection).await?; - - if row.is_none() { - let query = create_logical_replication_slot_query(&replication_slot_name); - sqlx::query(&query).execute(&mut connection).await?; + tx.commit().await?; + postgres_config.publication_name = Some(publication_name); + postgres_config.replication_slot_name = Some(replication_slot_name); + } else { + if postgres_config.publication_name.is_none() + || postgres_config.replication_slot_name.is_none() + { + return Err(Error::BadRequest( + "Publication name and slot name required in advanced mode".to_string(), + )); + } } - capture_config.trigger_config = Some(TriggerConfig::Postgres(postgres_config)); + Ok(capture_config) } @@ -366,9 +370,7 @@ async fn set_gcp_trigger_config( mut capture_config: NewCaptureConfig, ) -> Result { let Some(TriggerConfig::Gcp(mut gcp_config)) = capture_config.trigger_config else { - return Err(windmill_common::error::Error::BadRequest( - "Invalid GCP Pub/Sub config".to_string(), - )); + return Err(Error::BadRequest("Invalid GCP Pub/Sub config".to_string())); }; let config = manage_google_subscription( diff --git a/backend/windmill-api/src/postgres_triggers/handler.rs b/backend/windmill-api/src/postgres_triggers/handler.rs index 933582670c..9beafadbf2 100644 --- a/backend/windmill-api/src/postgres_triggers/handler.rs +++ b/backend/windmill-api/src/postgres_triggers/handler.rs @@ -6,7 +6,6 @@ use std::collections::{ use crate::{ db::{ApiAuthed, DB}, postgres_triggers::mapper::{Mapper, MappingInfo}, - resources::try_get_resource_from_db_as, }; use axum::{ extract::{Path, Query}, @@ -19,21 +18,20 @@ use quick_cache::sync::Cache; use rust_postgres::types::Type; use serde::{Deserialize, Deserializer, Serialize}; use sql_builder::{bind::Bind, SqlBuilder}; -use sqlx::{postgres::types::Oid, FromRow, PgConnection}; +use sqlx::{postgres::types::Oid, Connection, FromRow, PgConnection}; use windmill_audit::{audit_ee::audit_log, ActionKind}; -use windmill_common::error::Error; use windmill_common::{ db::UserDB, - error::{self, JsonResult, Result}, - utils::{not_found_if_none, paginate, Pagination, StripPath, empty_as_none}, + error::{self, Error, JsonResult, Result}, + utils::{empty_as_none, not_found_if_none, paginate, Pagination, StripPath}, worker::CLOUD_HOSTED, }; use windmill_git_sync::{handle_deployment_metadata, DeployedObject}; use super::{ - create_logical_replication_slot_query, create_publication_query, drop_publication_query, - generate_random_string, get_database_connection, get_raw_postgres_connection, - ERROR_PUBLICATION_NAME_NOT_EXISTS, ERROR_REPLICATION_SLOT_NOT_EXISTS, + check_if_valid_publication_for_postgres_version, create_logical_replication_slot, + create_pg_publication, drop_publication, generate_random_string, get_pg_connection, + ERROR_PUBLICATION_NAME_NOT_EXISTS, }; use lazy_static::lazy_static; @@ -53,15 +51,17 @@ pub struct Postgres { #[derive(Debug, Clone, FromRow, Serialize, Deserialize)] pub struct TableToTrack { pub table_name: String, + #[serde(default, deserialize_with = "empty_as_none")] pub where_clause: Option, - pub columns_name: Vec, + #[serde(default, deserialize_with = "empty_as_none")] + pub columns_name: Option>, } impl TableToTrack { fn new( table_name: String, where_clause: Option, - columns_name: Vec, + columns_name: Option>, ) -> TableToTrack { TableToTrack { table_name, where_clause, columns_name } } @@ -99,7 +99,6 @@ pub struct EditPostgresTrigger { } #[derive(Deserialize, Serialize, Debug)] - pub struct NewPostgresTrigger { path: String, script_path: String, @@ -124,7 +123,7 @@ pub async fn test_postgres_connection( Json(test_postgres): Json, ) -> Result<()> { let connect_f = async { - get_database_connection( + get_pg_connection( authed, Some(user_db), &db, @@ -189,7 +188,7 @@ where )); } - if !track_specific_columns_in_table && !table_to_track.columns_name.is_empty() { + if !track_specific_columns_in_table && table_to_track.columns_name.is_some() { track_specific_columns_in_table = true; } } @@ -267,39 +266,16 @@ impl PostgresPublicationReplication { } } -async fn check_if_publication_exist( - connection: &mut PgConnection, - publication_name: &str, -) -> Result<()> { - sqlx::query!( - "SELECT pubname FROM pg_publication WHERE pubname = $1", - publication_name - ) - .fetch_one(connection) - .await - .map_err(|err| match err { - sqlx::Error::RowNotFound => { - Error::BadRequest(ERROR_PUBLICATION_NAME_NOT_EXISTS.to_string()) - } - err => Error::SqlErr { error: err, location: "pg_trigger".to_string() }, - })?; - Ok(()) -} - async fn check_if_logical_replication_slot_exist( - connection: &mut PgConnection, + pg_connection: &mut PgConnection, replication_slot_name: &str, -) -> Result<()> { - sqlx::query!( - "SELECT slot_name FROM pg_replication_slots where slot_name = $1", - &replication_slot_name - ) - .fetch_one(connection) - .await - .map_err(|err| match err { - _ => Error::BadRequest(ERROR_REPLICATION_SLOT_NOT_EXISTS.to_string()), - })?; - Ok(()) +) -> Result { + let exists = sqlx::query("SELECT slot_name FROM pg_replication_slots where slot_name = $1") + .bind(&replication_slot_name) + .fetch_optional(pg_connection) + .await? + .is_some(); + Ok(exists) } async fn create_custom_slot_and_publication_inner( @@ -310,33 +286,30 @@ async fn create_custom_slot_and_publication_inner( w_id: &str, publication: &PublicationData, ) -> Result { - let publication_name = format!("windmill_trigger_{}", generate_random_string()); - let replication_slot_name = publication_name.clone(); - - let query = create_publication_query( - &publication_name, - publication.table_to_track.as_deref(), - &publication - .transaction_to_track - .iter() - .map(AsRef::as_ref) - .collect_vec(), - ); - - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), - Some(user_db.clone()), + Some(user_db), &db, &postgres_resource_path, &w_id, ) .await?; - sqlx::query(&query).execute(&mut connection).await?; + let mut tx = pg_connection.begin().await?; + let publication_name = format!("windmill_trigger_{}", generate_random_string()); + let replication_slot_name = publication_name.clone(); + + create_logical_replication_slot(&mut tx, &replication_slot_name).await?; + + create_pg_publication( + &mut tx, + &publication_name, + publication.table_to_track.as_deref(), + &publication.transaction_to_track, + ) + .await?; - let query = create_logical_replication_slot_query(&replication_slot_name); - - sqlx::query(&query).execute(&mut connection).await?; + tx.commit().await?; Ok(PostgresPublicationReplication::new( publication_name, @@ -344,6 +317,38 @@ async fn create_custom_slot_and_publication_inner( )) } +pub async fn get_postgres_version_internal(pg_connection: &mut PgConnection) -> Result { + let postgres_version: String = sqlx::query_scalar("SHOW server_version;") + .fetch_one(&mut *pg_connection) + .await + .map_err(|e| Error::Anyhow { + error: anyhow::anyhow!("Failed to retrieve PostgreSQL version: {}", e), + location: "postgres_triggers/handler.rs@379".to_string(), + })?; + + Ok(postgres_version) +} + +pub async fn get_postgres_version( + authed: ApiAuthed, + Extension(db): Extension, + Extension(user_db): Extension, + Path((w_id, postgres_resource_path)): Path<(String, String)>, +) -> Result { + let mut pg_connection = get_pg_connection( + authed.clone(), + Some(user_db), + &db, + &postgres_resource_path, + &w_id, + ) + .await?; + + let postgres_version = get_postgres_version_internal(&mut pg_connection).await?; + + Ok(postgres_version) +} + pub async fn create_postgres_trigger( authed: ApiAuthed, Extension(user_db): Extension, @@ -377,6 +382,7 @@ pub async fn create_postgres_trigger( if publication.is_none() { return Err(Error::BadRequest("publication must be set".to_string())); } + let PostgresPublicationReplication { publication_name, replication_slot_name } = create_custom_slot_and_publication_inner( authed.clone(), @@ -577,7 +583,7 @@ impl PublicationData { } } -#[derive(Debug, Serialize)] +#[derive(FromRow, Debug, Serialize)] pub struct SlotList { slot_name: Option, active: Option, @@ -589,7 +595,7 @@ pub async fn list_slot_name( Extension(db): Extension, Path((w_id, postgres_resource_path)): Path<(String, String)>, ) -> Result>> { - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -598,8 +604,7 @@ pub async fn list_slot_name( ) .await?; - let slots = sqlx::query_as!( - SlotList, + let slots: Vec = sqlx::query_as( r#" SELECT slot_name, @@ -609,9 +614,9 @@ pub async fn list_slot_name( WHERE plugin = 'pgoutput' AND slot_type = 'logical'; - "# + "#, ) - .fetch_all(&mut connection) + .fetch_all(&mut pg_connection) .await?; Ok(Json(slots)) @@ -629,7 +634,7 @@ pub async fn create_slot( Path((w_id, postgres_resource_path)): Path<(String, String)>, Json(Slot { name }): Json, ) -> Result { - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -638,13 +643,42 @@ pub async fn create_slot( ) .await?; - let query = create_logical_replication_slot_query(&name); - - sqlx::query(&query).execute(&mut connection).await?; + create_logical_replication_slot(&mut pg_connection, &name).await?; Ok(format!("Replication slot {} created!", name)) } +pub async fn drop_logical_replication_slot( + pg_connection: &mut PgConnection, + slot_name: &str, +) -> Result<()> { + let active_pid: Option = sqlx::query_scalar( + r#"SELECT + active_pid + FROM + pg_replication_slots + WHERE + slot_name = $1 + "#, + ) + .bind(&slot_name) + .fetch_optional(&mut *pg_connection) + .await? + .flatten(); + + if let Some(pid) = active_pid { + sqlx::query("SELECT pg_terminate_backend($1)") + .bind(pid) + .execute(&mut *pg_connection) + .await?; + } + sqlx::query("SELECT pg_drop_replication_slot($1)") + .bind(&slot_name) + .execute(pg_connection) + .await?; + Ok(()) +} + pub async fn drop_slot_name( authed: ApiAuthed, Extension(user_db): Extension, @@ -652,45 +686,14 @@ pub async fn drop_slot_name( Path((w_id, postgres_resource_path)): Path<(String, String)>, Json(Slot { name }): Json, ) -> Result { - let database = try_get_resource_from_db_as::( - authed, - Some(user_db), - &db, - &postgres_resource_path, - &w_id, - ) - .await?; + let mut pg_connection = + get_pg_connection(authed, Some(user_db), &db, &postgres_resource_path, &w_id).await?; - let mut connection = get_raw_postgres_connection(&database).await?; - - let active_pid = sqlx::query_scalar!( - r#"SELECT - active_pid - FROM - pg_replication_slots - WHERE - slot_name = $1 - "#, - &name - ) - .fetch_optional(&mut connection) - .await? - .flatten(); - - if let Some(pid) = active_pid { - sqlx::query("SELECT pg_terminate_backend($1)") - .bind(pid) - .execute(&mut connection) - .await?; - } - sqlx::query("SELECT pg_drop_replication_slot($1)") - .bind(&name) - .execute(&mut connection) - .await?; + drop_logical_replication_slot(&mut pg_connection, &name).await?; Ok(format!("Replication slot {} deleted!", name)) } -#[derive(Debug, Serialize)] +#[derive(FromRow, Debug, Serialize)] struct PublicationName { publication_name: String, } @@ -701,7 +704,7 @@ pub async fn list_database_publication( Extension(db): Extension, Path((w_id, postgres_resource_path)): Path<(String, String)>, ) -> Result>> { - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -710,12 +713,10 @@ pub async fn list_database_publication( ) .await?; - let publication_names = sqlx::query_as!( - PublicationName, - "SELECT pubname AS publication_name FROM pg_publication;" - ) - .fetch_all(&mut connection) - .await?; + let publication_names: Vec = + sqlx::query_as("SELECT pubname AS publication_name FROM pg_publication;") + .fetch_all(&mut pg_connection) + .await?; let publications = publication_names .iter() @@ -731,7 +732,7 @@ pub async fn get_publication_info( Extension(db): Extension, Path((w_id, publication_name, postgres_resource_path)): Path<(String, String, String)>, ) -> Result> { - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -741,11 +742,11 @@ pub async fn get_publication_info( .await?; let publication_data = - get_publication_scope_and_transaction(&mut connection, &publication_name).await; + get_publication_scope_and_transaction(&mut pg_connection, &publication_name).await; let (all_table, transaction_to_track) = match publication_data { - Ok(pub_data) => pub_data, - Err(Error::SqlErr { error: sqlx::Error::RowNotFound, .. }) => { + Ok(Some(pub_data)) => pub_data, + Ok(None) => { return Err(Error::NotFound( ERROR_PUBLICATION_NAME_NOT_EXISTS.to_string(), )) @@ -754,7 +755,7 @@ pub async fn get_publication_info( }; let table_to_track = if !all_table { - Some(get_tracked_relations(&mut connection, &publication_name).await?) + Some(get_tracked_relations(&mut pg_connection, &publication_name).await?) } else { None }; @@ -771,9 +772,7 @@ pub async fn create_publication( Path((w_id, publication_name, postgres_resource_path)): Path<(String, String, String)>, Json(publication_data): Json, ) -> Result { - let PublicationData { table_to_track, transaction_to_track } = publication_data; - - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -782,13 +781,19 @@ pub async fn create_publication( ) .await?; - let query = create_publication_query( + let PublicationData { table_to_track, transaction_to_track } = publication_data; + + let mut tx = pg_connection.begin().await?; + + create_pg_publication( + &mut tx, &publication_name, table_to_track.as_deref(), - &transaction_to_track.iter().map(AsRef::as_ref).collect_vec(), - ); + &transaction_to_track, + ) + .await?; - sqlx::query(&query).execute(&mut connection).await?; + tx.commit().await?; Ok(format!( "Publication {} successfully created!", @@ -802,7 +807,7 @@ pub async fn delete_publication( Extension(db): Extension, Path((w_id, publication_name, postgres_resource_path)): Path<(String, String, String)>, ) -> Result { - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -811,9 +816,7 @@ pub async fn delete_publication( ) .await?; - let query = drop_publication_query(&publication_name); - - sqlx::query(&query).execute(&mut connection).await?; + drop_publication(&mut pg_connection, &publication_name).await?; Ok(format!( "Publication {} successfully deleted!", @@ -821,27 +824,37 @@ pub async fn delete_publication( )) } -pub fn get_update_publication_query( +pub async fn update_pg_publication( + pg_connection: &mut PgConnection, publication_name: &str, PublicationData { table_to_track, transaction_to_track }: PublicationData, - all_table: bool, -) -> Vec { + all_table: Option, +) -> Result<()> { let quoted_publication_name = quote_identifier(&publication_name); - let transaction_to_track_as_str = transaction_to_track.iter().join(","); - let mut queries = Vec::with_capacity(2); match table_to_track { Some(ref relations) if !relations.is_empty() => { - if all_table { - queries.push(drop_publication_query(&publication_name)); - queries.push(create_publication_query( + //if all table is none it means that the publication do not exist in the database + if all_table.unwrap_or(true) { + if all_table.is_some() { + drop_publication(pg_connection, &publication_name).await?; + } + create_pg_publication( + pg_connection, &publication_name, table_to_track.as_deref(), - &transaction_to_track.iter().map(AsRef::as_ref).collect_vec(), - )); + &transaction_to_track, + ) + .await?; } else { - let mut query = String::from(""); + let pg_14 = check_if_valid_publication_for_postgres_version( + pg_connection, + table_to_track.as_deref(), + ) + .await?; + let mut query = String::from(""); + let mut first = true; query.push_str("ALTER PUBLICATION "); query.push_str("ed_publication_name); query.push_str(" SET"); @@ -851,16 +864,20 @@ pub fn get_update_publication_query( let quoted_schema = quote_identifier(&schema.schema_name); query.push_str("ed_schema); } else { - query.push_str(" TABLE ONLY "); + if pg_14 && first { + query.push_str(" TABLE ONLY "); + first = false + } else if !pg_14 { + query.push_str(" TABLE ONLY "); + } for (j, table) in schema.table_to_track.iter().enumerate() { let table_name = quote_identifier(&table.table_name); let schema_name = quote_identifier(&schema.schema_name); let full_name = format!("{}.{}", &schema_name, &table_name); query.push_str(&full_name); - if !table.columns_name.is_empty() { + if let Some(columns) = table.columns_name.as_ref() { query.push_str(" ("); - let columns = table - .columns_name + let columns = columns .iter() .map(|column| quote_identifier(column)) .join(", "); @@ -883,9 +900,8 @@ pub fn get_update_publication_query( query.push(','); } } - query.push(';'); - queries.push(query); + sqlx::query(&query).execute(&mut *pg_connection).await?; let mut query = String::new(); @@ -895,23 +911,25 @@ pub fn get_update_publication_query( " SET (publish = '{}');", transaction_to_track_as_str )); - queries.push(query); + + sqlx::query(&query).execute(pg_connection).await?; } } _ => { - queries.push(drop_publication_query(&publication_name)); - let to_execute = format!( + drop_publication(pg_connection, &publication_name).await?; + let query_to_execute = format!( r#" CREATE PUBLICATION {} FOR ALL TABLES WITH (publish = '{}'); "#, quoted_publication_name, transaction_to_track_as_str ); - queries.push(to_execute); + sqlx::query(&query_to_execute) + .execute(pg_connection) + .await?; } }; - - queries + Ok(()) } pub async fn alter_publication( @@ -921,7 +939,7 @@ pub async fn alter_publication( Path((w_id, publication_name, postgres_resource_path)): Path<(String, String, String)>, Json(publication_data): Json, ) -> Result { - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -930,16 +948,19 @@ pub async fn alter_publication( ) .await?; - check_if_publication_exist(&mut connection, &publication_name).await?; + let mut tx = pg_connection.begin().await?; + + let publication = get_publication_scope_and_transaction(&mut tx, &publication_name).await?; - let (all_table, _) = - get_publication_scope_and_transaction(&mut connection, &publication_name).await?; + update_pg_publication( + &mut tx, + &publication_name, + publication_data, + publication.map(|publication| publication.0), + ) + .await?; - let queries = get_update_publication_query(&publication_name, publication_data, all_table); - - for query in queries { - sqlx::query(&query).execute(&mut connection).await?; - } + tx.commit().await?; Ok(format!( "Publication {} updated with success", @@ -948,9 +969,9 @@ pub async fn alter_publication( } async fn get_publication_scope_and_transaction( - connection: &mut PgConnection, + pg_connection: &mut PgConnection, publication_name: &str, -) -> std::result::Result<(bool, Vec), Error> { +) -> Result)>> { #[derive(Debug, Deserialize, FromRow)] struct PublicationTransaction { all_table: bool, @@ -959,8 +980,7 @@ async fn get_publication_scope_and_transaction( delete: bool, } - let transaction = sqlx::query_as!( - PublicationTransaction, + let publication: Option = sqlx::query_as( r#" SELECT puballtables AS all_table, @@ -972,70 +992,100 @@ async fn get_publication_scope_and_transaction( WHERE pubname = $1 "#, - publication_name ) - .fetch_one(&mut *connection) + .bind(publication_name) + .fetch_optional(&mut *pg_connection) .await?; + if publication.is_none() { + return Ok(None); + } + let mut transaction_to_track = Vec::with_capacity(3); - if transaction.insert { + let publication = publication.unwrap(); + if publication.insert { transaction_to_track.push("insert".to_string()); } - if transaction.update { + if publication.update { transaction_to_track.push("update".to_string()); } - if transaction.delete { + if publication.delete { transaction_to_track.push("delete".to_string()); } - Ok((transaction.all_table, transaction_to_track)) + Ok(Some((publication.all_table, transaction_to_track))) } async fn get_tracked_relations( - connection: &mut PgConnection, + pg_connection: &mut PgConnection, publication_name: &str, ) -> Result> { #[derive(Debug, Deserialize, FromRow)] struct PublicationData { schema_name: Option, table_name: Option, + #[serde(default)] columns: Option>, + #[serde(default)] where_clause: Option, } - let publications = sqlx::query_as!( - PublicationData, + let pg_version = get_postgres_version_internal(pg_connection).await?; + let query = if pg_version.starts_with("14") { r#" SELECT schemaname AS schema_name, tablename AS table_name, - CASE - WHEN array_length(attnames, 1) = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = pg_publication_tables.schemaname AND table_name = pg_publication_tables.tablename) - THEN NULL - ELSE attnames - END AS columns, + NULL::text[] AS columns, + NULL::text AS where_clause + FROM + pg_publication_tables + WHERE + pubname = $1; + "# + } else { + r#" + SELECT + schemaname AS schema_name, + tablename AS table_name, + attnames AS columns, rowfilter AS where_clause FROM pg_publication_tables WHERE pubname = $1; - "#, - publication_name - ) - .fetch_all(&mut *connection) - .await?; + "# + }; + + let publications: Vec = sqlx::query_as(query) + .bind(publication_name) + .fetch_all(&mut *pg_connection) + .await?; let mut table_to_track: HashMap = HashMap::new(); for publication in publications { - let schema_name = publication.schema_name.unwrap(); + let schema_name = publication.schema_name.ok_or_else(|| Error::Anyhow { + error: anyhow::anyhow!( + "Unexpected NULL `schema_name` in publication entry (pubname: `{}`). This should never happen unless PostgreSQL internals are corrupted.", + publication_name, + ), + location: "postgres_triggers/handler.rs@1093".to_string(), + })?; + + let table_name = publication.table_name.ok_or_else(|| Error::Anyhow { + error: anyhow::anyhow!( + "Unexpected NULL `table_name` for schema `{}` in publication `{}`. This should never happen unless PostgreSQL internals are corrupted.", + schema_name, + publication_name, + ), + location: "postgres_triggers/handler.rs@1102".to_string(), + })?; + let entry = table_to_track.entry(schema_name.clone()); - let table_to_track = TableToTrack::new( - publication.table_name.unwrap(), - publication.where_clause, - publication.columns.unwrap_or_default(), - ); + let table_to_track = + TableToTrack::new(table_name, publication.where_clause, publication.columns); match entry { Occupied(mut occuped) => { occuped.get_mut().add_new_table(table_to_track); @@ -1111,7 +1161,7 @@ pub async fn update_postgres_trigger( publication, } = postgres_trigger; - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -1120,18 +1170,33 @@ pub async fn update_postgres_trigger( ) .await?; - check_if_logical_replication_slot_exist(&mut connection, &replication_slot_name).await?; + let exists = + check_if_logical_replication_slot_exist(&mut pg_connection, &replication_slot_name).await?; + + let mut tx = pg_connection.begin().await?; + + if !exists { + tracing::debug!( + "Logical replication slot named: {} does not exists creating it...", + &replication_slot_name + ); + create_logical_replication_slot(&mut tx, &replication_slot_name).await?; + } if let Some(publication) = publication { - check_if_publication_exist(&mut connection, &publication_name).await?; - let (all_table, _) = - get_publication_scope_and_transaction(&mut connection, &publication_name).await?; + let publication_data = + get_publication_scope_and_transaction(&mut tx, &publication_name).await?; - let queries = get_update_publication_query(&publication_name, publication, all_table); - for query in queries { - sqlx::query(&query).execute(&mut connection).await?; - } + update_pg_publication( + &mut tx, + &publication_name, + publication, + publication_data.map(|publication| publication.0), + ) + .await?; } + tx.commit().await?; + let mut tx = user_db.begin(&authed).await?; sqlx::query!( @@ -1356,7 +1421,7 @@ pub async fn create_template_script( )); } - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -1384,11 +1449,12 @@ pub async fn create_template_script( format!("{}.{}", &relation.schema_name, table_to_track.table_name); schema_or_fully_qualified_name.push(quote_literal(&fully_qualified_name)); - let columns = if !table_to_track.columns_name.is_empty() { - quote_literal(&table_to_track.columns_name.join(",")) - } else { - "''".to_string() - }; + let columns = table_to_track + .columns_name + .map(|columns| quote_literal(&columns.join(","))) + .or_else(|| Some("''".to_string())) + .unwrap(); + columns_list.push(columns); } continue; @@ -1448,11 +1514,7 @@ pub async fn create_template_script( tables_name, columns_list ); - let rows: Vec = sqlx::query_as(&query) - .fetch_all(&mut connection) - .await - .map_err(|e| error::Error::SqlErr { error: e, location: "pg_trigger".to_string() })?; - + let rows: Vec = sqlx::query_as(&query).fetch_all(&mut pg_connection).await?; let mut mapper: HashMap>> = HashMap::new(); for row in rows { @@ -1509,7 +1571,7 @@ pub async fn is_database_in_logical_level( Extension(db): Extension, Path((w_id, postgres_resource_path)): Path<(String, String)>, ) -> error::JsonResult { - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -1518,8 +1580,8 @@ pub async fn is_database_in_logical_level( ) .await?; - let wal_level = sqlx::query_scalar!("SHOW WAL_LEVEL;") - .fetch_optional(&mut connection) + let wal_level: Option = sqlx::query_scalar("SHOW WAL_LEVEL;") + .fetch_optional(&mut pg_connection) .await? .flatten(); diff --git a/backend/windmill-api/src/postgres_triggers/mod.rs b/backend/windmill-api/src/postgres_triggers/mod.rs index d557ca67cc..1cb0968f30 100644 --- a/backend/windmill-api/src/postgres_triggers/mod.rs +++ b/backend/windmill-api/src/postgres_triggers/mod.rs @@ -25,12 +25,17 @@ pub use handler::PostgresTrigger; use handler::{ alter_publication, create_postgres_trigger, create_publication, create_slot, create_template_script, delete_postgres_trigger, delete_publication, drop_slot_name, - exists_postgres_trigger, get_postgres_trigger, get_publication_info, get_template_script, + exists_postgres_trigger, get_postgres_trigger, get_postgres_version, + get_postgres_version_internal, get_publication_info, get_template_script, is_database_in_logical_level, list_database_publication, list_postgres_triggers, list_slot_name, set_enabled, test_postgres_connection, update_postgres_trigger, Postgres, Relations, }; -use windmill_common::{db::UserDB, error::Error, utils::StripPath}; +use windmill_common::{ + db::UserDB, + error::{Error, Result}, + utils::StripPath, +}; mod bool; mod converter; mod handler; @@ -47,13 +52,13 @@ const ERROR_REPLICATION_SLOT_NOT_EXISTS: &str = r#"The replication slot associat const ERROR_PUBLICATION_NAME_NOT_EXISTS: &str = r#"The publication associated with this trigger no longer exists. Recreate a new publication or select an existing one in the advanced tab, or delete and recreate a new trigger"#; -pub async fn get_database_connection( +pub async fn get_pg_connection( authed: ApiAuthed, user_db: Option, db: &DB, postgres_resource_path: &str, w_id: &str, -) -> std::result::Result { +) -> Result { let database = try_get_resource_from_db_as::(authed, user_db, db, postgres_resource_path, w_id) .await?; @@ -61,9 +66,7 @@ pub async fn get_database_connection( Ok(get_raw_postgres_connection(&database).await?) } -pub async fn get_raw_postgres_connection( - db: &Postgres, -) -> std::result::Result { +pub async fn get_raw_postgres_connection(db: &Postgres) -> Result { let options = { let sslmode = if !db.sslmode.is_empty() { PgSslMode::from_str(&db.sslmode)? @@ -99,7 +102,10 @@ pub async fn get_raw_postgres_connection( Ok(PgConnection::connect_with(&options).await?) } -pub fn create_logical_replication_slot_query(name: &str) -> String { +pub async fn create_logical_replication_slot( + pg_connection: &mut PgConnection, + name: &str, +) -> Result<()> { let query = format!( r#" SELECT @@ -109,14 +115,53 @@ pub fn create_logical_replication_slot_query(name: &str) -> String { quote_literal(&name) ); - query + sqlx::query(&query).execute(pg_connection).await?; + + Ok(()) } -pub fn create_publication_query( +async fn check_if_valid_publication_for_postgres_version( + pg_connection: &mut PgConnection, + table_to_track: Option<&[Relations]>, +) -> Result { + let postgres_version = get_postgres_version_internal(pg_connection).await?; + + let pg_14 = postgres_version.starts_with("14"); + if pg_14 { + let unsupported_publication = table_to_track + .and_then(|relations| { + relations.iter().find(|relation| { + let invalid_relation = relation.table_to_track.iter().find(|table_to_track| { + table_to_track.where_clause.is_some() + || table_to_track.columns_name.is_some() + }); + + relation.table_to_track.is_empty() || invalid_relation.is_some() + }) + }) + .is_some(); + + if unsupported_publication { + return Err(Error::BadRequest( + "Your PostgreSQL database is running version 14, which does not support the following publication features: \ + - WHERE clause filtering, \ + - selective column tracking, and \ + - tracking all tables within a schema.\n\ + These features are only available in PostgreSQL 15 and above.".to_string(), + )); + } + } + Ok(pg_14) +} + +pub async fn create_pg_publication( + pg_connection: &mut PgConnection, publication_name: &str, table_to_track: Option<&[Relations]>, - transaction_to_track: &[&str], -) -> String { + transaction_to_track: &[String], +) -> Result<()> { + let pg_14 = + check_if_valid_publication_for_postgres_version(pg_connection, table_to_track).await?; let mut query = String::from("CREATE PUBLICATION "); query.push_str("e_identifier(publication_name)); @@ -124,21 +169,26 @@ pub fn create_publication_query( match table_to_track { Some(database_component) if !database_component.is_empty() => { query.push_str(" FOR"); + let mut first = true; for (i, schema) in database_component.iter().enumerate() { if schema.table_to_track.is_empty() { query.push_str(" TABLES IN SCHEMA "); query.push_str("e_identifier(&schema.schema_name)); } else { - query.push_str(" TABLE ONLY "); + if pg_14 && first { + query.push_str(" TABLE ONLY "); + first = false; + } else if !pg_14 { + query.push_str(" TABLE ONLY "); + } for (j, table) in schema.table_to_track.iter().enumerate() { let table_name = quote_identifier(&table.table_name); let schema_name = quote_identifier(&schema.schema_name); let full_name = format!("{}.{}", &schema_name, &table_name); query.push_str(&full_name); - if !table.columns_name.is_empty() { + if let Some(columns) = table.columns_name.as_ref() { query.push_str(" ("); - let columns = table - .columns_name + let columns = columns .iter() .map(|column| quote_identifier(column)) .join(", "); @@ -174,22 +224,22 @@ pub fn create_publication_query( query.push_str("');"); } - query + sqlx::query(&query).execute(pg_connection).await?; + + Ok(()) } -pub fn drop_publication_query(publication_name: &str) -> String { +pub async fn drop_publication( + pg_connection: &mut PgConnection, + publication_name: &str, +) -> Result<()> { let mut query = String::from("DROP PUBLICATION IF EXISTS "); let quoted_publication_name = quote_identifier(publication_name); query.push_str("ed_publication_name); - query.push_str(";"); - query -} -pub fn drop_logical_replication_slot_query(replication_slot_name: &str) -> String { - format!( - "SELECT pg_drop_replication_slot({});", - quote_literal(&replication_slot_name) - ) + sqlx::query(&query).execute(pg_connection).await?; + + Ok(()) } pub fn generate_random_string() -> String { @@ -228,6 +278,10 @@ fn slot_service() -> Router { .route("/delete/*path", delete(drop_slot_name)) } +fn postgres_service() -> Router { + Router::new().route("/version/*path", get(get_postgres_version)) +} + pub fn workspaced_service() -> Router { Router::new() .route("/test", post(test_postgres_connection)) @@ -246,6 +300,7 @@ pub fn workspaced_service() -> Router { ) .nest("/publication", publication_service()) .nest("/slot", slot_service()) + .nest("/postgres", postgres_service()) } async fn run_job( diff --git a/backend/windmill-api/src/postgres_triggers/trigger.rs b/backend/windmill-api/src/postgres_triggers/trigger.rs index 71daffb4a9..b16862992e 100644 --- a/backend/windmill-api/src/postgres_triggers/trigger.rs +++ b/backend/windmill-api/src/postgres_triggers/trigger.rs @@ -34,8 +34,8 @@ use windmill_common::{ }; use super::{ - drop_logical_replication_slot_query, drop_publication_query, get_database_connection, - handler::{Postgres, PostgresTrigger}, + drop_publication, get_pg_connection, + handler::{drop_logical_replication_slot, Postgres, PostgresTrigger}, replication_message::PrimaryKeepAliveBody, ERROR_PUBLICATION_NAME_NOT_EXISTS, ERROR_REPLICATION_SLOT_NOT_EXISTS, }; @@ -585,7 +585,7 @@ impl PostgresConfig { let user_db = UserDB::new(db.clone()); - let mut connection = get_database_connection( + let mut pg_connection = get_pg_connection( authed.clone(), Some(user_db.clone()), &db, @@ -594,13 +594,12 @@ impl PostgresConfig { ) .await?; - let query = drop_logical_replication_slot_query(replication_slot_name); + if capture.trigger_config.basic_mode.unwrap_or(false) { + drop_logical_replication_slot(&mut pg_connection, replication_slot_name) + .await?; - let _ = sqlx::query(&query).execute(&mut connection).await; - - let query = drop_publication_query(publication_name); - - let _ = sqlx::query(&query).execute(&mut connection).await; + drop_publication(&mut pg_connection, publication_name).await?; + } Ok(()) } diff --git a/backend/windmill-api/src/triggers.rs b/backend/windmill-api/src/triggers.rs index 7101bdd2a9..c1cccb1c98 100644 --- a/backend/windmill-api/src/triggers.rs +++ b/backend/windmill-api/src/triggers.rs @@ -21,6 +21,9 @@ pub struct TriggersCount { kafka_count: i64, nats_count: i64, postgres_count: i64, + mqtt_count: i64, + sqs_count: i64, + gcp_count: i64, } pub(crate) async fn get_triggers_count_internal( db: &DB, @@ -97,6 +100,36 @@ pub(crate) async fn get_triggers_count_internal( .await? .unwrap_or(0); + let mqtt_count = sqlx::query_scalar!( + "SELECT COUNT(*) FROM mqtt_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3", + path, + is_flow, + w_id + ) + .fetch_one(db) + .await? + .unwrap_or(0); + + let sqs_count = sqlx::query_scalar!( + "SELECT COUNT(*) FROM sqs_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3", + path, + is_flow, + w_id + ) + .fetch_one(db) + .await? + .unwrap_or(0); + + let gcp_count = sqlx::query_scalar!( + "SELECT COUNT(*) FROM gcp_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3", + path, + is_flow, + w_id + ) + .fetch_one(db) + .await? + .unwrap_or(0); + let webhook_count = (if is_flow { sqlx::query_scalar!( "SELECT COUNT(*) FROM token WHERE label LIKE 'webhook-%' AND workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]", @@ -141,6 +174,9 @@ pub(crate) async fn get_triggers_count_internal( kafka_count, nats_count, postgres_count, + mqtt_count, + gcp_count, + sqs_count, })) } diff --git a/backend/windmill-api/src/users.rs b/backend/windmill-api/src/users.rs index 1f8529fe6a..5bc7ce9c4d 100644 --- a/backend/windmill-api/src/users.rs +++ b/backend/windmill-api/src/users.rs @@ -334,6 +334,7 @@ pub struct NewUser { pub super_admin: bool, pub name: Option, pub company: Option, + pub skip_email: Option, } #[derive(Deserialize)] diff --git a/backend/windmill-api/src/workspaces_export.rs b/backend/windmill-api/src/workspaces_export.rs index c58d773f66..cd2be0f708 100644 --- a/backend/windmill-api/src/workspaces_export.rs +++ b/backend/windmill-api/src/workspaces_export.rs @@ -360,6 +360,7 @@ pub(crate) async fn tarball_workspace( ScriptLang::Bigquery => "bq.sql", ScriptLang::Snowflake => "sf.sql", ScriptLang::Mssql => "ms.sql", + ScriptLang::DuckDb => "duckdb.sql", ScriptLang::Graphql => "gql", ScriptLang::Nativets => "fetch.ts", ScriptLang::Bun | ScriptLang::Bunnative => { diff --git a/backend/windmill-common/src/client.rs b/backend/windmill-common/src/client.rs index 95d9f64bd2..0c5394c6e6 100644 --- a/backend/windmill-common/src/client.rs +++ b/backend/windmill-common/src/client.rs @@ -2,7 +2,11 @@ use anyhow::Context; use reqwest::{Body, Response}; use serde::de::DeserializeOwned; -use crate::utils::HTTP_CLIENT; +use crate::{ + error::{self, to_anyhow}, + s3_helpers::{DuckdbConnectionSettingsQueryV2, DuckdbConnectionSettingsResponse}, + utils::HTTP_CLIENT, +}; #[derive(Clone)] pub struct AuthedClient { @@ -197,4 +201,44 @@ impl AuthedClient { _ => Err(anyhow::anyhow!(response.text().await.unwrap_or_default()))?, } } + + pub async fn get_duckdb_connection_settings( + &self, + s3: &DuckdbConnectionSettingsQueryV2, + ) -> error::Result { + let url = format!( + "{}/api/w/{}/job_helpers/v2/duckdb_connection_settings", + self.base_internal_url, &self.workspace + ); + let response = self + .force_client + .as_ref() + .unwrap_or(&HTTP_CLIENT) + .post(url) + .header( + reqwest::header::CONTENT_TYPE, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .header( + reqwest::header::AUTHORIZATION, + reqwest::header::HeaderValue::from_str(&format!("Bearer {}", self.token)) + .map_err(|e| error::Error::BadConfig(e.to_string()))?, + ) + .body(serde_json::to_string(&s3).map_err(to_anyhow)?) + .send() + .await + .context(format!("Sent get_duckdb_connection_settings request",)) + .map_err(error::Error::from)?; + match response.status().as_u16() { + 200u16 => Ok(response + .json::() + .await + .context("decoding duckdb_connection_settings response as json")?), + _ => Err(anyhow::anyhow!(response.text().await.unwrap_or_default()))?, + } + } } diff --git a/backend/windmill-common/src/s3_helpers.rs b/backend/windmill-common/src/s3_helpers.rs index 29f59cf07c..7e7c48851e 100644 --- a/backend/windmill-common/src/s3_helpers.rs +++ b/backend/windmill-common/src/s3_helpers.rs @@ -891,3 +891,20 @@ pub async fn convert_json_line_stream>( Ok(tokio_stream::wrappers::ReceiverStream::new(rx)) } + +#[derive(Deserialize, Serialize)] +pub struct DuckdbConnectionSettingsResponse { + pub connection_settings_str: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub azure_container_path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub s3_bucket: Option, +} + +#[derive(Deserialize, Serialize)] +pub struct DuckdbConnectionSettingsQueryV2 { + #[serde(skip_serializing_if = "Option::is_none")] + pub s3_resource_path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub storage: Option, +} diff --git a/backend/windmill-common/src/schema.rs b/backend/windmill-common/src/schema.rs index 2b24ead0d3..71ecd220d1 100644 --- a/backend/windmill-common/src/schema.rs +++ b/backend/windmill-common/src/schema.rs @@ -349,7 +349,7 @@ pub fn should_validate_schema(code: &str, lang: &ScriptLang) -> bool { let comment = match lang { Nativets | Bun | Bunnative | Deno | Php | CSharp | Java => "//", Python3 | Go | Bash | Powershell | Graphql | Ansible | Nu => "#", - Postgresql | Mysql | Bigquery | Snowflake | Mssql | OracleDB => "--", + Postgresql | Mysql | Bigquery | Snowflake | Mssql | OracleDB | DuckDb => "--", Rust => "//!", // for related places search: ADD_NEW_LANG }; diff --git a/backend/windmill-common/src/scripts.rs b/backend/windmill-common/src/scripts.rs index e0391767f8..dda9daf0f4 100644 --- a/backend/windmill-common/src/scripts.rs +++ b/backend/windmill-common/src/scripts.rs @@ -46,13 +46,13 @@ pub enum ScriptLang { Graphql, Mssql, OracleDB, + DuckDb, Php, Rust, Ansible, CSharp, Nu, - Java, - // for related places search: ADD_NEW_LANG + Java, // for related places search: ADD_NEW_LANG } impl ScriptLang { @@ -73,6 +73,7 @@ impl ScriptLang { ScriptLang::Mssql => "mssql", ScriptLang::Graphql => "graphql", ScriptLang::OracleDB => "oracledb", + ScriptLang::DuckDb => "duckdb", ScriptLang::Php => "php", ScriptLang::Rust => "rust", ScriptLang::Ansible => "ansible", diff --git a/backend/windmill-common/src/worker.rs b/backend/windmill-common/src/worker.rs index aa1a715758..6b11fa086f 100644 --- a/backend/windmill-common/src/worker.rs +++ b/backend/windmill-common/src/worker.rs @@ -79,6 +79,7 @@ lazy_static::lazy_static! { "csharp".to_string(), "nu".to_string(), "java".to_string(), + "duckdb".to_string(), // for related places search: ADD_NEW_LANG "dependency".to_string(), "flow".to_string(), diff --git a/backend/windmill-worker/Cargo.toml b/backend/windmill-worker/Cargo.toml index 4dccc3213c..6a6a0abf01 100644 --- a/backend/windmill-worker/Cargo.toml +++ b/backend/windmill-worker/Cargo.toml @@ -31,6 +31,7 @@ csharp = ["dep:windmill-parser-csharp"] rust = ["dep:windmill-parser-rust"] nu = ["dep:windmill-parser-nu"] java = ["dep:windmill-parser-java"] +duckdb = ["dep:duckdb"] [dependencies] windmill-queue.workspace = true @@ -92,6 +93,7 @@ deno_permissions = { workspace = true, optional = true } deno_io = { workspace = true, optional = true } deno_error = { workspace = true, optional = true } async-stream.workspace = true +duckdb = { workspace = true, optional = true } postgres-native-tls.workspace = true native-tls.workspace = true diff --git a/backend/windmill-worker/nsjail/download.rust.config.proto b/backend/windmill-worker/nsjail/download.rust.config.proto new file mode 100644 index 0000000000..7239a77b74 --- /dev/null +++ b/backend/windmill-worker/nsjail/download.rust.config.proto @@ -0,0 +1,117 @@ +name: "rust download script" + +mode: ONCE +hostname: "rust" +log_level: ERROR + +disable_rl: true + +cwd: "/tmp" + +clone_newnet: false + +keep_caps: false +keep_env: true +mount_proc: true + +mount { + src: "/bin" + dst: "/bin" + is_bind: true +} + +mount { + src: "/lib" + dst: "/lib" + is_bind: true +} + + +mount { + src: "/lib64" + dst: "/lib64" + is_bind: true + mandatory: false +} + + +mount { + src: "/usr" + dst: "/usr" + is_bind: true +} + +mount { + src: "/dev/null" + dst: "/dev/null" + is_bind: true + rw: true +} + +mount { + dst: "/tmp" + fstype: "tmpfs" + rw: true + options: "size=500000000" +} + +mount { + src: "/etc" + dst: "/etc" + is_bind: true +} + +mount { + src: "/dev/random" + dst: "/dev/random" + is_bind: true +} +mount { + src: "{JOB_DIR}" + dst: "/tmp" + is_bind: true + rw: true +} + +mount { + src: "/dev/urandom" + dst: "/dev/urandom" + is_bind: true +} + +iface_no_lo: true + +mount { + src: "{BUILD}" + dst: "{BUILD}" + is_bind: true + mandatory: false + rw: true +} +mount { + src: "{CARGO_HOME}" + dst: "{CARGO_HOME}" + is_bind: true + # Readonly + rw: false +} + +mount { + src: "{BUILD}/registry" + dst: "{CARGO_HOME}/registry" + is_bind: true + mandatory: true + # Read-write + rw: true +} + +mount { + src: "{BUILD}/git" + dst: "{CARGO_HOME}/git" + is_bind: true + mandatory: true + # Read-write + rw: true +} + +{DEV} diff --git a/backend/windmill-worker/nsjail/run.rust.config.proto b/backend/windmill-worker/nsjail/run.rust.config.proto index 3357cd88a9..d5265f8ddd 100644 --- a/backend/windmill-worker/nsjail/run.rust.config.proto +++ b/backend/windmill-worker/nsjail/run.rust.config.proto @@ -104,3 +104,6 @@ mount { } {SHARED_MOUNT} + +{DEV} + diff --git a/backend/windmill-worker/src/duckdb_executor.rs b/backend/windmill-worker/src/duckdb_executor.rs new file mode 100644 index 0000000000..8ee78292d3 --- /dev/null +++ b/backend/windmill-worker/src/duckdb_executor.rs @@ -0,0 +1,664 @@ +use std::collections::HashMap; +use std::env; + +use duckdb::types::TimeUnit; +use duckdb::{params_from_iter, Row}; +use rust_decimal::prelude::FromPrimitive; +use rust_decimal::Decimal; +use serde_json::value::RawValue; +use serde_json::{json, Value}; +use tokio::fs::remove_file; +use tokio::task; +use uuid::Uuid; +use windmill_common::error::{to_anyhow, Error, Result}; +use windmill_common::s3_helpers::{ + DuckdbConnectionSettingsQueryV2, DuckdbConnectionSettingsResponse, S3Object, +}; +use windmill_common::worker::{to_raw_value, Connection}; +use windmill_parser_sql::{parse_duckdb_sig, parse_sql_blocks}; +use windmill_queue::{CanceledBy, MiniPulledJob}; + +use crate::common::{build_args_values, OccupancyMetrics}; +use crate::handle_child::run_future_with_polling_update_job_poller; +#[cfg(feature = "mysql")] +use crate::mysql_executor::MysqlDatabase; +use crate::pg_executor::PgDatabase; +use crate::sanitized_sql_params::sanitize_and_interpolate_unsafe_sql_args; +use windmill_common::client::AuthedClient; + +fn do_duckdb_inner( + conn: &duckdb::Connection, + query: &str, + job_args: &HashMap, + skip_collect: bool, + column_order: &mut Option>, +) -> Result> { + let mut rows_vec = vec![]; + + let (query, job_args) = interpolate_named_args(query, &job_args); + + let mut stmt = conn + .prepare(&query) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + + let mut rows = stmt + .query(params_from_iter(job_args)) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + + if skip_collect { + return Ok(to_raw_value(&json!([]))); + } + + // Statement needs to be stepped at least once or stmt.column_names() will panic + let mut column_names = None; + loop { + let row = rows.next(); + match row { + Ok(Some(row)) => { + // Set column names if not already set + let stmt = row.as_ref(); + let column_names = match column_names.as_ref() { + Some(column_names) => column_names, + None => { + column_names = Some(stmt.column_names()); + column_names.as_ref().unwrap() + } + }; + + let row = row_to_value(row, &column_names.as_slice()) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + rows_vec.push(row); + } + Ok(None) => break, + Err(e) => { + return Err(Error::ExecutionErr(e.to_string())); + } + } + } + + if let (Some(column_order), Some(column_names)) = (column_order.as_mut(), column_names) { + *column_order = column_names.clone(); + } + + return Ok(to_raw_value(&rows_vec)); +} + +pub async fn do_duckdb( + job: &MiniPulledJob, + client: &AuthedClient, + query: &str, + conn: &Connection, + mem_peak: &mut i32, + canceled_by: &mut Option, + worker_name: &str, + column_order_ref: &mut Option>, + occupancy_metrics: &mut OccupancyMetrics, +) -> Result> { + let result_f = async { + let sig = parse_duckdb_sig(query)?.args; + let mut job_args = build_args_values(job, client, conn).await?; + + let (query, _) = &sanitize_and_interpolate_unsafe_sql_args(query, &sig, &job_args)?; + // Prevent interpolate_named_args from detecting argument identifiers in the signature for + // the first query block + let query = trunc_sig(query); + + let (_query_with_transformed_s3_uris, mut used_storages) = + transform_s3_uris(query, client).await?; + let query = _query_with_transformed_s3_uris.as_deref().unwrap_or(query); + + let job_args = { + let mut m: HashMap = HashMap::new(); + for sig_arg in sig.into_iter() { + let json_value = job_args + .remove(&sig_arg.name) + .or_else(|| sig_arg.default) + .unwrap_or_else(|| json!(null)); + + if matches!(&sig_arg.otyp.as_ref().map(String::as_str), Some("s3object")) { + let s3_obj = serde_json::from_value::(json_value).map_err(|e| { + Error::ExecutionErr(format!("Failed to deserialize S3Object: {}", e)) + })?; + let duckdb_conn_settings: windmill_common::s3_helpers::DuckdbConnectionSettingsResponse = client + .get_duckdb_connection_settings(&DuckdbConnectionSettingsQueryV2 { + s3_resource_path: None, + storage: s3_obj.storage.clone(), + }) + .await?; + + let uri = match ( + &duckdb_conn_settings.s3_bucket, + &duckdb_conn_settings.azure_container_path, + ) { + (Some(s3_bucket), None) => format!("s3://{}/{}", s3_bucket, &s3_obj.s3), + (None, Some(az_container)) => format!("{}/{}", az_container, &s3_obj.s3), + _ => { + return Err(Error::ExecutionErr( + "S3Object must have either s3_bucket or azure_container_path" + .to_string(), + )); + } + }; + m.insert(sig_arg.name, duckdb::types::Value::Text(uri)); + used_storages.insert(s3_obj.storage, duckdb_conn_settings); + } else { + let duckdb_value = json_value_to_duckdb_value( + &json_value, + sig_arg + .otyp + .clone() + .unwrap_or_else(|| "text".to_string()) + .as_str(), + client, + )?; + m.insert(sig_arg.name, duckdb_value); + } + } + m + }; + + let query_block_list = parse_sql_blocks(query); + + // Replace windmill resource ATTACH statements with the real instructions + let query_block_list = { + let mut v = vec![]; + for query_block in query_block_list.iter() { + match parse_attach_db_resource(query_block) { + Some(parsed) => v.extend( + transform_attach_db_resource_query(&parsed, &job.id, client).await?, + ), + None => v.push(query_block.to_string()), + }; + } + v + }; + + // duckdb::Connection is not Send so we do it in a single blocking task + let (result, column_order) = task::spawn_blocking(move || { + let conn = duckdb::Connection::open_in_memory() + .map_err(|e| Error::ConnectingToDatabase(e.to_string()))?; + + for (_, DuckdbConnectionSettingsResponse { connection_settings_str, .. }) in + used_storages.into_iter() + { + conn.execute_batch(&connection_settings_str) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + } + + let mut result: Option> = None; + let mut column_order = None; + for (query_block_index, query_block) in query_block_list.iter().enumerate() { + result = Some( + do_duckdb_inner( + &conn, + query_block.as_str(), + &job_args, + query_block_index != query_block_list.len() - 1, + &mut column_order, + ) + .map_err(|e| Error::ExecutionErr(e.to_string()))?, + ); + } + let result = result.unwrap_or_else(|| to_raw_value(&json!([]))); + Ok::<_, Error>((result, column_order)) + }) + .await + .map_err(to_anyhow)??; + + *column_order_ref = column_order; + + // BigQuery cleanup + let bq_credentials_path = make_bq_credentials_path(&job.id); + env::remove_var("GOOGLE_APPLICATION_CREDENTIALS"); + if matches!(tokio::fs::try_exists(&bq_credentials_path).await, Ok(true)) { + remove_file(&bq_credentials_path).await.map_err(to_anyhow)?; + } + Ok(result) + }; + + let result = run_future_with_polling_update_job_poller( + job.id, + job.timeout, + conn, + mem_peak, + canceled_by, + result_f, + worker_name, + &job.workspace_id, + &mut Some(occupancy_metrics), + Box::pin(futures::stream::once(async { 0 })), + ) + .await?; + + Ok(result) +} + +fn row_to_value(row: &Row<'_>, column_names: &[String]) -> Result> { + let mut obj = serde_json::Map::new(); + for (i, key) in column_names.iter().enumerate() { + let value: duckdb::types::Value = + row.get(i).map_err(|e| Error::ExecutionErr(e.to_string()))?; + let json_value = match value { + duckdb::types::Value::Null => serde_json::Value::Null, + duckdb::types::Value::Boolean(b) => serde_json::Value::Bool(b), + duckdb::types::Value::TinyInt(i) => serde_json::Value::Number(i.into()), + duckdb::types::Value::SmallInt(i) => serde_json::Value::Number(i.into()), + duckdb::types::Value::Int(i) => serde_json::Value::Number(i.into()), + duckdb::types::Value::BigInt(i) => serde_json::Value::Number(i.into()), + duckdb::types::Value::HugeInt(i) => serde_json::Value::String(i.to_string()), + duckdb::types::Value::UTinyInt(u) => serde_json::Value::Number(u.into()), + duckdb::types::Value::USmallInt(u) => serde_json::Value::Number(u.into()), + duckdb::types::Value::UInt(u) => serde_json::Value::Number(u.into()), + duckdb::types::Value::UBigInt(u) => serde_json::Value::Number(u.into()), + duckdb::types::Value::Float(f) => serde_json::Value::Number( + serde_json::Number::from_f64(f as f64) + .ok_or_else(|| Error::ExecutionErr("Could not convert to f64".to_string()))?, + ), + duckdb::types::Value::Double(f) => serde_json::Value::Number( + serde_json::Number::from_f64(f) + .ok_or_else(|| Error::ExecutionErr("Could not convert to f64".to_string()))?, + ), + duckdb::types::Value::Decimal(d) => serde_json::Value::String(d.to_string()), + duckdb::types::Value::Timestamp(_, ts) => serde_json::Value::String(ts.to_string()), + duckdb::types::Value::Text(s) => serde_json::Value::String(s), + duckdb::types::Value::Blob(b) => serde_json::Value::Array( + b.into_iter() + .map(|byte| serde_json::Value::Number(byte.into())) + .collect(), + ), + duckdb::types::Value::Date32(d) => serde_json::Value::Number(d.into()), + duckdb::types::Value::Time64(_, t) => serde_json::Value::String(t.to_string()), + duckdb::types::Value::Interval { months, days, nanos } => serde_json::json!({ + "months": months, + "days": days, + "nanos": nanos + }), + duckdb::types::Value::List(values) => serde_json::Value::Array( + values + .into_iter() + .map(|v| serde_json::Value::String(format!("{:?}", v))) + .collect(), + ), + duckdb::types::Value::Enum(e) => serde_json::Value::String(e), + duckdb::types::Value::Struct(fields) => serde_json::Value::Object( + fields + .iter() + .map(|(k, v)| (k.clone(), serde_json::Value::String(format!("{:?}", v)))) + .collect(), + ), + duckdb::types::Value::Array(values) => serde_json::Value::Array( + values + .into_iter() + .map(|v| serde_json::Value::String(format!("{:?}", v))) + .collect(), + ), + duckdb::types::Value::Map(map) => serde_json::Value::Object( + map.iter() + .map(|(k, v)| { + ( + format!("{:?}", k), + serde_json::Value::String(format!("{:?}", v)), + ) + }) + .collect(), + ), + duckdb::types::Value::Union(value) => { + serde_json::Value::String(format!("{:?}", *value)) + } + }; + obj.insert(key.clone(), json_value); + } + serde_json::value::to_raw_value(&obj).map_err(|e| e.into()) +} + +fn json_value_to_duckdb_value( + json_value: &serde_json::Value, + arg_type: &str, + client: &AuthedClient, +) -> Result { + let arg_type = arg_type.to_lowercase(); + let duckdb_value = match json_value { + serde_json::Value::Null => duckdb::types::Value::Null, + serde_json::Value::Bool(b) => duckdb::types::Value::Boolean(*b), + + serde_json::Value::String(s) + if matches!( + arg_type.as_str(), + "timestamp" | "timestamptz" | "timestamp with time zone" | "datetime" + ) => + { + string_to_duckdb_timestamp(&s)? + } + serde_json::Value::String(s) if arg_type.as_str() == "date" => string_to_duckdb_date(&s)?, + serde_json::Value::String(s) if arg_type.as_str() == "time" => string_to_duckdb_time(&s)?, + serde_json::Value::String(s) => duckdb::types::Value::Text(s.clone()), + + serde_json::Value::Number(n) if n.is_i64() => { + let v = n.as_i64().unwrap(); + match arg_type.as_str() { + "tinyint" | "int1" => duckdb::types::Value::TinyInt(v as i8), + "smallint" | "int2" | "short" => duckdb::types::Value::SmallInt(v as i16), + "integer" | "int4" | "int" | "signed" => duckdb::types::Value::Int(v as i32), + "bigint" | "int8" | "long" => duckdb::types::Value::BigInt(v), + "hugeint" => duckdb::types::Value::HugeInt(v as i128), + "float" | "float4" | "real" => duckdb::types::Value::Float(v as f32), + "double" | "float8" => duckdb::types::Value::Double(v as f64), + _ => duckdb::types::Value::BigInt(v), // default fallback + } + } + + serde_json::Value::Number(n) if n.is_u64() => { + let v = n.as_u64().unwrap(); + match arg_type.as_str() { + "utinyint" => duckdb::types::Value::UTinyInt(v as u8), + "usmallint" => duckdb::types::Value::USmallInt(v as u16), + "uinteger" => duckdb::types::Value::UInt(v as u32), + "ubigint" | "uhugeint" => duckdb::types::Value::UBigInt(v), + _ => duckdb::types::Value::UBigInt(v), // default fallback + } + } + + serde_json::Value::Number(n) if n.is_f64() => { + let v = n.as_f64().unwrap(); + match arg_type.as_str() { + "float" | "float4" | "real" => duckdb::types::Value::Float(v as f32), + "double" | "float8" => duckdb::types::Value::Double(v), + "decimal" | "numeric" => { + duckdb::types::Value::Decimal(Decimal::from_f64(v).ok_or_else(|| { + Error::ExecutionErr("Could not convert f64 to Decimal".to_string()) + })?) + } + _ => duckdb::types::Value::Double(v), // default fallback + } + } + + serde_json::Value::Array(arr) => duckdb::types::Value::Array( + arr.iter() + .map(|val| json_value_to_duckdb_value(val, arg_type.as_str(), client)) + .collect::>>()?, + ), + serde_json::Value::Object(map) => duckdb::types::Value::Struct( + map.iter() + .map(|(k, v)| { + Ok::<_, Error>(( + k.clone(), + json_value_to_duckdb_value(v, arg_type.as_str(), client)?, + )) + }) + .collect::>>()? + .into(), + ), + + value @ _ => { + return Err(Error::ExecutionErr(format!( + "Unsupported type in query: {:?} and signature {arg_type:?}", + value + ))) + } + }; + Ok(duckdb_value) +} + +fn string_to_duckdb_timestamp(s: &str) -> Result { + let ts = chrono::DateTime::parse_from_rfc3339(s) + .map_err(|e: chrono::ParseError| Error::ExecutionErr(e.to_string()))?; + Ok(duckdb::types::Value::Timestamp( + TimeUnit::Millisecond, + ts.timestamp_millis(), + )) +} + +fn string_to_duckdb_date(s: &str) -> Result { + use chrono::Datelike; + let date = chrono::NaiveDate::parse_from_str(s, "%Y-%m-%d").unwrap(); + Ok(duckdb::types::Value::Date32(date.num_days_from_ce())) +} + +fn string_to_duckdb_time(s: &str) -> Result { + use chrono::Timelike; + let time = chrono::NaiveTime::parse_from_str(s, "%H:%M:%S").unwrap(); + Ok(duckdb::types::Value::Time64( + TimeUnit::Microsecond, + time.num_seconds_from_midnight() as i64, + )) +} + +struct ParsedAttachDbResource<'a> { + resource_path: &'a str, + name: &'a str, + db_type: &'a str, + extra_args: Option<&'a str>, +} +fn parse_attach_db_resource<'a>(query: &'a str) -> Option> { + lazy_static::lazy_static! { + static ref RE: regex::Regex = regex::Regex::new(r"ATTACH '\$res:([^']+)' AS (\S+) \(TYPE (\w+)(.*)\)").unwrap(); + } + + for cap in RE.captures_iter(query) { + if let (Some(resource_path), Some(name), Some(db_type)) = + (cap.get(1), cap.get(2), cap.get(3)) + { + let extra_args = cap.get(4).map(|m| query[m.start()..m.end()].trim()); + return Some(ParsedAttachDbResource { + resource_path: query[resource_path.start()..resource_path.end()].trim(), + name: query[name.start()..name.end()].trim(), + db_type: query[db_type.start()..db_type.end()].trim(), + extra_args, + }); + } + } + None +} + +async fn transform_attach_db_resource_query( + parsed: &ParsedAttachDbResource<'_>, + job_id: &Uuid, + client: &AuthedClient, +) -> Result> { + match parsed.db_type.to_lowercase().as_str() { + "postgres" => { + let resource: PgDatabase = client + .get_resource_value_interpolated(parsed.resource_path, Some(job_id.to_string())) + .await?; + + let attach_str = format!( + "ATTACH 'dbname={} {} host={} {} {}' AS {} (TYPE postgres{});", + resource.dbname, + resource + .user + .map(|u| format!("user={}", u)) + .unwrap_or_default(), + resource.host, + resource + .password + .map(|p| format!("password={}", p)) + .unwrap_or_default(), + resource + .port + .map(|p| format!("port={}", p)) + .unwrap_or_default(), + parsed.name, + parsed.extra_args.unwrap_or("") + ); + + Ok(vec![ + "INSTALL postgres;".to_string(), + "LOAD postgres;".to_string(), + attach_str, + ]) + } + "mysql" => { + #[cfg(not(feature = "mysql"))] + return Err(Error::ExecutionErr( + "MySQL feature is not enabled".to_string(), + )); + + #[cfg(feature = "mysql")] + { + let resource: MysqlDatabase = client + .get_resource_value_interpolated(parsed.resource_path, Some(job_id.to_string())) + .await?; + + let attach_str = format!( + "ATTACH 'database={} host={} ssl_mode={} {} {} {}' AS {} (TYPE mysql{});", + resource.database, + resource.host, + resource + .ssl + .map(|ssl| if ssl { "required" } else { "disabled" }) + .unwrap_or("preferred"), + resource + .password + .map(|p| format!("password={}", p)) + .unwrap_or_default(), + resource + .port + .map(|p| format!("port={}", p)) + .unwrap_or_default(), + resource + .user + .map(|u| format!("user={}", u)) + .unwrap_or_default(), + parsed.name, + parsed.extra_args.unwrap_or("") + ); + + Ok(vec![ + "INSTALL mysql;".to_string(), + "LOAD mysql;".to_string(), + attach_str, + ]) + } + } + "bigquery" => { + let resource: Value = client + .get_resource_value_interpolated(parsed.resource_path, Some(job_id.to_string())) + .await?; + // duckdb's bigquery extension requires a json file as credentials + let bq_credentials_path = make_bq_credentials_path(job_id); + env::set_var("GOOGLE_APPLICATION_CREDENTIALS", &bq_credentials_path); + tokio::fs::write(&bq_credentials_path, resource.to_string()) + .await + .map_err(|e| { + Error::ExecutionErr(format!( + "Failed to write BigQuery credentials to {}: {}", + &bq_credentials_path, e + )) + })?; + let project_id: String = serde_json::from_value( + resource + .get("project_id") + .ok_or_else(|| { + Error::ExecutionErr("BigQuery resource must contain project_id".to_string()) + })? + .to_owned(), + ) + .map_err(|_e| Error::ExecutionErr("failed project_id deserialize".to_string()))?; + let attach_str = format!( + "ATTACH 'project={}' as {} (TYPE bigquery{});", + project_id, + parsed.name, + parsed.extra_args.unwrap_or("") + ) + .to_string(); + Ok(vec![ + "INSTALL bigquery FROM community;".to_string(), + "LOAD bigquery;".to_string(), + attach_str, + ]) + } + _ => Err(Error::ExecutionErr(format!( + "Unsupported db type in DuckDB ATTACH: {}", + parsed.db_type + ))), + } +} + +// Returns the transformed query and the set of storages used +async fn transform_s3_uris( + query: &str, + client: &AuthedClient, +) -> Result<( + Option, + HashMap, DuckdbConnectionSettingsResponse>, +)> { + let mut transformed_query = None; + lazy_static::lazy_static! { + static ref RE: regex::Regex = regex::Regex::new(r"'s3://([^'/]*)/([^']+)'").unwrap(); + } + let mut used_storages = HashMap::new(); + for cap in RE.captures_iter(query) { + if let (storage, Some(s3_path)) = (cap.get(1), cap.get(2)) { + let s3_path = s3_path.as_str(); + let storage = match storage.map(|m| m.as_str()) { + Some("") | None => None, + Some(s) => Some(s.to_string()), + }; + let original_str_lit = + format!("'s3://{}/{}'", storage.as_deref().unwrap_or(""), s3_path); + let duckdb_conn_settings = client + .get_duckdb_connection_settings(&DuckdbConnectionSettingsQueryV2 { + s3_resource_path: None, + storage: storage.clone(), + }) + .await?; + let url = match &duckdb_conn_settings { + DuckdbConnectionSettingsResponse { s3_bucket: Some(bucket), .. } => { + format!("'s3://{bucket}/{s3_path}'") + } + DuckdbConnectionSettingsResponse { azure_container_path: Some(base), .. } => { + format!("'{base}/{s3_path}'") + } + _ => { + return Err(Error::ExecutionErr( + "DuckDB connection settings response must have either s3_bucket or azure_container_path".to_string(), + ))?; + } + }; + transformed_query = Some( + transformed_query + .unwrap_or(query.to_string()) + .replace(&original_str_lit, &url), + ); + used_storages.insert(storage, duckdb_conn_settings); + } + } + Ok((transformed_query, used_storages)) +} + +// BigQuery extension requires a json file as credentials +// The file path is set as an env var by do_duckdb +// It is created by transform_attach_db_resource_query (when bigquery is detected) +// and deleted by do_duckdb after the query is executed +fn make_bq_credentials_path(job_id: &Uuid) -> String { + format!("/tmp/service-account-credentials-{}.json", job_id) +} + +// duckdb-rs does not support named parameters, +// and it raises an error when passing unused arguments. We cannot prepare batch statements +// but only single SQL statements so it doesn't work when all arguments are not used by +// every single statement. +fn interpolate_named_args<'a>( + query: &str, + args: &'a HashMap, +) -> (String, Vec<&'a duckdb::types::Value>) { + let mut query = query.to_string(); + + let mut values = vec![]; + for (arg_name, arg_value) in args { + let pat = format!("${}", arg_name); + if !query.contains(&pat) { + continue; + } + values.push(arg_value); + query = query.replace(&pat, &format!("${}", values.len())); + } + (query, values) +} + +fn trunc_sig(query: &str) -> &str { + let idx = query.rfind("-- $").unwrap_or(query.len()); + // find next \n starting from idx and return everything after it + let idx = query[idx..].find('\n').map(|i| i + idx).unwrap_or(0); + &query[idx..] +} diff --git a/backend/windmill-worker/src/lib.rs b/backend/windmill-worker/src/lib.rs index 4ea56c090e..fa6eb10960 100644 --- a/backend/windmill-worker/src/lib.rs +++ b/backend/windmill-worker/src/lib.rs @@ -20,6 +20,8 @@ mod csharp_executor; #[cfg(feature = "enterprise")] mod dedicated_worker; mod deno_executor; +#[cfg(feature = "duckdb")] +mod duckdb_executor; mod global_cache; mod go_executor; mod graphql_executor; diff --git a/backend/windmill-worker/src/mysql_executor.rs b/backend/windmill-worker/src/mysql_executor.rs index ffd84db175..04403e4e08 100644 --- a/backend/windmill-worker/src/mysql_executor.rs +++ b/backend/windmill-worker/src/mysql_executor.rs @@ -32,13 +32,13 @@ use crate::{ }; #[derive(Deserialize)] -struct MysqlDatabase { - host: String, - user: Option, - password: Option, - port: Option, - database: String, - ssl: Option, +pub struct MysqlDatabase { + pub host: String, + pub user: Option, + pub password: Option, + pub port: Option, + pub database: String, + pub ssl: Option, } fn do_mysql_inner<'a>( diff --git a/backend/windmill-worker/src/pg_executor.rs b/backend/windmill-worker/src/pg_executor.rs index 67c2d945aa..2c7fe123dc 100644 --- a/backend/windmill-worker/src/pg_executor.rs +++ b/backend/windmill-worker/src/pg_executor.rs @@ -47,14 +47,14 @@ use lazy_static::lazy_static; use urlencoding::encode; use windmill_common::client::AuthedClient; #[derive(Deserialize)] -struct PgDatabase { - host: String, - user: Option, - password: Option, - port: Option, - sslmode: Option, - dbname: String, - root_certificate_pem: Option, +pub struct PgDatabase { + pub host: String, + pub user: Option, + pub password: Option, + pub port: Option, + pub sslmode: Option, + pub dbname: String, + pub root_certificate_pem: Option, } lazy_static! { diff --git a/backend/windmill-worker/src/rust_executor.rs b/backend/windmill-worker/src/rust_executor.rs index 1a6a93ecca..0255783f6f 100644 --- a/backend/windmill-worker/src/rust_executor.rs +++ b/backend/windmill-worker/src/rust_executor.rs @@ -4,7 +4,11 @@ use uuid::Uuid; use windmill_parser_rust::parse_rust_deps_into_manifest; use itertools::Itertools; -use tokio::{fs::File, io::AsyncReadExt, process::Command}; +use tokio::{ + fs::{create_dir_all, File}, + io::AsyncReadExt, + process::Command, +}; use windmill_common::{ error::{self, Error}, utils::calculate_hash, @@ -19,8 +23,8 @@ use crate::{ read_result, start_child_process, OccupancyMetrics, }, handle_child::handle_child, - DISABLE_NSJAIL, DISABLE_NUSER, HOME_ENV, NSJAIL_PATH, PATH_ENV, PROXY_ENVS, - RUST_CACHE_DIR, TZ_ENV, + DISABLE_NSJAIL, DISABLE_NUSER, HOME_ENV, NSJAIL_PATH, PATH_ENV, PROXY_ENVS, RUST_CACHE_DIR, + TZ_ENV, }; use windmill_common::client::AuthedClient; @@ -28,12 +32,18 @@ use windmill_common::client::AuthedClient; use crate::SYSTEM_ROOT; const NSJAIL_CONFIG_RUN_RUST_CONTENT: &str = include_str!("../nsjail/run.rust.config.proto"); +const NSJAIL_CONFIG_COMPILE_RUST_CONTENT: &str = + include_str!("../nsjail/download.rust.config.proto"); lazy_static::lazy_static! { static ref HOME_DIR: String = std::env::var("HOME").expect("Could not find the HOME environment variable"); static ref CARGO_HOME: String = std::env::var("CARGO_HOME").unwrap_or_else(|_| { CARGO_HOME_DEFAULT.clone() }); static ref RUSTUP_HOME: String = std::env::var("RUSTUP_HOME").unwrap_or_else(|_| { RUSTUP_HOME_DEFAULT.clone() }); static ref CARGO_PATH: String = std::env::var("CARGO_PATH").unwrap_or_else(|_| format!("{}/bin/cargo", CARGO_HOME.as_str())); + // static ref CARGO_SWEEP_PATH: String = std::env::var("CARGO_SWEEP_PATH").unwrap_or_else(|_| format!("{}/bin/cargo-sweep", CARGO_HOME.as_str())); + static ref SWEEP_MAXSIZE: String = std::env::var("CARGO_SWEEP_MAXSIZE").unwrap_or("25GB".to_owned()); + static ref NO_SHARED_BUILD_DIR: bool = std::env::var("RUST_NO_SHARED_BUILD_DIR").ok().map(|flag| flag == "true").unwrap_or(false); + } #[cfg(windows)] @@ -42,7 +52,20 @@ lazy_static::lazy_static! { static ref RUSTUP_HOME_DEFAULT: String = format!("{}\\.rustup", *HOME_DIR); } -#[cfg(unix)] +#[cfg(debug_assertions)] +const DEV_CONF_NSJAIL: &'static str = r#" +# Mount nix store for nixos to work properly +mount { + src: "/nix/store" + dst: "/nix/store" + is_bind: true + mandatory: false +} +"#; + +#[cfg(not(debug_assertions))] +const DEV_CONF_NSJAIL: &'static str = ""; + lazy_static::lazy_static! { static ref CARGO_HOME_DEFAULT: String = format!("{}/.cargo", *HOME_DIR); static ref RUSTUP_HOME_DEFAULT: String = format!("{}/.rustup", *HOME_DIR); @@ -176,54 +199,211 @@ pub async fn generate_cargo_lockfile( Ok(req_content) } +async fn get_build_dir( + job: &MiniPulledJob, + job_dir: &str, + conn: &Connection, + worker_name: &str, + is_preview: bool, +) -> anyhow::Result { + let (bd, run_sweep) = job + .runnable_path + .as_ref() + .and_then(|p| { + if !is_preview || *NO_SHARED_BUILD_DIR { + None + } else { + if *DISABLE_NSJAIL { + // If nsjail is disabled then entire worker has shared build directory + // It drastically improves cache hit-rate. + Some((format!("{RUST_CACHE_DIR}/build/{worker_name}"), true)) + } else { + // If nsjail is enabled, having global shared directory is vulnerability and target for an attack + // Instead we either: + // 1. Create different build directory for workspace script and user. Balanced caching while mainining high degree of security. + // 2. If user is not known or something else goes wrong - use random build dir. This is equivalent to no cache at all. + Some(( + format!( + "{RUST_CACHE_DIR}/build/{}@{}@{}", + &job.workspace_id, + p.replace('/', "."), + &job.created_by + ), + true, + )) + } + } + }) + .unwrap_or((format!("{RUST_CACHE_DIR}/build/{}", Uuid::new_v4()), false)); + + { + let (t, r, g) = ( + create_dir_all(format!("{}/target", &bd)).await, + create_dir_all(format!("{}/registry", &bd)).await, + create_dir_all(format!("{}/git", &bd)).await, + ); + + t.and(r) + .and(g) + .map_err(|e| anyhow::anyhow!("Could not create build dir for rust.\ne: {e}"))?; + } + + if run_sweep { + // Also run sweep to make sure target isn't using too much disk + let mut sweep_cmd = Command::new(CARGO_PATH.as_str()); + sweep_cmd + .current_dir(job_dir) + .env_clear() + .env("PATH", PATH_ENV.as_str()) + .env("CARGO_HOME", CARGO_HOME.as_str()) + .env("HOME", HOME_ENV.as_str()) + .env("CARGO_TARGET_DIR", &(bd.clone() + "/target")) + .env("RUSTUP_HOME", RUSTUP_HOME.as_str()) + .args(["sweep", "--maxsize", SWEEP_MAXSIZE.as_str()]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + + #[cfg(windows)] + { + sweep_cmd.env("SystemRoot", SYSTEM_ROOT.as_str()); + sweep_cmd.env( + "TMP", + std::env::var("TMP").unwrap_or_else(|_| "C:\\tmp".to_string()), + ); + sweep_cmd.env("USERPROFILE", crate::USERPROFILE_ENV.as_str()); + } + + let (job_id, conn, w_id, wk_name) = ( + job.id.clone(), + conn.clone(), + job.workspace_id.clone(), + worker_name.to_owned(), + ); + + tokio::spawn(async move { + if let Err(e) = match start_child_process(sweep_cmd, CARGO_PATH.as_str()).await { + Ok(sweep_process) => { + handle_child( + &job_id, + &conn, + &mut 0, + &mut None, + sweep_process, + false, + &wk_name, + &w_id, + "cargo sweep", + None, + false, + &mut None, + None, + ) + .await + } + Err(e) => Err(e), + } { + tracing::warn!( + workspace_id = %w_id, + job_id = %job_id, + "Failed to run `cargo sweep`. Rust cache may grow over time, cargo sweep is meant to clean up unused cache.\ne: {e}\n" + ); + } + }); + } + Ok(bd) +} + pub async fn build_rust_crate( - job_id: &Uuid, + job: &MiniPulledJob, mem_peak: &mut i32, canceled_by: &mut Option, job_dir: &str, conn: &Connection, worker_name: &str, - w_id: &str, base_internal_url: &str, hash: &str, occupancy_metrics: &mut OccupancyMetrics, + is_preview: bool, ) -> error::Result { let bin_path = format!("{}/{hash}", RUST_CACHE_DIR); - let mut build_rust_cmd = Command::new(CARGO_PATH.as_str()); - build_rust_cmd - .current_dir(job_dir) - .env_clear() - .envs(PROXY_ENVS.clone()) - .env("PATH", PATH_ENV.as_str()) - .env("BASE_INTERNAL_URL", base_internal_url) - .env("HOME", HOME_ENV.as_str()) - .env("CARGO_HOME", CARGO_HOME.as_str()) - .env("RUSTUP_HOME", RUSTUP_HOME.as_str()) - .args(vec!["build", "--release"]) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); + let build_dir = get_build_dir(job, job_dir, conn, worker_name, is_preview).await?; - #[cfg(windows)] - { - build_rust_cmd.env("SystemRoot", SYSTEM_ROOT.as_str()); - build_rust_cmd.env( - "TMP", - std::env::var("TMP").unwrap_or_else(|_| "C:\\tmp".to_string()), - ); - build_rust_cmd.env("USERPROFILE", crate::USERPROFILE_ENV.as_str()); - } + let child = if !*DISABLE_NSJAIL { + let _ = write_file( + job_dir, + "download.config.proto", + &NSJAIL_CONFIG_COMPILE_RUST_CONTENT + .replace("{JOB_DIR}", job_dir) + .replace("{CACHE_DIR}", RUST_CACHE_DIR) + .replace("{CARGO_HOME}", CARGO_HOME.as_str()) + .replace("{DEV}", DEV_CONF_NSJAIL) + .replace("{BUILD}", &build_dir), + )?; + let mut nsjail_cmd = Command::new(NSJAIL_PATH.as_str()); + nsjail_cmd + .current_dir(job_dir) + .env_clear() + .env("PATH", PATH_ENV.as_str()) + .env("TZ", TZ_ENV.as_str()) + .env("BASE_INTERNAL_URL", base_internal_url) + .envs(PROXY_ENVS.clone()) + .env("HOME", HOME_ENV.as_str()) + .env("CARGO_HOME", CARGO_HOME.as_str()) + .env("RUSTUP_HOME", RUSTUP_HOME.as_str()) + .env("CARGO_TARGET_DIR", &(build_dir.clone() + "/target")) + .args(vec![ + "--config", + "download.config.proto", + "--", + CARGO_PATH.as_ref(), + "build", + ]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + if !is_preview { + nsjail_cmd.arg("--release"); + } + start_child_process(nsjail_cmd, NSJAIL_PATH.as_str()).await? + } else { + let mut build_rust_cmd = Command::new(CARGO_PATH.as_str()); + build_rust_cmd + .current_dir(job_dir) + .env_clear() + .envs(PROXY_ENVS.clone()) + .env("PATH", PATH_ENV.as_str()) + .env("BASE_INTERNAL_URL", base_internal_url) + .env("HOME", HOME_ENV.as_str()) + .env("CARGO_HOME", CARGO_HOME.as_str()) + .env("RUSTUP_HOME", RUSTUP_HOME.as_str()) + .env("CARGO_TARGET_DIR", &(build_dir.clone() + "/target")) + .args(vec!["build"]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); - let build_rust_process = start_child_process(build_rust_cmd, CARGO_PATH.as_str()).await?; + if !is_preview { + build_rust_cmd.arg("--release"); + } + #[cfg(windows)] + { + build_rust_cmd.env("SystemRoot", SYSTEM_ROOT.as_str()); + build_rust_cmd.env( + "TMP", + std::env::var("TMP").unwrap_or_else(|_| "C:\\tmp".to_string()), + ); + build_rust_cmd.env("USERPROFILE", crate::USERPROFILE_ENV.as_str()); + } + start_child_process(build_rust_cmd, CARGO_PATH.as_str()).await? + }; handle_child( - job_id, + &job.id, conn, mem_peak, canceled_by, - build_rust_process, + child, false, worker_name, - w_id, + &job.workspace_id, "rust build", None, false, @@ -231,16 +411,19 @@ pub async fn build_rust_crate( None, ) .await?; - append_logs(job_id, w_id, "\n\n", conn).await; + append_logs(&job.id, &job.workspace_id, "\n\n", conn).await; tokio::fs::copy( - &format!("{job_dir}/target/release/main"), + &format!( + "{build_dir}/target/{}/main", + if is_preview { "debug" } else { "release" }, + ), format! {"{job_dir}/main"}, ) .await .map_err(|e| { Error::ExecutionErr(format!( - "could not copy built binary from [...]/target/release/main to {job_dir}/main: {e:?}" + "could not copy built binary from [...]/target/.../main to {job_dir}/main: {e:?}" )) })?; @@ -298,6 +481,9 @@ pub async fn handle_rust_job( let bin_path = format!("{}/{hash}", RUST_CACHE_DIR); let remote_path = format!("{RUST_OBJECT_STORE_PREFIX}{hash}"); + let reserved_variables = + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; + let (cache, cache_logs) = windmill_common::worker::load_cache(&bin_path, &remote_path, false).await; @@ -332,16 +518,16 @@ pub async fn handle_rust_job( create_args_and_out_file(client, job, job_dir, conn).await?; build_rust_crate( - &job.id, + &job, mem_peak, canceled_by, job_dir, conn, worker_name, - &job.workspace_id, base_internal_url, &hash, occupancy_metrics, + requirements_o.is_none(), ) .await? }; @@ -349,9 +535,6 @@ pub async fn handle_rust_job( let logs2 = format!("{cache_logs}\n\n--- RUST CODE EXECUTION ---\n"); append_logs(&job.id, &job.workspace_id, logs2, conn).await; - let reserved_variables = - get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; - let child = if !*DISABLE_NSJAIL { let _ = write_file( job_dir, @@ -361,6 +544,7 @@ pub async fn handle_rust_job( .replace("{CACHE_DIR}", RUST_CACHE_DIR) .replace("{CACHE_HASH}", &hash) .replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string()) + .replace("{DEV}", DEV_CONF_NSJAIL) .replace("{SHARED_MOUNT}", shared_mount), )?; let mut nsjail_cmd = Command::new(NSJAIL_PATH.as_str()); diff --git a/backend/windmill-worker/src/windmill-client.js b/backend/windmill-worker/src/windmill-client.js index 3ae15e7453..1ecf28e664 100644 --- a/backend/windmill-worker/src/windmill-client.js +++ b/backend/windmill-worker/src/windmill-client.js @@ -2998,6 +2998,8 @@ var $RawScript = { "mssql", "graphql", "nativets", + "duckdb", + // for related places search: ADD_NEW_LANG ], }, path: { diff --git a/backend/windmill-worker/src/worker.rs b/backend/windmill-worker/src/worker.rs index 221650389a..e15c24ef70 100644 --- a/backend/windmill-worker/src/worker.rs +++ b/backend/windmill-worker/src/worker.rs @@ -145,6 +145,9 @@ use crate::ansible_executor::handle_ansible_job; #[cfg(feature = "mysql")] use crate::mysql_executor::do_mysql; +#[cfg(feature = "duckdb")] +use crate::duckdb_executor::do_duckdb; + #[cfg(feature = "oracledb")] use crate::oracledb_executor::do_oracledb; @@ -2614,6 +2617,30 @@ async fn handle_code_execution_job( ) .await; } + } else if language == Some(ScriptLang::DuckDb) { + #[allow(unreachable_code)] + #[cfg(not(feature = "duckdb"))] + { + return Err(Error::internal_err( + "Duck DB requires the duckdb feature to be enabled".to_string(), + )); + } + + #[cfg(feature = "duckdb")] + { + return do_duckdb( + job, + &client, + &code, + conn, + mem_peak, + canceled_by, + worker_name, + column_order, + occupancy_metrics, + ) + .await; + } } else if language == Some(ScriptLang::Graphql) { return do_graphql( job, @@ -3021,6 +3048,7 @@ fn parse_sig_of_lang( ScriptLang::Snowflake => Some(windmill_parser_sql::parse_snowflake_sig(code)?), ScriptLang::Graphql => None, ScriptLang::Mssql => Some(windmill_parser_sql::parse_mssql_sig(code)?), + ScriptLang::DuckDb => Some(windmill_parser_sql::parse_duckdb_sig(code)?), ScriptLang::OracleDB => Some(windmill_parser_sql::parse_oracledb_sig(code)?), #[cfg(feature = "php")] ScriptLang::Php => Some(windmill_parser_php::parse_php_signature( diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index a03010948b..cde9bc5320 100644 --- a/benchmarks/lib.ts +++ b/benchmarks/lib.ts @@ -2,7 +2,7 @@ import { sleep } from "https://deno.land/x/sleep@v1.2.1/mod.ts"; import * as windmill from "https://deno.land/x/windmill@v1.174.0/mod.ts"; import * as api from "https://deno.land/x/windmill@v1.174.0/windmill-api/index.ts"; -export const VERSION = "v1.492.1"; +export const VERSION = "v1.494.0"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/bootstrap/script_bootstrap.ts b/cli/bootstrap/script_bootstrap.ts index 2ac67bdb83..e9e8a12db5 100644 --- a/cli/bootstrap/script_bootstrap.ts +++ b/cli/bootstrap/script_bootstrap.ts @@ -76,6 +76,7 @@ func main() (interface{}, error) { bash: `echo "Hello world" `, + duckdb: `SELECT 'Hello world' AS message`, oracledb: `SELECT 'Hello world' AS message`, powershell: `Write-Output "Hello world"`, @@ -126,5 +127,5 @@ public class Main { } } `, -// for related places search: ADD_NEW_LANG + // for related places search: ADD_NEW_LANG }; diff --git a/cli/build.sh b/cli/build.sh index bf00b99a57..e228750b51 100755 --- a/cli/build.sh +++ b/cli/build.sh @@ -1,3 +1,4 @@ #!/bin/bash +# Note for mac OS users: you need to install gnu-sed with `brew install gnu-sed` and use `gsed` instead of `sed`. ./gen_wm_client.sh deno run -A dnt.ts diff --git a/cli/main.ts b/cli/main.ts index e87c8b14a5..c5b67cc26a 100644 --- a/cli/main.ts +++ b/cli/main.ts @@ -63,7 +63,7 @@ export { // } // }); -export const VERSION = "1.492.1"; +export const VERSION = "1.494.0"; const command = new Command() .name("wmill") diff --git a/cli/metadata.ts b/cli/metadata.ts index 3a83143182..ee39d0b9da 100644 --- a/cli/metadata.ts +++ b/cli/metadata.ts @@ -528,6 +528,9 @@ export async function inferSchema( { name: "database", typ: { resource: "postgresql" } }, ...inferedSchema.args, ]; + } else if (language === "duckdb") { + const { parse_sql } = await import("./wasm/regex/windmill_parser_wasm.js"); + inferedSchema = JSON.parse(parse_sql(content)); } else if (language === "graphql") { const { parse_graphql } = await import( "./wasm/regex/windmill_parser_wasm.js" diff --git a/cli/script.ts b/cli/script.ts index 3896d19c5c..e12c15d9ba 100644 --- a/cli/script.ts +++ b/cli/script.ts @@ -547,6 +547,8 @@ export function filePathExtensionFromContentType( return ".my.sql"; } else if (language === "bigquery") { return ".bq.sql"; + } else if (language === "duckdb") { + return ".duckdb.sql"; } else if (language === "oracledb") { return ".odb.sql"; } else if (language === "snowflake") { @@ -573,7 +575,7 @@ export function filePathExtensionFromContentType( return ".nu"; } else if (language === "java") { return ".java"; - // for related places search: ADD_NEW_LANG + // for related places search: ADD_NEW_LANG } else { throw new Error("Invalid language: " + language); } @@ -593,6 +595,7 @@ export const exts = [ ".odb.sql", ".sf.sql", ".ms.sql", + ".duckdb.sql", ".sql", ".gql", ".ps1", @@ -601,9 +604,8 @@ export const exts = [ ".cs", ".nu", ".playbook.yml", - ".java" - // for related places search: ADD_NEW_LANG - + ".java", + // for related places search: ADD_NEW_LANG ]; export function removeExtensionToPath(path: string): string { diff --git a/cli/script_common.ts b/cli/script_common.ts index a41d7dee8c..39906e7bb9 100644 --- a/cli/script_common.ts +++ b/cli/script_common.ts @@ -9,6 +9,7 @@ export type ScriptLanguage = | "postgresql" | "mysql" | "bigquery" + | "duckdb" | "oracledb" | "snowflake" | "mssql" @@ -19,7 +20,7 @@ export type ScriptLanguage = | "nu" | "ansible" | "java"; - // for related places search: ADD_NEW_LANG +// for related places search: ADD_NEW_LANG export function inferContentTypeFromFilePath( contentPath: string, @@ -43,6 +44,8 @@ export function inferContentTypeFromFilePath( return "bigquery"; } else if (contentPath.endsWith(".odb.sql")) { return "oracledb"; + } else if (contentPath.endsWith(".duckdb.sql")) { + return "duckdb"; } else if (contentPath.endsWith(".sf.sql")) { return "snowflake"; } else if (contentPath.endsWith(".ms.sql")) { @@ -67,7 +70,7 @@ export function inferContentTypeFromFilePath( return "nu"; } else if (contentPath.endsWith(".java")) { return "java"; - // for related places search: ADD_NEW_LANG + // for related places search: ADD_NEW_LANG } else { throw new Error( "Invalid language: " + contentPath.substring(contentPath.lastIndexOf(".")) diff --git a/cli/sync.ts b/cli/sync.ts index 867b8c4d17..456afcadf9 100644 --- a/cli/sync.ts +++ b/cli/sync.ts @@ -344,6 +344,7 @@ export function newPathAssigner(defaultTs: "bun" | "deno"): PathAssigner { else if (language == "nu") ext = "nu"; else if (language == "ansible") ext = "playbook.yml"; else if (language == "java") ext = "java"; + else if (language == "duckdb") ext = "duckdb.sql"; // for related places search: ADD_NEW_LANG else ext = "no_ext"; diff --git a/cli/wasm/regex/windmill_parser_wasm.js b/cli/wasm/regex/windmill_parser_wasm.js index 5418fad879..7867ab4a35 100644 --- a/cli/wasm/regex/windmill_parser_wasm.js +++ b/cli/wasm/regex/windmill_parser_wasm.js @@ -1,5 +1,6 @@ + let WASM_VECTOR_LEN = 0; let cachedUint8ArrayMemory0 = null; diff --git a/docker/DockerfileFull b/docker/DockerfileFull index 78eec753d1..ddc1cdb3af 100644 --- a/docker/DockerfileFull +++ b/docker/DockerfileFull @@ -3,6 +3,7 @@ FROM ghcr.io/windmill-labs/windmill:dev # Rust COPY --from=rust:1.86.0 /usr/local/cargo /usr/local/cargo COPY --from=rust:1.86.0 /usr/local/rustup /usr/local/rustup +RUN /usr/local/cargo/bin/cargo install cargo-sweep --version ^0.7 # Ansible RUN uv tool install ansible && [ -d "$(uv tool dir)/ansible/bin/" ] && find "$(uv tool dir)/ansible/bin/" -mindepth 1 -maxdepth 1 -type f -executable -regextype posix-extended -regex '^((.+/)?)[^.]+' -print0 | xargs -0 ln -s -t "$UV_TOOL_BIN_DIR/" || true diff --git a/docker/DockerfileFullEe b/docker/DockerfileFullEe index 138038559c..7ed7108de2 100644 --- a/docker/DockerfileFullEe +++ b/docker/DockerfileFullEe @@ -22,6 +22,7 @@ FROM ghcr.io/windmill-labs/windmill-ee:dev # Rust COPY --from=rust:1.86.0 /usr/local/cargo /usr/local/cargo COPY --from=rust:1.86.0 /usr/local/rustup /usr/local/rustup +RUN /usr/local/cargo/bin/cargo install cargo-sweep --version ^0.7 # Ansible RUN uv tool install ansible && [ -d "$(uv tool dir)/ansible/bin/" ] && find "$(uv tool dir)/ansible/bin/" -mindepth 1 -maxdepth 1 -type f -executable -regextype posix-extended -regex '^((.+/)?)[^.]+' -print0 | xargs -0 ln -s -t "$UV_TOOL_BIN_DIR/" || true diff --git a/docker/DockerfileNsjail b/docker/DockerfileNsjail index e51e73a3ea..cd17557256 100644 --- a/docker/DockerfileNsjail +++ b/docker/DockerfileNsjail @@ -45,6 +45,7 @@ RUN apt-get update && apt-get install -y libprotobuf-dev libnl-route-3-dev # Rust COPY --from=rust:1.80.1 /usr/local/cargo /usr/local/cargo COPY --from=rust:1.80.1 /usr/local/rustup /usr/local/rustup +RUN /usr/local/cargo/bin/cargo install cargo-sweep --version ^0.7 # Ansible RUN uv tool install ansible && [ -d "$(uv tool dir)/ansible/bin/" ] && find "$(uv tool dir)/ansible/bin/" -mindepth 1 -maxdepth 1 -type f -executable -regextype posix-extended -regex '^((.+/)?)[^.]+' -print0 | xargs -0 ln -s -t "$UV_TOOL_BIN_DIR/" || true diff --git a/flake.nix b/flake.nix index f9df73f465..10a1e26c14 100644 --- a/flake.nix +++ b/flake.nix @@ -81,11 +81,13 @@ buildInputs = buildInputs ++ (with pkgs; [ # Essentials rust + cargo-sweep git xcaddy sqlx-cli sccache nsjail + openapi-generator-cli # Python flock @@ -186,6 +188,7 @@ # for related places search: ADD_NEW_LANG FLOCK_PATH = "${pkgs.flock}/bin/flock"; CARGO_PATH = "${rust}/bin/cargo"; + CARGO_SWEEP_PATH = "${pkgs.cargo-sweep}/bin/cargo-sweep"; DOTNET_PATH = "${pkgs.dotnet-sdk_9}/bin/dotnet"; DOTNET_ROOT = "${pkgs.dotnet-sdk_9}/share/dotnet"; ORACLE_LIB_DIR = "${pkgs.oracle-instantclient.lib}/lib"; diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md deleted file mode 100644 index 63f35ab820..0000000000 --- a/frontend/CLAUDE.md +++ /dev/null @@ -1,241 +0,0 @@ -# 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. - -## Reactivity with Runes - -Svelte 5 introduces Runes for more explicit and flexible reactivity. - -1. **Embrace Runes for State Management**: - - - Use `$state` for reactive local component state. - - ```svelte - - - - ``` - - - Use `$derived` for computed values based on other reactive state. - - ```svelte - - -

{count} * 2 = {doubled}

- ``` - - - Use `$effect` for side effects that need to run when reactive values change (e.g., logging, manual DOM manipulation, data fetching). Remember `$effect` does not run on the server. - - ```svelte - - ``` - -2. **Props with `$props`**: - - - Declare component props using `$props()`. This offers better clarity and flexibility compared to `export let`. - - ```svelte - - -

Name: {name}

-

Age: {age}

- ``` - - - For bindable props, use `$bindable`. - - ```svelte - - - - ``` - -## Event Handling - -- **Use direct event attributes**: Svelte 5 moves away from `on:` directives for DOM events. - - **Do**: `` - - **Don't**: `` -- **For component events, prefer callback props**: Instead of `createEventDispatcher`, pass functions as props. - - ```svelte - - - -

Message from child: {message}

- - - - - ``` - -## Snippets for Content Projection - -- **Use `{#snippet ...}` and `{@render ...}` instead of slots**: Snippets are more powerful and flexible. - - ```svelte - - - - - {#snippet title()} - My Awesome Title - {/snippet} - {#snippet content()} -

Some interesting content here.

- {/snippet} -
- - - - -
-
{@render title()}
-
{@render content()}
-
- ``` - -- Default content is passed via the `children` prop (which is a snippet). - ```svelte - - -
- {@render children?.()} -
- ``` - -## Component Design - -1. **Create Small, Reusable Components**: Break down complex UIs into smaller, focused components. Each component should have a single responsibility. This also aids performance by limiting the scope of reactivity updates. -2. **Descriptive Naming**: Use clear and descriptive names for variables, functions, and components. -3. **Minimize Logic in Components**: Move complex business logic to utility functions or services. Keep components focused on presentation and interaction. - -## State Management (Stores) - -1. **Segment Stores**: Avoid a single global store. Create multiple stores, each responsible for a specific piece of global state (e.g., `userStore.js`, `themeStore.js`). This can help limit reactivity updates to only the parts of the UI that depend on specific state segments. -2. **Use Custom Stores for Complex Logic**: For stores with related methods, create custom stores. - - ```javascript - // counterStore.js - import { writable } from 'svelte/store' - - function createCounter() { - const { subscribe, set, update } = writable(0) - - return { - subscribe, - increment: () => update((n) => n + 1), - decrement: () => update((n) => n - 1), - reset: () => set(0) - } - } - export const counter = createCounter() - ``` - -3. **Use Context API for Localized State**: For state shared within a component subtree, consider Svelte's context API (`setContext`, `getContext`) instead of global stores when the state doesn't need to be truly global. - -## Performance Optimizations (Svelte 5) - -When generating Svelte 5 code, prioritize frontend performance by applying the following principles: - -### General Svelte 5 Principles - -- **Leverage the Compiler:** Trust Svelte's compiler to generate optimized JavaScript. Avoid manual DOM manipulation (`document.querySelector`, etc.) unless absolutely necessary for integrating third-party libraries that lack Svelte adapters. -- **Keep Components Small and Focused:** Reinforcing from Component Design, smaller components lead to less complex reactivity graphs and more targeted, efficient updates. - -### Reactivity & State Management - -- **Optimize Computations with `$derived`:** Always use `$derived` for computed values that depend on other state. This ensures the computation only runs when its specific dependencies change, avoiding unnecessary work compared to recomputing derived values in `$effect` or less efficient methods. -- **Minimize `$effect` Usage:** Use `$effect` sparingly and only for true side effects that interact with the outside world or non-Svelte state. Avoid putting complex logic or state updates _within_ an `$effect` unless those updates are explicitly intended as a reaction to external changes or non-Svelte state. Excessive or complex effects can impact rendering performance. -- **Structure State for Fine-Grained Updates:** Design your `$state` objects or variables such that updates affect only the necessary parts of the UI. Avoid putting too much unrelated state into a single large object that gets frequently updated, as this can potentially trigger broader updates than necessary. Consider normalizing complex, nested state. - -### List Rendering (`{#each}`) - -- **Mandate `key` Attribute:** Always use a `key` attribute (`{#each items as item (item.id)}`) that refers to a unique, stable identifier for each item in a list. This is critical for allowing Svelte to efficiently update, reorder, add, or remove list items without destroying and re-creating unnecessary DOM elements and component instances. - -### Component Loading & Bundling - -- **Implement Lazy Loading/Code Splitting:** For routes, components, or modules that are not immediately needed on page load, use dynamic imports (`import(...)`) to split the code bundle. SvelteKit handles this automatically for routes, but it can be applied manually to components using helper patterns if needed. -- **Be Mindful of Third-Party Libraries:** When incorporating external libraries, import only the necessary functions or components to minimize the final bundle size. Prefer libraries designed to be tree-shakeable. - -### Rendering & DOM - -- **Use CSS for Animations/Transitions:** Prefer CSS animations or transitions where possible for performance. Svelte's built-in `transition:` directive is also highly optimized and should be used for complex state-driven transitions, but simple cases can often use plain CSS. -- **Optimize Image Loading:** Implement best practices for images: use optimized formats (WebP, AVIF), lazy loading (`loading="lazy"`), and responsive images (``, `srcset`) to avoid loading unnecessarily large images. - -### Server-Side Rendering (SSR) & Hydration - -- **Ensure SSR Compatibility:** Write components that can be rendered on the server for faster initial page loads. Avoid relying on browser-specific APIs (like `window` or `document`) in the main ` - -
- Hello -
- ``` - -5. **Stay Updated**: Keep Svelte and its related packages up to date to benefit from the latest features, performance improvements, and security fixes. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8b9594413e..44afdff817 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.492.1", + "version": "1.494.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.492.1", + "version": "1.494.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -74,7 +74,7 @@ "windmill-parser-wasm-nu": "^1.474.1", "windmill-parser-wasm-php": "^1.429.0", "windmill-parser-wasm-py": "^1.477.1", - "windmill-parser-wasm-regex": "^1.481.0", + "windmill-parser-wasm-regex": "^1.492.1", "windmill-parser-wasm-rust": "^1.429.0", "windmill-parser-wasm-ts": "^1.486.1", "windmill-parser-wasm-yaml": "^1.429.0", @@ -12838,9 +12838,9 @@ "integrity": "sha512-EY3mSMWpqFPzd7fsLg2/hSfQFU8HpW9nplFwm4JHHCDbcTpBzlvzjPJoHAAGO5kMzowAxjqi5ai/mXjeUWuiSg==" }, "node_modules/windmill-parser-wasm-regex": { - "version": "1.481.0", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-regex/-/windmill-parser-wasm-regex-1.481.0.tgz", - "integrity": "sha512-QY9NOaF0M55SBEbbcAkHoXppjdS2gb2NlwqhlZ1ciYWTtIrbZoL5K8xoG4FbB5vWRHxInG1aRdA2tb+JP180yA==" + "version": "1.492.1", + "resolved": "https://registry.npmjs.org/windmill-parser-wasm-regex/-/windmill-parser-wasm-regex-1.492.1.tgz", + "integrity": "sha512-CBdjz3x00z2xA4BRZv8/hsuHcpZgL28UKTjYVSj5O9XMYlY9g0LNsEQ5TTl/oVyFBs62/CPyvWwGvW4oSAObzg==" }, "node_modules/windmill-parser-wasm-rust": { "version": "1.429.0", diff --git a/frontend/package.json b/frontend/package.json index f8cff0de9a..2a4b7a66d9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,11 +1,11 @@ { "name": "windmill-components", - "version": "1.492.1", + "version": "1.494.0", "scripts": { "dev": "vite dev", "build": "vite build", "preview": "vite preview", - "postinstall": "node scripts/untar_ui_builder.js", + "postinstall": "node scripts/untar_ui_builder.js && node scripts/patch_files.js", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --threshold warning", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", @@ -143,7 +143,7 @@ "windmill-parser-wasm-nu": "^1.474.1", "windmill-parser-wasm-php": "^1.429.0", "windmill-parser-wasm-py": "^1.477.1", - "windmill-parser-wasm-regex": "^1.481.0", + "windmill-parser-wasm-regex": "^1.492.1", "windmill-parser-wasm-rust": "^1.429.0", "windmill-parser-wasm-ts": "^1.486.1", "windmill-parser-wasm-yaml": "^1.429.0", diff --git a/frontend/scripts/patch_files.js b/frontend/scripts/patch_files.js new file mode 100644 index 0000000000..291468f913 --- /dev/null +++ b/frontend/scripts/patch_files.js @@ -0,0 +1,57 @@ +// patch-editor-worker.mjs +import { readFile, writeFile } from 'fs/promises' +import path from 'path' +import { fileURLToPath } from 'url' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const filePath = path.join( + __dirname, + '..', + 'node_modules', + '@codingame', + 'monaco-vscode-api', + 'workers', + 'editor.worker.js' +) + +const originalSnippet = `return requestHandler?.[propKey];` + +const patchedCode = ` +import '../vscode/src/vs/editor/common/services/editorWebWorkerMain.js'; +import { start } from '../vscode/src/vs/editor/editor.worker.start.js'; + +function initialize(createFn) { + let requestHandler; + const foreignModule = new Proxy({}, { + get(_target, propKey) { + if (propKey === '$initialize') { + return async (data) => { + if (!requestHandler) { + requestHandler = createFn(context, data); + } + }; + } + const value = requestHandler?.[propKey] + if (typeof value === 'function') { + return value.bind(requestHandler); + } + return value; + } + }); + const context = start(foreignModule); +} + +export { initialize }; +` + +try { + const current = await readFile(filePath, 'utf8') + if (current.includes(originalSnippet)) { + await writeFile(filePath, patchedCode, 'utf8') + console.log('✅ editor.worker.js patched successfully.') + } else { + console.log('ℹ️ Patch already applied or file has changed.') + } +} catch (err) { + console.error('❌ Failed to patch editor.worker.js:', err) +} diff --git a/frontend/src/lib/components/ArgInput.svelte b/frontend/src/lib/components/ArgInput.svelte index 80b0388df1..2f4a9af993 100644 --- a/frontend/src/lib/components/ArgInput.svelte +++ b/frontend/src/lib/components/ArgInput.svelte @@ -573,6 +573,30 @@ }} /> + {:else if itemsType?.type == 'object' && itemsType?.resourceType == 's3object'} +
+ { + value = [ + ...value, + { + s3: evt.detail?.path ?? '', + filename: evt.detail?.filename ?? '' + } + ] + }} + on:deletion={(evt) => { + value = value.filter((v) => v.s3 !== evt.detail?.path) + }} + defaultValue={defaultValue?.map((v) => v.s3)} + initialValue={value} + /> +
{:else}
{#key redraw} diff --git a/frontend/src/lib/components/ArrayTypeNarrowing.svelte b/frontend/src/lib/components/ArrayTypeNarrowing.svelte index 2d37233086..3694b021b7 100644 --- a/frontend/src/lib/components/ArrayTypeNarrowing.svelte +++ b/frontend/src/lib/components/ArrayTypeNarrowing.svelte @@ -21,12 +21,24 @@ } | undefined - let selected: 'string' | 'number' | 'object' | 'bytes' | 'enum' | 'resource' | undefined = + let selected: + | 'string' + | 'number' + | 'object' + | 'bytes' + | 'enum' + | 'resource' + | 's3object' + | undefined = itemsType?.type != 'string' - ? itemsType?.type + ? itemsType?.type == 'object' && itemsType?.resourceType == 's3object' + ? 's3object' + : itemsType?.type : Array.isArray(itemsType?.enum) ? 'enum' - : 'string' + : itemsType?.contentEncoding == 'base64' + ? 'bytes' + : 'string' let schema = { properties: itemsType?.properties || {}, @@ -60,6 +72,8 @@ itemsType = { type: 'string', contentEncoding: 'base64' } } else if (selected == 'resource') { itemsType = { type: 'resource', resourceType: itemsType?.resourceType } + } else if (selected == 's3object') { + itemsType = { type: 'object', resourceType: 's3object' } } else { itemsType = undefined } @@ -69,6 +83,7 @@ {#if originalType != 'string[]'} + diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index 41fa4d99ba..579cac9b28 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -115,7 +115,7 @@ import { workspaceStore } from '$lib/stores' import { type Preview, ResourceService, UserService } from '$lib/gen' import type { Text } from 'yjs' - import { initializeVscode } from '$lib/components/vscode' + import { initializeVscode, keepModelAroundToAvoidDisposalOfWorkers } from '$lib/components/vscode' import { initializeMode } from 'monaco-graphql/esm/initializeMode.js' import type { MonacoGraphQLAPI } from 'monaco-graphql/esm/api.js' @@ -133,6 +133,7 @@ import EditorTheme from './EditorTheme.svelte' import { BIGQUERY_TYPES, + DUCKDB_TYPES, MSSQL_TYPES, MYSQL_TYPES, ORACLEDB_TYPES, @@ -343,7 +344,10 @@ } export function setCode(ncode: string, noHistory: boolean = false): void { - code = ncode + if (code != ncode) { + code = ncode + } + if (noHistory) { editor?.setValue(ncode) } else { @@ -363,6 +367,15 @@ } } + function updateCode() { + const ncode = getCode() + if (code == ncode) { + return + } + code = ncode + dispatch('change', ncode) + } + export function append(code: string): void { if (editor) { const lineCount = editor.getModel()?.getLineCount() || 0 @@ -386,7 +399,7 @@ export async function format() { if (editor) { - code = getCode() + updateCode() if (lang != 'shell' && lang != 'nu') { if ($formatOnSave != false) { if (scriptLang == 'deno' && languageClients.length > 0) { @@ -423,7 +436,7 @@ await editor?.getAction('editor.action.formatDocument')?.run() } } - code = getCode() + updateCode() } if (formatAction) { formatAction() @@ -482,7 +495,9 @@ ? MSSQL_TYPES : scriptLang === 'oracledb' ? ORACLEDB_TYPES - : [] + : scriptLang === 'duckdb' + ? DUCKDB_TYPES + : [] ).map((t) => ({ label: t, kind: languages.CompletionItemKind.Function, @@ -1263,6 +1278,8 @@ folding }) + keepModelAroundToAvoidDisposalOfWorkers() + // updateEditorKeybindingsMode(editor, 'vim', undefined) let ataModel: NodeJS.Timeout | undefined = undefined @@ -1270,9 +1287,7 @@ editor?.onDidChangeModelContent((event) => { timeoutModel && clearTimeout(timeoutModel) timeoutModel = setTimeout(() => { - let ncode = getCode() - code = ncode - dispatch('change', ncode) + updateCode() }, changeTimeout) ataModel && clearTimeout(ataModel) @@ -1291,12 +1306,12 @@ dispatch('focus') editor?.addCommand(KeyMod.CtrlCmd | KeyCode.KeyS, function () { - code = getCode() + updateCode() shouldBindKey && format && format() }) editor?.addCommand(KeyMod.CtrlCmd | KeyCode.Enter, function () { - code = getCode() + updateCode() shouldBindKey && cmdEnterAction && cmdEnterAction() }) @@ -1352,6 +1367,7 @@ try { closeWebsockets() vimDisposable?.dispose() + console.log('disposing editor') model?.dispose() editor && editor.dispose() console.log('disposed editor') diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index 9a66ec9370..3fc5b2dcb4 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -8,7 +8,8 @@ type OpenFlow, type InputTransform, type TriggersCount, - CaptureService + CaptureService, + type HubScriptKind } from '$lib/gen' import { initHistory, redo, undo } from '$lib/history' import { @@ -553,6 +554,7 @@ }) export async function loadTriggers() { + if (initialPath == '') return $triggersCount = await FlowService.getTriggersCountOfFlow({ workspace: $workspaceStore!, path: initialPath diff --git a/frontend/src/lib/components/HighlightCode.svelte b/frontend/src/lib/components/HighlightCode.svelte index ac4357e5ca..bf196c7868 100644 --- a/frontend/src/lib/components/HighlightCode.svelte +++ b/frontend/src/lib/components/HighlightCode.svelte @@ -55,6 +55,8 @@ return sql case 'oracledb': return sql + case 'duckdb': + return sql case 'powershell': return powershell case 'php': @@ -66,10 +68,10 @@ case 'nu': return python case 'ansible': - return yaml; + return yaml case 'java': - return java; - // for related places search: ADD_NEW_LANG + return java + // for related places search: ADD_NEW_LANG default: return typescript } diff --git a/frontend/src/lib/components/SchedulePanel.svelte b/frontend/src/lib/components/SchedulePanel.svelte index b6240534b4..334adcb98c 100644 --- a/frontend/src/lib/components/SchedulePanel.svelte +++ b/frontend/src/lib/components/SchedulePanel.svelte @@ -33,9 +33,7 @@ bind:this={scheduleEditor} hideTarget allowDraft - hasDraft={!!selectedTrigger.draftConfig} - isDraftOnly={selectedTrigger.isDraft} - primary={selectedTrigger.isPrimary} + trigger={selectedTrigger} draftSchema={schema} {customLabel} {...restProps} diff --git a/frontend/src/lib/components/SimpleEditor.svelte b/frontend/src/lib/components/SimpleEditor.svelte index 984b05564a..ac69ded87f 100644 --- a/frontend/src/lib/components/SimpleEditor.svelte +++ b/frontend/src/lib/components/SimpleEditor.svelte @@ -7,6 +7,16 @@ import '@codingame/monaco-vscode-standalone-css-language-features' import '@codingame/monaco-vscode-standalone-typescript-language-features' import '@codingame/monaco-vscode-standalone-html-language-features' + import { + editor as meditor, + KeyCode, + KeyMod, + Uri as mUri, + languages, + type IRange, + type IDisposable + } from 'monaco-editor' + languages.typescript.javascriptDefaults.setCompilerOptions({ target: languages.typescript.ScriptTarget.Latest, allowNonTsExtensions: true, @@ -14,12 +24,15 @@ noLib: true, moduleResolution: languages.typescript.ModuleResolutionKind.NodeJs }) - languages.typescript.javascriptDefaults.setDiagnosticsOptions({ - noSemanticValidation: false, - noSyntaxValidation: false, - noSuggestionDiagnostics: false, - diagnosticCodesToIgnore: [1108] - }) + function setDiagnosticsOptions() { + languages.typescript.javascriptDefaults.setDiagnosticsOptions({ + noSemanticValidation: false, + noSyntaxValidation: false, + noSuggestionDiagnostics: false, + diagnosticCodesToIgnore: [1108] + }) + } + setDiagnosticsOptions() languages.json.jsonDefaults.setDiagnosticsOptions({ validate: true, allowComments: false, @@ -44,15 +57,15 @@ import { BROWSER } from 'esm-env' import { createHash, editorConfig, langToExt, updateOptions } from '$lib/editorUtils' - import { - editor as meditor, - KeyCode, - KeyMod, - Uri as mUri, - languages, - type IRange, - type IDisposable - } from 'monaco-editor' + // import { + // editor as meditor, + // KeyCode, + // KeyMod, + // Uri as mUri, + // languages, + // type IRange, + // type IDisposable + // } from 'monaco-editor' import { allClasses } from './apps/editor/componentsPanel/cssUtils' @@ -60,7 +73,7 @@ import libStdContent from '$lib/es6.d.ts.txt?raw' import domContent from '$lib/dom.d.ts.txt?raw' - import { initializeVscode } from './vscode' + import { initializeVscode, keepModelAroundToAvoidDisposalOfWorkers } from './vscode' import EditorTheme from './EditorTheme.svelte' import { vimMode } from '$lib/stores' import { initVim } from './monaco_keybindings' @@ -144,10 +157,21 @@ } export function setCode(ncode: string): void { - code = ncode + if (ncode != code) { + code = ncode + } editor?.setValue(ncode) } + function updateCode() { + const ncode = getCode() + if (code == ncode) { + return + } + code = ncode + dispatch('change', ncode) + } + function updatePlaceholderVisibility(value: string) { if (!value) { placeholderVisible = true @@ -158,11 +182,11 @@ export function format() { if (editor) { - code = getCode() + updateCode() editor.getAction('editor.action.formatDocument')?.run() if (formatAction) { formatAction() - code = getCode() + updateCode() } } } @@ -348,14 +372,14 @@ snippetsPreventQuickSuggestions: disableSuggestions } }) + keepModelAroundToAvoidDisposalOfWorkers() let timeoutModel: NodeJS.Timeout | undefined = undefined editor.onDidChangeModelContent((event) => { suggestion = '' timeoutModel && clearTimeout(timeoutModel) timeoutModel = setTimeout(() => { - code = getCode() - dispatch('change', { code }) + updateCode() }, 200) }) @@ -365,7 +389,7 @@ loadExtraLib() editor.addCommand(KeyMod.CtrlCmd | KeyCode.KeyS, function () { - code = getCode() + updateCode() shouldBindKey && format && format() }) @@ -397,12 +421,12 @@ editor.onDidFocusEditorText(() => { if (!editor) return editor.addCommand(KeyMod.CtrlCmd | KeyCode.KeyS, function () { - code = getCode() + updateCode() shouldBindKey && format && format() }) editor.addCommand(KeyMod.CtrlCmd | KeyCode.Enter, function () { - code = getCode() + updateCode() shouldBindKey && cmdEnterAction && cmdEnterAction() }) dispatch('focus') @@ -410,8 +434,7 @@ editor.onDidBlurEditorText(() => { dispatch('blur') - - code = getCode() + updateCode() }) if (lang === 'css' && !cssClassesLoaded) { @@ -511,6 +534,7 @@ }) } + let previousExtraLib = undefined function loadExtraLib() { if (lang == 'javascript') { const stdLib = { content: libStdContent, filePath: 'es6.d.ts' } @@ -524,6 +548,10 @@ content: extraLib, filePath: 'windmill.d.ts' }) + if (previousExtraLib == extraLib) { + return + } + previousExtraLib = extraLib } languages.typescript.javascriptDefaults.setExtraLibs(libs) } diff --git a/frontend/src/lib/components/TemplateEditor.svelte b/frontend/src/lib/components/TemplateEditor.svelte index 941c72fc74..b7027633ca 100644 --- a/frontend/src/lib/components/TemplateEditor.svelte +++ b/frontend/src/lib/components/TemplateEditor.svelte @@ -1,3 +1,21 @@ + + - - + diff --git a/frontend/src/lib/components/apps/editor/SettingsPanel.svelte b/frontend/src/lib/components/apps/editor/SettingsPanel.svelte index b2e0a4b52e..108a2498c2 100644 --- a/frontend/src/lib/components/apps/editor/SettingsPanel.svelte +++ b/frontend/src/lib/components/apps/editor/SettingsPanel.svelte @@ -121,9 +121,15 @@ gridItemWithLocation?.location.type === 'subgrid' && Array.isArray($app.subgrids?.[gridItemWithLocation.location.subgridKey]) ) { - $app.subgrids[gridItemWithLocation.location.subgridKey][ - gridItemWithLocation.location.subgridItemIndex - ] = cs.item + if ( + $app.subgrids[gridItemWithLocation.location.subgridKey][ + gridItemWithLocation.location.subgridItemIndex + ] + ) { + $app.subgrids[gridItemWithLocation.location.subgridKey][ + gridItemWithLocation.location.subgridItemIndex + ] = cs.item + } } } } diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte index 670ebb2445..3e280e9538 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte @@ -1,4 +1,7 @@ + {#if inlineScript} {#if inlineScript.language != 'frontend'} { + onkeyup={() => { $app = $app if (stateId) { $stateId++ diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/EvalV2InputEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/EvalV2InputEditor.svelte index 3b59f74051..dd9c7aebb6 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/EvalV2InputEditor.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/EvalV2InputEditor.svelte @@ -13,14 +13,27 @@ import { zIndexes } from '$lib/zIndexes' import Popover from '$lib/components/Popover.svelte' - export let componentInput: EvalV2AppInput | undefined - export let id: string - export let field: string - export let fixedOverflowWidgets: boolean = true - export let acceptSelf: boolean = false - export let recomputeOnInputChanged = true - export let showOnDemandOnlyToggle = false - export let securedContext = false + interface Props { + componentInput: EvalV2AppInput | undefined + id: string + field: string + fixedOverflowWidgets?: boolean + acceptSelf?: boolean + recomputeOnInputChanged?: boolean + showOnDemandOnlyToggle?: boolean + securedContext?: boolean + } + + let { + componentInput = $bindable(), + id, + field, + fixedOverflowWidgets = true, + acceptSelf = false, + recomputeOnInputChanged = true, + showOnDemandOnlyToggle = false, + securedContext = false + }: Props = $props() const { onchange, @@ -30,15 +43,17 @@ } = getContext('AppViewerContext') const { evalPreview } = getContext('AppEditorContext') - let editor: SimpleEditor + let editor: SimpleEditor | undefined = $state() export function setCode(code: string) { editor?.setCode(code) } - $: extraLib = - componentInput?.expr && $worldStore + let exprDefined = $derived(componentInput?.expr != undefined) + let extraLib = $derived( + exprDefined && $worldStore ? buildExtraLib($worldStore?.outputsById ?? {}, acceptSelf ? '' : id, $stateStore, false) : undefined + ) if ( componentInput && @@ -58,8 +73,8 @@ } } - let fullscreen = false - let focus = false + let fullscreen = $state(false) + let focus = $state(false) {#if componentInput?.type === 'evalv2'} @@ -110,7 +125,14 @@ small bind:this={editor} lang="javascript" - bind:code={() => componentInput.expr ?? '', (e) => (componentInput.expr = e)} + bind:code={ + () => componentInput.expr ?? '', + (e) => { + if (componentInput.expr != e) { + componentInput.expr = e + } + } + } shouldBindKey={false} {extraLib} autoHeight @@ -132,17 +154,17 @@
- + {#snippet text()} This context variable is securely provided by the backend and cannot be altered by users - + {/snippet}
{/if} (fullscreen = true)}> {#if focus}
diff --git a/frontend/src/lib/components/common/fileInput/FileInput.svelte b/frontend/src/lib/components/common/fileInput/FileInput.svelte index 0212f5f534..77d9b308d8 100644 --- a/frontend/src/lib/components/common/fileInput/FileInput.svelte +++ b/frontend/src/lib/components/common/fileInput/FileInput.svelte @@ -18,7 +18,7 @@ export let iconSize = 36 export let returnFileNames = false export let submittedText: string | undefined = undefined - export let defaultFile: string | undefined = undefined + export let defaultFile: string | string[] | undefined = undefined export let disabled: boolean | undefined = undefined export let folderOnly = false @@ -160,9 +160,8 @@ files = files if (convertTo && files) { const promises = files.map(convertFile) - let converted: ConvertedFile[] | { name: string; data: ConvertedFile }[] = await Promise.all( - promises - ) + let converted: ConvertedFile[] | { name: string; data: ConvertedFile }[] = + await Promise.all(promises) if (returnFileNames) { converted = converted.map((c, i) => ({ name: files![i].name, data: c })) } @@ -239,7 +238,7 @@ {multiple} {...$$restProps} /> - {#if defaultFile} + {#if defaultFile && (!Array.isArray(defaultFile) || defaultFile.length > 0)}
Default file: {defaultFile}
diff --git a/frontend/src/lib/components/common/fileUpload/FileUpload.svelte b/frontend/src/lib/components/common/fileUpload/FileUpload.svelte index 9e5180b76c..44f2a7d8d6 100644 --- a/frontend/src/lib/components/common/fileUpload/FileUpload.svelte +++ b/frontend/src/lib/components/common/fileUpload/FileUpload.svelte @@ -12,69 +12,111 @@ import { createEventDispatcher, onDestroy } from 'svelte' import { emptyString } from '$lib/utils' - export let acceptedFileTypes: string[] | undefined = ['*'] - export let allowMultiple: boolean = true - export let allowDelete = true - export let folderOnly = false - export let containerText: string = folderOnly - ? 'Drag and drop a folder here or click to browse' - : allowMultiple - ? 'Drag and drop files here or click to browse' - : 'Drag and drop a file here or click to browse' - export let customResourcePath: string | undefined = undefined - export let customResourceType: 's3' | 'azure_blob' | undefined = undefined // when customResourcePath is provided, this should be provided as well. Will default to S3 if not - export let customClass: string = '' - export let customStyle: string = '' - export let randomFileKey: boolean = false - export let pathTransformer: any = undefined // function taking as input {file: File} and returning a string - export let forceDisplayUploads: boolean = false - export let defaultValue: string | undefined = undefined - export let workspace: string | undefined = undefined - export let fileUploads: Writable = writable([]) - export let appPath: string | undefined = undefined - export let disabled = false - export let iconSize: number | undefined = undefined - export let initialValue: - | { - s3: string - filename: string - } - | undefined = undefined - - init() - - function init() { - if (initialValue?.s3) { - if (!$fileUploads.find((fileUpload) => fileUpload.path === initialValue?.s3)) { - $fileUploads = [ - ...$fileUploads, - { - name: initialValue.filename, - size: 0, - progress: 100, - path: initialValue?.s3 - } - ] - } - } + interface Props { + acceptedFileTypes?: string[] | undefined + allowMultiple?: boolean + allowDelete?: boolean + folderOnly?: boolean + containerText?: string + customResourcePath?: string | undefined + customResourceType?: 's3' | 'azure_blob' | undefined // when customResourcePath is provided, this should be provided as well. Will default to S3 if not + customClass?: string + customStyle?: string + randomFileKey?: boolean + pathTransformer?: any // function taking as input {file: File} and returning a string + forceDisplayUploads?: boolean + defaultValue?: string | string[] | undefined + workspace?: string | undefined + fileUploads?: Writable + appPath?: string | undefined + disabled?: boolean + iconSize?: number | undefined + initialValue?: + | { + s3: string + filename: string + } + | { + s3: string + filename: string + }[] + | undefined + computeForceViewerPolicies?: + | (() => + | { + allowed_resources: string[] + allow_user_resources: boolean + allow_workspace_resource: boolean + file_key_regex: string + } + | undefined) + | undefined } - export let computeForceViewerPolicies: - | (() => - | { - allowed_resources: string[] - allow_user_resources: boolean - allow_workspace_resource: boolean - file_key_regex: string - } - | undefined) - | undefined = undefined + let { + acceptedFileTypes = ['*'], + allowMultiple = true, + allowDelete = true, + folderOnly = false, + containerText = folderOnly + ? 'Drag and drop a folder here or click to browse' + : allowMultiple + ? 'Drag and drop files here or click to browse' + : 'Drag and drop a file here or click to browse', + customResourcePath = undefined, + customResourceType = undefined, + customClass = '', + customStyle = '', + randomFileKey = false, + pathTransformer = undefined, + forceDisplayUploads = $bindable(false), + defaultValue = undefined, + workspace = undefined, + fileUploads = writable([]), + appPath = undefined, + disabled = false, + iconSize = undefined, + initialValue = undefined, + computeForceViewerPolicies = undefined + }: Props = $props() const dispatch = createEventDispatcher<{ addition: { path?: string; filename?: string } deletion: { path: string } }>() + let initialS3 = $derived( + Array.isArray(initialValue) + ? initialValue?.map((v) => v.s3) + : initialValue?.s3 + ? [initialValue?.s3] + : undefined + ) + init() + + function init() { + if (initialS3) { + function transform(initialValue: { s3: string; filename: string }) { + return { + name: initialValue.filename, + size: 0, + progress: 100, + path: initialValue?.s3 + } + } + for (const s3 of initialS3) { + if (!$fileUploads.find((fileUpload) => fileUpload.path === s3)) { + let initialFileUploads = initialValue + ? Array.isArray(initialValue) + ? initialValue.map(transform) + : [transform(initialValue)] + : [] + $fileUploads = [...$fileUploads, ...initialFileUploads] + } + } + } + } + type FileUploadData = { name: string size: number @@ -554,10 +596,10 @@ {containerText}{#if disabled}
(Disabled){/if} {/if} - {#if initialValue?.s3 && $fileUploads.length == 0} + {#if initialS3 && initialS3.length > 0 && $fileUploads.length == 0}
- File currently selected: {initialValue?.s3} + File currently selected: {initialS3?.join(', ')}
{/if} diff --git a/frontend/src/lib/components/common/languageIcons/LanguageIcon.svelte b/frontend/src/lib/components/common/languageIcons/LanguageIcon.svelte index 9dd3c9860a..6a3de43bf9 100644 --- a/frontend/src/lib/components/common/languageIcons/LanguageIcon.svelte +++ b/frontend/src/lib/components/common/languageIcons/LanguageIcon.svelte @@ -22,6 +22,7 @@ import CSharpIcon from '$lib/components/icons/CSharpIcon.svelte' import NuIcon from '$lib/components/icons/NuIcon.svelte' import JavaIcon from '$lib/components/icons/JavaIcon.svelte' + import DuckDbIcon from '$lib/components/icons/DuckDbIcon.svelte' export let lang: | SupportedLanguage @@ -49,6 +50,7 @@ postgresql: 'Postgresql', bigquery: 'BigQuery', oracledb: 'Oracle Database', + duckdb: 'DuckDB', snowflake: 'Snowflake', mysql: 'MySQL', mssql: 'MS SQL Server', @@ -59,7 +61,7 @@ csharp: 'C#', nu: 'Nu', java: 'Java' - // for related places search: ADD_NEW_LANG + // for related places search: ADD_NEW_LANG } const langToComponent: Record< @@ -91,8 +93,9 @@ ansible: AnsibleIcon, csharp: CSharpIcon, nu: NuIcon, - java: JavaIcon - // for related places search: ADD_NEW_LANG + java: JavaIcon, + duckdb: DuckDbIcon + // for related places search: ADD_NEW_LANG } let subIconScale = width === 30 ? 0.6 : 0.8 diff --git a/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts b/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts index 9952199fd2..4662a62f8f 100644 --- a/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts +++ b/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts @@ -161,15 +161,15 @@ export class Autocompletor { modifiedCode: string = '' applyZone: | { - startLineNumber: number - endLineNumber: number - } + startLineNumber: number + endLineNumber: number + } | undefined = undefined lastChangePosition: | { - lineNumber: number - column: number - } + lineNumber: number + column: number + } | undefined = undefined abortController: AbortController | undefined = undefined @@ -180,12 +180,12 @@ export class Autocompletor { predictedChange: | { - position: { - lineNumber: number - column: number - } - distance: number - } + position: { + lineNumber: number + column: number + } + distance: number + } | undefined = undefined tabWidget: meditor.IContentWidget | undefined = undefined @@ -240,18 +240,18 @@ export class Autocompletor { let closestPosition: | { - lineNumber: number - column: number - } + lineNumber: number + column: number + } | undefined = undefined let closestDistance = Infinity for (const change of this.visualChanges) { if (change.type === 'deleted') { const distance = Math.min( Math.abs(change.range.startLine - position.lineNumber) + - Math.abs(change.range.startColumn - position.column) / 10000, + Math.abs(change.range.startColumn - position.column) / 10000, Math.abs(change.range.endLine - position.lineNumber) + - Math.abs(change.range.endColumn - position.column) / 10000 + Math.abs(change.range.endColumn - position.column) / 10000 ) if (distance < closestDistance) { closestDistance = distance diff --git a/frontend/src/lib/components/graph/FlowGraphV2.svelte b/frontend/src/lib/components/graph/FlowGraphV2.svelte index 2965f3cee7..f0c1b0bc9e 100644 --- a/frontend/src/lib/components/graph/FlowGraphV2.svelte +++ b/frontend/src/lib/components/graph/FlowGraphV2.svelte @@ -25,7 +25,7 @@ import ResultNode from './renderers/nodes/ResultNode.svelte' import BaseEdge from './renderers/edges/BaseEdge.svelte' import EmptyEdge from './renderers/edges/EmptyEdge.svelte' - import { sugiyama, dagStratify, decrossOpt, coordCenter } from 'd3-dag' + import { sugiyama, dagStratify, coordCenter, decrossTwoLayer, decrossOpt } from 'd3-dag' import { Expand } from 'lucide-svelte' import Toggle from '../Toggle.svelte' import DataflowEdge from './renderers/edges/DataflowEdge.svelte' @@ -143,12 +143,13 @@ let boxSize: any try { const layout = sugiyama() - .decross(decrossOpt()) + .decross(nodes.length > 20 ? decrossTwoLayer() : decrossOpt()) .coord(coordCenter()) .nodeSize(() => [NODE.width + NODE.gap.horizontal, NODE.height + NODE.gap.vertical]) boxSize = layout(dag) } catch { const layout = sugiyama() + .decross(decrossTwoLayer()) .coord(coordCenter()) .nodeSize(() => [NODE.width + NODE.gap.horizontal, NODE.height + NODE.gap.vertical]) boxSize = layout(dag) diff --git a/frontend/src/lib/components/graph/graphBuilder.ts b/frontend/src/lib/components/graph/graphBuilder.ts index 01a45f4696..ab851db42e 100644 --- a/frontend/src/lib/components/graph/graphBuilder.ts +++ b/frontend/src/lib/components/graph/graphBuilder.ts @@ -635,7 +635,7 @@ export function graphBuilder( if (failureModule) { let toAdd: Record = {} Object.keys(extra.flowModuleStates ?? {}).forEach((id) => { - if (id.startsWith('failure-')) { + if (id.startsWith('failure')) { const failureState = extra.flowModuleStates?.[id] as GraphModuleState | undefined if (failureState?.parent_module) { toAdd[failureState.parent_module] = id diff --git a/frontend/src/lib/components/icons/DuckDbIcon.svelte b/frontend/src/lib/components/icons/DuckDbIcon.svelte new file mode 100644 index 0000000000..7229a377a6 --- /dev/null +++ b/frontend/src/lib/components/icons/DuckDbIcon.svelte @@ -0,0 +1,19 @@ + + + + + + + diff --git a/frontend/src/lib/components/propertyPicker/ObjectViewer.svelte b/frontend/src/lib/components/propertyPicker/ObjectViewer.svelte index 74225bdf4a..97d541a673 100644 --- a/frontend/src/lib/components/propertyPicker/ObjectViewer.svelte +++ b/frontend/src/lib/components/propertyPicker/ObjectViewer.svelte @@ -1,4 +1,6 @@ +{#snippet renderScalar(k: string, v: any)} + + + { + selectProp(k, v, true) + }} + title={JSON.stringify(v)} + > + {#if v === NEVER_TESTED_THIS_FAR} + Test the flow to see a value + {:else if v == undefined} + undefined + {:else if v == null} + null + {:else if typeof v == 'string'} + "{truncate(v, 200)}" + {:else if typeof v == 'number' && Number.isInteger(v) && !Number.isSafeInteger(v)} + + {truncate(JSON.stringify(v), 200)} + + + {#snippet text()} + This number is too large for the frontend to handle correctly and may be rounded. + {/snippet} + + + {:else} + + {truncate(JSON.stringify(v), 200)} + + {/if} + +{/snippet} + @@ -118,10 +175,11 @@ {#if searchOpen}
{ - if (event?.key === 'Escape') { + onkeydown={(event) => { + if ((event as KeyboardEvent)?.key === 'Escape') { clearSearch() } + event.stopPropagation() }} type="text" class="!h-6 !text-2xs mt-0.5" @@ -130,7 +188,7 @@ /> @@ -147,12 +205,13 @@ {/if}
{/if} + {#if keys.length > 0} {#if !fullyCollapsed} {#if level != 0 && keys.length > 1} - - + + {/if} @@ -275,7 +297,7 @@
diff --git a/frontend/src/lib/components/triggers/postgres/PostgresTriggersPanel.svelte b/frontend/src/lib/components/triggers/postgres/PostgresTriggersPanel.svelte index 0a007d6db0..d59e074114 100644 --- a/frontend/src/lib/components/triggers/postgres/PostgresTriggersPanel.svelte +++ b/frontend/src/lib/components/triggers/postgres/PostgresTriggersPanel.svelte @@ -41,8 +41,7 @@ hideTarget hideTooltips={!isDeployed || cloudDisabled} allowDraft={true} - hasDraft={!!selectedTrigger.draftConfig} - isDraftOnly={selectedTrigger.isDraft} + trigger={selectedTrigger} {isEditor} {isDeployed} {cloudDisabled} diff --git a/frontend/src/lib/components/triggers/postgres/PublicationPicker.svelte b/frontend/src/lib/components/triggers/postgres/PublicationPicker.svelte index 840d9a6856..4ba863d399 100644 --- a/frontend/src/lib/components/triggers/postgres/PublicationPicker.svelte +++ b/frontend/src/lib/components/triggers/postgres/PublicationPicker.svelte @@ -18,8 +18,12 @@ export let transaction_to_track: string[] = [] export let disabled: boolean = false + let loadingPublication: boolean = false + let deletingPublication: boolean = false + let updatingPublication: boolean = false async function listDatabasePublication() { try { + loadingPublication = true const publications = await PostgresTriggerService.listPostgresPublication({ path: postgres_resource_path, workspace: $workspaceStore! @@ -28,11 +32,14 @@ items = publications } catch (error) { sendUserToast(error.body, true) + } finally { + loadingPublication = false } } async function updatePublication() { try { + updatingPublication = true const message = await PostgresTriggerService.updatePostgresPublication({ path: postgres_resource_path, workspace: $workspaceStore!, @@ -45,11 +52,14 @@ sendUserToast(message) } catch (error) { sendUserToast(error.body, true) + } finally { + updatingPublication = false } } async function deletePublication() { try { + deletingPublication = true const message = await PostgresTriggerService.deletePostgresPublication({ path: postgres_resource_path, workspace: $workspaceStore!, @@ -62,6 +72,8 @@ sendUserToast(message) } catch (error) { sendUserToast(error.body, true) + } finally { + deletingPublication = false } } @@ -91,6 +103,7 @@