diff --git a/.github/workflows/backend-test.yml b/.github/workflows/backend-test.yml index 43e8954c33..940eb34b1f 100644 --- a/.github/workflows/backend-test.yml +++ b/.github/workflows/backend-test.yml @@ -86,4 +86,4 @@ jobs: run: | deno --version && bun -v && go version && python3 --version cd windmill-duckdb-ffi-internal && ./build_dev.sh && cd .. - DENO_PATH=$(which deno) BUN_PATH=$(which bun) GO_PATH=$(which go) UV_PATH=$(which uv) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,private --all -- --nocapture + DENO_PATH=$(which deno) BUN_PATH=$(which bun) GO_PATH=$(which go) UV_PATH=$(which uv) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private --all -- --nocapture diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 0a7661bf3b..18ab1ba4e8 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -104,7 +104,7 @@ jobs: } } claude_args: | - --allowedTools "Bash" + --allowedTools "Bash,WebFetch,WebSearch" --system-prompt "## IMPORTANT INSTRUCTIONS - Your branch name should be a short description of the requested changes. - 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. diff --git a/.github/workflows/git-commands.yaml b/.github/workflows/git-commands.yaml index 7c7a05e81e..7e8a5e2acf 100644 --- a/.github/workflows/git-commands.yaml +++ b/.github/workflows/git-commands.yaml @@ -82,6 +82,10 @@ jobs: run: | set -e # Exit on any command failure PR_NUMBER=${{ github.event.issue.number }} + + # Set up error trap to comment on PR for any failure + trap 'gh pr comment $PR_NUMBER --body "❌ SQLx update failed. Please check the workflow logs for details."' ERR + BRANCH_NAME=$(gh pr view $PR_NUMBER --json headRefName --jq .headRefName) echo "Checking out PR branch: $BRANCH_NAME" git checkout $BRANCH_NAME @@ -93,10 +97,8 @@ jobs: cd backend cargo install sqlx-cli --version 0.8.5 sqlx migrate run - if ! ./update_sqlx.sh --dir ./windmill-ee-private; then - gh pr comment $PR_NUMBER --body "❌ SQLx update failed. Please check the workflow logs for details." - exit 1 - fi + ./substitute_ee_code.sh --dir ./windmill-ee-private + ./update_sqlx.sh # Pass the branch name to the next step echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV @@ -216,11 +218,12 @@ jobs: with: github-token: ${{ steps.app.outputs.token }} script: | + const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: 'Starting ee ref update...' + body: `Starting ee ref update...\n\n[View workflow run](${runUrl})` }) - name: Checkout repository @@ -249,7 +252,12 @@ jobs: env: GH_TOKEN: ${{ steps.app.outputs.token }} run: | + set -e # Exit on any command failure PR_NUMBER=${{ github.event.issue.number }} + + # Set up error trap to comment on PR for any failure + trap 'gh pr comment $PR_NUMBER --body "❌ EE ref update failed. Please check the workflow logs for details."' ERR + BRANCH_NAME=$(gh pr view $PR_NUMBER --json headRefName --jq .headRefName) echo "Checking out PR branch: $BRANCH_NAME" git checkout $BRANCH_NAME diff --git a/CHANGELOG.md b/CHANGELOG.md index c42c850475..e4f2ce0b34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,79 @@ # Changelog +## [1.585.1](https://github.com/windmill-labs/windmill/compare/v1.585.0...v1.585.1) (2025-11-26) + + +### Bug Fixes + +* clone group members on workspace forks ([#7232](https://github.com/windmill-labs/windmill/issues/7232)) ([faad000](https://github.com/windmill-labs/windmill/commit/faad0006b430262f1ab6b749ccf60a6860a54405)) + +## [1.585.0](https://github.com/windmill-labs/windmill/compare/v1.584.0...v1.585.0) (2025-11-26) + + +### Features + +* flow for loop squashing ([#7107](https://github.com/windmill-labs/windmill/issues/7107)) ([93c34c6](https://github.com/windmill-labs/windmill/commit/93c34c6d769dd56da02064c0abdaa060efe0259d)) +* **frontend:** move app reports script to hub ([#7227](https://github.com/windmill-labs/windmill/issues/7227)) ([f8a0bfc](https://github.com/windmill-labs/windmill/commit/f8a0bfc20d1ccb6ce36e3adf4188533470270bdb)) + + +### Bug Fixes + +* **cli:** improve back-compatibility with app.yaml with policy still present ([c0a92f8](https://github.com/windmill-labs/windmill/commit/c0a92f83b00341b0eee36e2dc88d301a75b6fdfb)) +* **frontend:** workspace color race condition for superadmins ([#7229](https://github.com/windmill-labs/windmill/issues/7229)) ([8922be1](https://github.com/windmill-labs/windmill/commit/8922be11a6935d200e1909f14aa410c6eff67a13)) +* workspace forks shouldn't inherit promotion mode repo ([#7223](https://github.com/windmill-labs/windmill/issues/7223)) ([f56f3b0](https://github.com/windmill-labs/windmill/commit/f56f3b0fe6185167e9c4c8541ddefba01c509b8d)) + +## [1.584.0](https://github.com/windmill-labs/windmill/compare/v1.583.3...v1.584.0) (2025-11-25) + + +### Features + +* **app:** add chat component ([#7199](https://github.com/windmill-labs/windmill/issues/7199)) ([c47669b](https://github.com/windmill-labs/windmill/commit/c47669be0bffb0821afe9d4182cc071cb3b675f0)) + + +### Bug Fixes + +* **cli:** handle better public apps ([de7739a](https://github.com/windmill-labs/windmill/commit/de7739a3ee7ef76a8eb4fe6570ef0bdfbdb92293)) +* **frontend:** forking UI issues ([#7215](https://github.com/windmill-labs/windmill/issues/7215)) ([dccee1d](https://github.com/windmill-labs/windmill/commit/dccee1dba08b4c4b170336b3f3e959fbe7bca8ce)) +* **frontend:** improve preprocessor discoverability ([#7214](https://github.com/windmill-labs/windmill/issues/7214)) ([a2d3297](https://github.com/windmill-labs/windmill/commit/a2d3297343338ba0b559481723e64db5f4acf3a7)) +* **frontend:** loading saved/history inputs when json view is on ([#7217](https://github.com/windmill-labs/windmill/issues/7217)) ([e87f814](https://github.com/windmill-labs/windmill/commit/e87f81470904578467f42598cfce5fad2249f131)) +* **frontend:** show trigger table when no trigger selected ([#7219](https://github.com/windmill-labs/windmill/issues/7219)) ([c37dde0](https://github.com/windmill-labs/windmill/commit/c37dde096c301a502c6ff2c570b91153a5717fcd)) +* list scripts without 1000 limits ([897faf0](https://github.com/windmill-labs/windmill/commit/897faf085b49ada0648594797cfe627decb50952)) + +## [1.583.3](https://github.com/windmill-labs/windmill/compare/v1.583.2...v1.583.3) (2025-11-24) + + +### Bug Fixes + +* **cli:** fix pushing non existing apps with cli ([29d8ad2](https://github.com/windmill-labs/windmill/commit/29d8ad2e5de1447f39252edd5ceea22034801547)) +* fix deadlock on oidc ([0e717c9](https://github.com/windmill-labs/windmill/commit/0e717c9588c1a3811cc4d438b53a93b4b13cf239)) + +## [1.583.2](https://github.com/windmill-labs/windmill/compare/v1.583.1...v1.583.2) (2025-11-24) + + +### Bug Fixes + +* listScripts include description with opt-out query arg ([#7210](https://github.com/windmill-labs/windmill/issues/7210)) ([80c7911](https://github.com/windmill-labs/windmill/commit/80c79116416db8629135a8853df645d9fff286dd)) +* **scim:** use value instead of display for group updates ([#7203](https://github.com/windmill-labs/windmill/issues/7203)) ([193efe3](https://github.com/windmill-labs/windmill/commit/193efe31c8aeab3a5e3e28278855d518c000bda8)) + +## [1.583.1](https://github.com/windmill-labs/windmill/compare/v1.583.0...v1.583.1) (2025-11-21) + + +### Bug Fixes + +* **cli:** improve cli local policy generation ([b857d15](https://github.com/windmill-labs/windmill/commit/b857d15352ab422c1d477cd9172856956c2c4b7c)) + +## [1.583.0](https://github.com/windmill-labs/windmill/compare/v1.582.2...v1.583.0) (2025-11-21) + + +### Features + +* **cli:** app policies are generated locally ([#7200](https://github.com/windmill-labs/windmill/issues/7200)) ([f85ab0c](https://github.com/windmill-labs/windmill/commit/f85ab0c5dd64f01fbd0c0c9c2a4cea029a04cd50)) + + +### Bug Fixes + +* **backend:** handle malformed errors in flow error handler ([#7196](https://github.com/windmill-labs/windmill/issues/7196)) ([f531866](https://github.com/windmill-labs/windmill/commit/f53186653220a5213e0bffdf77187faaa9190a7e)) + ## [1.582.2](https://github.com/windmill-labs/windmill/compare/v1.582.1...v1.582.2) (2025-11-21) diff --git a/backend/.sqlx/query-00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098.json b/backend/.sqlx/query-00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098.json new file mode 100644 index 0000000000..72942b3788 --- /dev/null +++ b/backend/.sqlx/query-00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098.json @@ -0,0 +1,58 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n workspace.id AS \"id!\",\n workspace.name AS \"name!\",\n workspace.owner AS \"owner!\",\n workspace.deleted AS \"deleted!\",\n workspace.premium AS \"premium!\",\n workspace_settings.color AS \"color\",\n workspace.parent_workspace_id AS \"parent_workspace_id\"\n FROM workspace\n LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id\n WHERE workspace.id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id!", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "name!", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "owner!", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "deleted!", + "type_info": "Bool" + }, + { + "ordinal": 4, + "name": "premium!", + "type_info": "Bool" + }, + { + "ordinal": 5, + "name": "color", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "parent_workspace_id", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + true + ] + }, + "hash": "00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098" +} diff --git a/backend/.sqlx/query-05f4663a0f58736e92fe7cbbef3c99a03bc74ab3be1bacdbbf3910a76a1beacc.json b/backend/.sqlx/query-05f4663a0f58736e92fe7cbbef3c99a03bc74ab3be1bacdbbf3910a76a1beacc.json new file mode 100644 index 0000000000..c1e18c20a6 --- /dev/null +++ b/backend/.sqlx/query-05f4663a0f58736e92fe7cbbef3c99a03bc74ab3be1bacdbbf3910a76a1beacc.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT name FROM group_ WHERE workspace_id = $1 UNION SELECT name FROM instance_group ORDER BY name asc", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "name", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "05f4663a0f58736e92fe7cbbef3c99a03bc74ab3be1bacdbbf3910a76a1beacc" +} diff --git a/backend/.sqlx/query-086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9.json b/backend/.sqlx/query-086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9.json new file mode 100644 index 0000000000..2348defd19 --- /dev/null +++ b/backend/.sqlx/query-086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM flow_conversation WHERE id = $1) as \"exists!\"", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists!", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + null + ] + }, + "hash": "086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9" +} diff --git a/backend/.sqlx/query-348d64dc9f81f04538c5fec98df51312794c22d6337be897bc618585fa5b27f3.json b/backend/.sqlx/query-348d64dc9f81f04538c5fec98df51312794c22d6337be897bc618585fa5b27f3.json new file mode 100644 index 0000000000..46d591b6a1 --- /dev/null +++ b/backend/.sqlx/query-348d64dc9f81f04538c5fec98df51312794c22d6337be897bc618585fa5b27f3.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE v2_job_status\n SET flow_status = jsonb_set(\n flow_status,\n '{memory_id}',\n to_jsonb($2::uuid)\n )\n WHERE id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "348d64dc9f81f04538c5fec98df51312794c22d6337be897bc618585fa5b27f3" +} diff --git a/backend/.sqlx/query-3f9004b5542afaaef40942a3ca8889ea164d9cfb4962997650d922d82f000df9.json b/backend/.sqlx/query-3f9004b5542afaaef40942a3ca8889ea164d9cfb4962997650d922d82f000df9.json new file mode 100644 index 0000000000..094331bb82 --- /dev/null +++ b/backend/.sqlx/query-3f9004b5542afaaef40942a3ca8889ea164d9cfb4962997650d922d82f000df9.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO usr_to_group (workspace_id, group_, usr)\n SELECT $2, group_, usr\n FROM usr_to_group\n WHERE workspace_id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "3f9004b5542afaaef40942a3ca8889ea164d9cfb4962997650d922d82f000df9" +} diff --git a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json index 713ccb9dd3..36ddb8ab9f 100644 --- a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json +++ b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json @@ -15,7 +15,7 @@ ] }, "nullable": [ - null + true ] }, "hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55" diff --git a/backend/.sqlx/query-8830fc3736ec6dbbaee20f0ebeba5a87c2c94227798f4545fe0931af2818a6fa.json b/backend/.sqlx/query-8830fc3736ec6dbbaee20f0ebeba5a87c2c94227798f4545fe0931af2818a6fa.json new file mode 100644 index 0000000000..cfd79b3cdd --- /dev/null +++ b/backend/.sqlx/query-8830fc3736ec6dbbaee20f0ebeba5a87c2c94227798f4545fe0931af2818a6fa.json @@ -0,0 +1,66 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT workspace_id, name, display_name, owners, extra_perms, summary, created_by, edited_at FROM folder WHERE workspace_id = $1 ORDER BY name asc LIMIT $2 OFFSET $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "display_name", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "owners", + "type_info": "VarcharArray" + }, + { + "ordinal": 4, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 5, + "name": "summary", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "created_by", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "edited_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text", + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + true, + true + ] + }, + "hash": "8830fc3736ec6dbbaee20f0ebeba5a87c2c94227798f4545fe0931af2818a6fa" +} diff --git a/backend/.sqlx/query-ba9ab074f466bc2c581f018e2592f5a453e8a766c35dbf919d29c96966d63c75.json b/backend/.sqlx/query-ba9ab074f466bc2c581f018e2592f5a453e8a766c35dbf919d29c96966d63c75.json new file mode 100644 index 0000000000..c7114f6591 --- /dev/null +++ b/backend/.sqlx/query-ba9ab074f466bc2c581f018e2592f5a453e8a766c35dbf919d29c96966d63c75.json @@ -0,0 +1,42 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM group_ WHERE workspace_id = $1 ORDER BY name asc LIMIT $2 OFFSET $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "summary", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "extra_perms", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Text", + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false, + true, + false + ] + }, + "hash": "ba9ab074f466bc2c581f018e2592f5a453e8a766c35dbf919d29c96966d63c75" +} diff --git a/backend/.sqlx/query-c77fc86e0fa5d483889b0c4201f6d89b454523b31847798bedcc6c460f9ff7ea.json b/backend/.sqlx/query-c77fc86e0fa5d483889b0c4201f6d89b454523b31847798bedcc6c460f9ff7ea.json new file mode 100644 index 0000000000..2e2b953eee --- /dev/null +++ b/backend/.sqlx/query-c77fc86e0fa5d483889b0c4201f6d89b454523b31847798bedcc6c460f9ff7ea.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT name FROM folder WHERE workspace_id = $1 ORDER BY name asc LIMIT $2 OFFSET $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "name", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Int8", + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c77fc86e0fa5d483889b0c4201f6d89b454523b31847798bedcc6c460f9ff7ea" +} diff --git a/backend/.sqlx/query-f5568a691ec5931634cf986f806f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d.json b/backend/.sqlx/query-f5568a691ec5931634cf986f806f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d.json deleted file mode 100644 index 68461c0c98..0000000000 --- a/backend/.sqlx/query-f5568a691ec5931634cf986f806f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE v2_job_status \n SET flow_status = jsonb_set(\n flow_status,\n '{memory_id}',\n to_jsonb($2::uuid)\n )\n WHERE id = $1", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid", - "Uuid" - ] - }, - "nullable": [] - }, - "hash": "f5568a691ec5931634cf986f806f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d" -} diff --git a/backend/Cargo.lock b/backend/Cargo.lock index f188add772..dbe2b535d3 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -556,7 +556,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -645,7 +645,7 @@ checksum = "850b60ddcc664dcd848f8a2fa8436ab9336e051d6dd2b3f21f897dd8e9c24703" dependencies = [ "base64 0.22.1", "bytes", - "http 1.3.1", + "http 1.4.0", "rand 0.8.5", "reqwest 0.12.24", "serde", @@ -670,7 +670,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -692,7 +692,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -703,7 +703,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -777,7 +777,7 @@ dependencies = [ "bytes", "fastrand", "hex", - "http 1.3.1", + "http 1.4.0", "ring 0.17.14", "time", "tokio", @@ -800,9 +800,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5932a7d9d28b0d2ea34c6b3779d35e3dd6f6345317c34e73438c4f1f29144151" +checksum = "6b5ce75405893cd713f9ab8e297d8e438f624dde7d706108285f7e17a25a180f" dependencies = [ "aws-lc-sys", "zeroize", @@ -810,11 +810,10 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1826f2e4cfc2cd19ee53c42fbf68e2f81ec21108e0b7ecf6a71cf062137360fc" +checksum = "179c3777a8b5e70e90ea426114ffc565b2c1a9f82f6c4a0c5a34aa6ef5e781b6" dependencies = [ - "bindgen 0.72.1", "cc", "cmake", "dunce", @@ -896,9 +895,9 @@ dependencies = [ [[package]] name = "aws-sdk-rds" -version = "1.117.0" +version = "1.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b116d0229c41d5b72050dda07aa2cc7d1c571de8f7870c8b87fa297a724982" +checksum = "32ddd2f95d05c73d977308579961917c3b00bbacd36a592470111058a72582ac" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1024,7 +1023,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "percent-encoding", "sha2 0.10.9", "time", @@ -1067,7 +1066,7 @@ dependencies = [ "futures-core", "futures-util", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "percent-encoding", "pin-project-lite", @@ -1087,7 +1086,7 @@ dependencies = [ "h2 0.3.27", "h2 0.4.12", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "hyper 0.14.32", "hyper 1.8.1", @@ -1148,7 +1147,7 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", "pin-project-lite", @@ -1167,7 +1166,7 @@ dependencies = [ "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "pin-project-lite", "tokio", "tracing", @@ -1185,7 +1184,7 @@ dependencies = [ "bytes-utils", "futures-core", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -1244,7 +1243,7 @@ dependencies = [ "axum-macros", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -1278,7 +1277,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "mime", @@ -1298,7 +1297,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1438,7 +1437,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.110", + "syn 2.0.111", "which 4.4.2", ] @@ -1459,7 +1458,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1472,14 +1471,12 @@ dependencies = [ "cexpr", "clang-sys", "itertools 0.13.0", - "log", - "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash 2.1.1", "shlex", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1632,7 +1629,7 @@ dependencies = [ "futures-core", "futures-util", "hex", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 1.8.1", "hyper-named-pipe", @@ -1686,14 +1683,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] name = "borsh" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ "borsh-derive", "cfg_aliases 0.2.1", @@ -1701,15 +1698,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1719,7 +1716,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17d4f95e880cfd28c4ca5a006cf7f6af52b4bcb7b5866f573b2faa126fb7affb" dependencies = [ "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1805,11 +1802,12 @@ dependencies = [ [[package]] name = "byte-unit" -version = "5.1.6" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cd29c3c585209b0cbc7309bfe3ed7efd8c84c21b7af29c8bfae908f8777174" +checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" dependencies = [ "rust_decimal", + "schemars 1.1.0", "serde", "utf8-width", ] @@ -1853,7 +1851,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1996,7 +1994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b4a6cae9efc04cc6cbb8faf338d2c497c165c83e74509cf4dbedea948bbf6e5" dependencies = [ "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2010,9 +2008,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.46" +version = "1.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36" +checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" dependencies = [ "find-msvc-tools", "jobserver", @@ -2148,7 +2146,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2203,7 +2201,7 @@ dependencies = [ "nom 7.1.3", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2399,9 +2397,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -2585,7 +2583,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2678,7 +2676,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2692,7 +2690,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2725,7 +2723,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2736,7 +2734,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2749,7 +2747,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.12", + "parking_lot_core", ] [[package]] @@ -2763,7 +2761,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.12", + "parking_lot_core", ] [[package]] @@ -2820,7 +2818,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "parquet", "rand 0.8.5", "regex", @@ -2855,7 +2853,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "tokio", ] @@ -3028,7 +3026,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "parquet", "rand 0.8.5", "tokio", @@ -3053,7 +3051,7 @@ dependencies = [ "futures", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "rand 0.8.5", "tempfile", "url", @@ -3189,7 +3187,7 @@ dependencies = [ "datafusion-common", "datafusion-expr", "datafusion-physical-plan", - "parking_lot 0.12.5", + "parking_lot", "paste", ] @@ -3228,7 +3226,7 @@ checksum = "df6f88d7ee27daf8b108ba910f9015176b36fbc72902b1ca5c2a5f1d1717e1a1" dependencies = [ "datafusion-expr", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -3330,7 +3328,7 @@ dependencies = [ "indexmap 2.11.1", "itertools 0.14.0", "log", - "parking_lot 0.12.5", + "parking_lot", "pin-project-lite", "tokio", ] @@ -3355,7 +3353,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "tokio", ] @@ -3480,11 +3478,11 @@ dependencies = [ "deno_error", "deno_media_type", "deno_path_util", - "http 1.3.1", + "http 1.4.0", "indexmap 2.11.1", "log", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "serde", "serde_json", "sha2 0.10.9", @@ -3566,7 +3564,7 @@ dependencies = [ "indexmap 2.11.1", "libc", "memoffset", - "parking_lot 0.12.5", + "parking_lot", "percent-encoding", "pin-project", "serde", @@ -3666,7 +3664,7 @@ checksum = "babccedee31ce7e57c3e6dff2cb3ab8d68c49d0df8222fe0d11d628e65192790" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -3688,7 +3686,7 @@ dependencies = [ "error_reporter", "h2 0.4.12", "hickory-resolver", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 1.8.1", "hyper-rustls 0.27.7", @@ -3775,7 +3773,7 @@ dependencies = [ "deno_websocket", "flate2", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "httparse", "hyper 0.14.32", "hyper 1.8.1", @@ -3811,7 +3809,7 @@ dependencies = [ "log", "once_cell", "os_pipe", - "parking_lot 0.12.5", + "parking_lot", "pin-project", "rand 0.8.5", "tokio", @@ -3842,7 +3840,7 @@ dependencies = [ "denokv_remote", "denokv_sqlite", "faster-hex", - "http 1.3.1", + "http 1.4.0", "http-body-util", "log", "num-bigint", @@ -3969,7 +3967,7 @@ dependencies = [ "faster-hex", "h2 0.4.12", "hkdf", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 1.8.1", "hyper-util", @@ -4057,7 +4055,7 @@ dependencies = [ "stringcase", "strum 0.25.0", "strum_macros 0.25.3", - "syn 2.0.110", + "syn 2.0.111", "thiserror 2.0.17", ] @@ -4191,7 +4189,7 @@ dependencies = [ "log", "node_resolver", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "sys_traits", "thiserror 2.0.17", "url", @@ -4239,7 +4237,7 @@ dependencies = [ "dlopen2 0.6.1", "encoding_rs", "fastwebsockets", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 0.14.32", "hyper 1.8.1", @@ -4348,7 +4346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6742a724e8becb372a74c650a1aefb8924a5b8107f7d75b3848763ea24b27a87" dependencies = [ "futures-util", - "parking_lot 0.12.5", + "parking_lot", "tokio", ] @@ -4424,7 +4422,7 @@ dependencies = [ "deno_tls", "fastwebsockets", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 1.8.1", "hyper-util", @@ -4487,7 +4485,7 @@ dependencies = [ "deno_error", "denokv_proto", "futures", - "http 1.3.1", + "http 1.4.0", "log", "prost", "rand 0.8.5", @@ -4559,7 +4557,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4580,7 +4578,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4624,7 +4622,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4644,7 +4642,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4770,7 +4768,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4805,7 +4803,7 @@ checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5015,7 +5013,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5081,7 +5079,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5101,7 +5099,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5121,7 +5119,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5449,7 +5447,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5487,7 +5485,7 @@ checksum = "32016f1242eb82af5474752d00fd8ebcd9004bd69b462b1c91de833972d08ed4" dependencies = [ "proc-macro2", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5592,7 +5590,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.12.5", + "parking_lot", ] [[package]] @@ -5622,7 +5620,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -6007,7 +6005,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -6102,7 +6100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de13e62d7e0ffc3eb40a0113ddf753cf6ec741be739164442b08893db4f9bfca" dependencies = [ "google-cloud-token", - "http 1.3.1", + "http 1.4.0", "thiserror 1.0.69", "tokio", "tokio-retry2", @@ -6262,7 +6260,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.3.1", + "http 1.4.0", "indexmap 2.11.1", "slab", "tokio", @@ -6339,7 +6337,7 @@ checksum = "149e3ea90eb5a26ad354cfe3cb7f7401b9329032d0235f2687d03a35f30e5d4c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -6383,7 +6381,7 @@ dependencies = [ "base64 0.22.1", "bytes", "headers-core", - "http 1.3.1", + "http 1.4.0", "httpdate", "mime", "sha1", @@ -6395,7 +6393,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -6436,7 +6434,7 @@ checksum = "629d8f3bbeda9d148036d6b0de0a3ab947abd08ce90626327fc3547a49d59d97" dependencies = [ "dirs 6.0.0", "futures", - "http 1.3.1", + "http 1.4.0", "indicatif", "libc", "log", @@ -6490,7 +6488,7 @@ dependencies = [ "ipconfig", "moka", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "rand 0.9.0", "resolv-conf", "serde", @@ -6582,12 +6580,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -6609,7 +6606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -6620,7 +6617,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "pin-project-lite", ] @@ -6678,7 +6675,7 @@ dependencies = [ "futures-channel", "futures-core", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "httparse", "httpdate", @@ -6699,7 +6696,7 @@ dependencies = [ "bytes", "futures-util", "headers", - "http 1.3.1", + "http 1.4.0", "hyper 1.8.1", "hyper-rustls 0.27.7", "hyper-util", @@ -6747,7 +6744,7 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.3.1", + "http 1.4.0", "hyper 1.8.1", "hyper-util", "log", @@ -6813,7 +6810,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "hyper 1.8.1", "ipnet", @@ -7101,18 +7098,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "integer-encoding" version = "3.0.4" @@ -7185,7 +7170,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -7481,7 +7466,7 @@ dependencies = [ "either", "futures", "home", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -7515,7 +7500,7 @@ dependencies = [ "chrono", "derive_more 2.0.1", "form_urlencoded", - "http 1.3.1", + "http 1.4.0", "json-patch", "k8s-openapi", "schemars 0.8.22", @@ -7536,7 +7521,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -7556,7 +7541,7 @@ dependencies = [ "json-patch", "k8s-openapi", "kube-client", - "parking_lot 0.12.5", + "parking_lot", "pin-project", "serde", "serde_json", @@ -7592,7 +7577,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8199,7 +8184,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8286,7 +8271,7 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "equivalent", - "parking_lot 0.12.5", + "parking_lot", "portable-atomic", "rustc_version 0.4.1", "smallvec", @@ -8318,7 +8303,7 @@ checksum = "c402a4092d5e204f32c9e155431046831fa712637043c58cb73bc6bc6c9663b5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8330,7 +8315,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.3.1", + "http 1.4.0", "httparse", "memchr", "mime", @@ -8363,7 +8348,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "termcolor", "thiserror 2.0.17", ] @@ -8466,7 +8451,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8672,7 +8657,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8940,7 +8925,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8958,7 +8943,7 @@ dependencies = [ "base64 0.22.1", "chrono", "getrandom 0.2.16", - "http 1.3.1", + "http 1.4.0", "rand 0.8.5", "reqwest 0.12.24", "serde", @@ -9007,14 +8992,14 @@ dependencies = [ "chrono", "form_urlencoded", "futures", - "http 1.3.1", + "http 1.4.0", "http-body-util", "httparse", "humantime", "hyper 1.8.1", "itertools 0.14.0", "md-5 0.10.6", - "parking_lot 0.12.5", + "parking_lot", "percent-encoding", "quick-xml 0.37.5", "rand 0.9.0", @@ -9125,7 +9110,7 @@ dependencies = [ "dyn-clone", "ed25519-dalek", "hmac", - "http 1.3.1", + "http 1.4.0", "itertools 0.10.5", "log", "oauth2", @@ -9168,7 +9153,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -9233,7 +9218,7 @@ checksum = "10a8a7f5f6ba7c1b286c2fbca0454eaba116f63bbe69ed250b642d36fbb04d80" dependencies = [ "async-trait", "bytes", - "http 1.3.1", + "http 1.4.0", "opentelemetry", ] @@ -9245,7 +9230,7 @@ checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" dependencies = [ "async-trait", "futures-core", - "http 1.3.1", + "http 1.4.0", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", @@ -9433,17 +9418,6 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.5" @@ -9451,21 +9425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", - "parking_lot_core 0.9.12", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -9604,9 +9564,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.3" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" +checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" dependencies = [ "memchr", "ucd-trie", @@ -9614,9 +9574,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.3" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" +checksum = "51f72981ade67b1ca6adc26ec221be9f463f2b5839c7508998daa17c23d94d7f" dependencies = [ "pest", "pest_generator", @@ -9624,22 +9584,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.3" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" +checksum = "dee9efd8cdb50d719a80088b76f81aec7c41ed6d522ee750178f83883d271625" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] name = "pest_meta" -version = "2.8.3" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" +checksum = "bf1d70880e76bdc13ba52eafa6239ce793d85c8e43896507e43dd8984ff05b82" dependencies = [ "pest", "sha2 0.10.9", @@ -9713,7 +9673,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -9763,7 +9723,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -9975,7 +9935,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10039,7 +9999,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10050,7 +10010,7 @@ checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f" dependencies = [ "proc-macro-rules-macros", "proc-macro2", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10062,7 +10022,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10143,7 +10103,7 @@ dependencies = [ "fnv", "lazy_static", "memchr", - "parking_lot 0.12.5", + "parking_lot", "thiserror 2.0.17", ] @@ -10173,7 +10133,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.110", + "syn 2.0.111", "tempfile", ] @@ -10187,7 +10147,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10312,7 +10272,7 @@ dependencies = [ "ahash 0.8.12", "equivalent", "hashbrown 0.16.1", - "parking_lot 0.12.5", + "parking_lot", ] [[package]] @@ -10597,16 +10557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b" dependencies = [ "quote", - "syn 2.0.110", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", + "syn 2.0.111", ] [[package]] @@ -10666,7 +10617,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10774,7 +10725,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -10819,7 +10770,7 @@ checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" dependencies = [ "anyhow", "async-trait", - "http 1.3.1", + "http 1.4.0", "reqwest 0.12.24", "serde", "thiserror 1.0.69", @@ -10828,24 +10779,23 @@ dependencies = [ [[package]] name = "reqwest-retry" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c73e4195a6bfbcb174b790d9b3407ab90646976c55de58a6515da25d851178" +checksum = "105747e3a037fe5bf17458d794de91149e575b6183fc72c85623a44abb9683f5" dependencies = [ "anyhow", "async-trait", "futures", "getrandom 0.2.16", - "http 1.3.1", + "http 1.4.0", "hyper 1.8.1", - "parking_lot 0.11.2", "reqwest 0.12.24", "reqwest-middleware", "retry-policies", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tracing", - "wasm-timer", + "wasmtimer", ] [[package]] @@ -10856,9 +10806,9 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" [[package]] name = "retry-policies" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5875471e6cab2871bc150ecb8c727db5113c9338cc3354dc5ee3425b6aa40a1c" +checksum = "503c78f59814e2664c9980b739b19e40f549233ecf39928040ee54fdd431f614" dependencies = [ "rand 0.8.5", ] @@ -10950,7 +10900,7 @@ dependencies = [ "bytes", "chrono", "futures", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "paste", @@ -10981,7 +10931,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11071,7 +11021,7 @@ dependencies = [ "quote", "rust-embed-utils", "shellexpand", - "syn 2.0.110", + "syn 2.0.111", "walkdir", ] @@ -11559,7 +11509,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11571,7 +11521,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11760,7 +11710,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11771,7 +11721,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11823,7 +11773,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11890,7 +11840,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12012,9 +11962,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -12321,7 +12271,7 @@ checksum = "da5fc6819faabb412da764b99d3b713bb55083c11e7e0c00144d386cd6a1939c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12386,7 +12336,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12409,7 +12359,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.110", + "syn 2.0.111", "tokio", "url", ] @@ -12573,7 +12523,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12642,7 +12592,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12654,7 +12604,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12773,7 +12723,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12822,7 +12772,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12907,7 +12857,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13014,7 +12964,7 @@ checksum = "63db0adcff29d220c3d151c5b25c0eabe7e32dd936212b84cdaa1392e3130497" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13025,7 +12975,7 @@ checksum = "f486687bfb7b5c560868f69ed2d458b880cebc9babebcb67e49f31b55c5bf847" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13048,7 +12998,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13064,9 +13014,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.110" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -13108,7 +13058,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13466,7 +13416,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13477,7 +13427,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13695,7 +13645,7 @@ dependencies = [ "io-uring", "libc", "mio 1.1.0", - "parking_lot 0.12.5", + "parking_lot", "pin-project-lite", "signal-hook-registry", "slab", @@ -13723,7 +13673,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13760,7 +13710,7 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot 0.12.5", + "parking_lot", "percent-encoding", "phf 0.11.3", "pin-project-lite", @@ -13786,7 +13736,7 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot 0.12.5", + "parking_lot", "percent-encoding", "phf 0.11.3", "pin-project-lite", @@ -13919,7 +13869,7 @@ dependencies = [ "bytes", "futures-core", "futures-sink", - "http 1.3.1", + "http 1.4.0", "httparse", "rand 0.8.5", "ring 0.17.14", @@ -13982,7 +13932,7 @@ dependencies = [ "indexmap 2.11.1", "toml_datetime 0.7.0", "toml_parser", - "winnow 0.7.13", + "winnow 0.7.14", ] [[package]] @@ -13991,7 +13941,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "winnow 0.7.13", + "winnow 0.7.14", ] [[package]] @@ -14007,7 +13957,7 @@ dependencies = [ "bytes", "flate2", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -14076,8 +14026,8 @@ dependencies = [ "axum-core", "cookie 0.18.1", "futures-util", - "http 1.3.1", - "parking_lot 0.12.5", + "http 1.4.0", + "parking_lot", "pin-project-lite", "tower-layer", "tower-service", @@ -14085,9 +14035,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" dependencies = [ "async-compression", "base64 0.22.1", @@ -14095,7 +14045,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "iri-string", @@ -14135,32 +14085,32 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" dependencies = [ "crossbeam-channel", - "thiserror 1.0.69", + "thiserror 2.0.17", "time", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" dependencies = [ "once_cell", "valuable", @@ -14340,7 +14290,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.3.1", + "http 1.4.0", "httparse", "log", "native-tls", @@ -14406,7 +14356,7 @@ checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -14721,9 +14671,9 @@ checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" [[package]] name = "utf8-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" [[package]] name = "utf8_iter" @@ -14889,7 +14839,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "wasm-bindgen-shared", ] @@ -14924,7 +14874,7 @@ checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -14959,7 +14909,7 @@ checksum = "a369369e4360c2884c3168d22bded735c43cccae97bbc147586d4b480edd138d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -14975,21 +14925,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wasm_dep_analyzer" version = "0.2.0" @@ -15000,6 +14935,20 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "wasmtimer" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "web-sys" version = "0.3.80" @@ -15072,7 +15021,7 @@ dependencies = [ "log", "naga", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "profiling", "raw-window-handle", "ron", @@ -15114,7 +15063,7 @@ dependencies = [ "ndk-sys", "objc", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "profiling", "range-alloc", "raw-window-handle", @@ -15213,7 +15162,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "aws-sdk-config", @@ -15275,7 +15224,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "argon2", @@ -15317,7 +15266,7 @@ dependencies = [ "hex", "hf-hub", "hmac", - "http 1.3.1", + "http 1.4.0", "hyper 1.8.1", "indexmap 2.11.1", "itertools 0.14.0", @@ -15396,7 +15345,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.582.2" +version = "1.585.1" dependencies = [ "base64 0.22.1", "chrono", @@ -15411,7 +15360,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.582.2" +version = "1.585.1" dependencies = [ "chrono", "lazy_static", @@ -15425,7 +15374,7 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "axum", @@ -15444,7 +15393,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "async-recursion", @@ -15534,7 +15483,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.582.2" +version = "1.585.1" dependencies = [ "regex", "serde", @@ -15549,7 +15498,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "bytes", @@ -15573,19 +15522,19 @@ dependencies = [ [[package]] name = "windmill-macros" -version = "1.582.2" +version = "1.585.1" dependencies = [ "itertools 0.14.0", "lazy_static", "proc-macro2", "quote", "regex", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] name = "windmill-parser" -version = "1.582.2" +version = "1.585.1" dependencies = [ "convert_case 0.6.0", "serde", @@ -15594,7 +15543,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15606,7 +15555,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "serde_json", @@ -15618,7 +15567,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "gosyn", @@ -15630,7 +15579,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15642,7 +15591,7 @@ dependencies = [ [[package]] name = "windmill-parser-java" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "serde_json", @@ -15654,7 +15603,7 @@ dependencies = [ [[package]] name = "windmill-parser-nu" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "nu-parser", @@ -15665,7 +15614,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15676,7 +15625,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15688,7 +15637,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "async-recursion", @@ -15711,7 +15660,7 @@ dependencies = [ [[package]] name = "windmill-parser-ruby" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15725,7 +15674,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -15735,14 +15684,14 @@ dependencies = [ "quote", "regex", "serde_json", - "syn 2.0.110", + "syn 2.0.111", "toml", "windmill-parser", ] [[package]] name = "windmill-parser-sql" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15756,7 +15705,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15774,7 +15723,7 @@ dependencies = [ [[package]] name = "windmill-parser-wasm" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "getrandom 0.2.16", @@ -15799,7 +15748,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "serde", @@ -15810,7 +15759,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "async-recursion", @@ -15847,7 +15796,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.582.2" +version = "1.585.1" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -15857,7 +15806,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.582.2" +version = "1.585.1" dependencies = [ "anyhow", "async-once-cell", @@ -16073,7 +16022,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16084,7 +16033,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16095,7 +16044,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16106,7 +16055,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16117,7 +16066,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16128,7 +16077,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16480,9 +16429,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -16636,7 +16585,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "synstructure 0.13.2", ] @@ -16648,28 +16597,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "synstructure 0.13.2", ] [[package]] name = "zerocopy" -version = "0.8.28" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90" +checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.28" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26" +checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16689,7 +16638,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "synstructure 0.13.2", ] @@ -16710,7 +16659,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16743,7 +16692,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 4d35f7f8bf..fb05b41b6d 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.582.2" +version = "1.585.1" authors.workspace = true edition.workspace = true @@ -34,7 +34,7 @@ members = [ exclude = ["./windmill-duckdb-ffi-internal"] [workspace.package] -version = "1.582.2" +version = "1.585.1" authors = ["Ruben Fiszel "] edition = "2021" diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 5e8cbdea21..2a3de2d939 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -c90bfc11c7c643b2c8c5111f092e7ae142318e9d \ No newline at end of file +99828e4a3a27af428a45d1e6e65092ca15082b1e diff --git a/backend/parsers/windmill-parser-wasm/build.nu b/backend/parsers/windmill-parser-wasm/build.nu index 7c3bf9d4a6..d954366113 100755 --- a/backend/parsers/windmill-parser-wasm/build.nu +++ b/backend/parsers/windmill-parser-wasm/build.nu @@ -65,15 +65,19 @@ const targets = [ # -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort # Build all separately -def 'main all' [ --no-opt(-n), --cli] { +def 'main all' [ --no-opt(-n), --cli, --node ] { if ($no_opt) { - if ($cli) { + if ($node) { + $targets | each { main $in.ident -n --node } + } else if ($cli) { $targets | each { main $in.ident -n --cli } } else { $targets | each { main $in.ident -n } } } else { - if ($cli) { + if ($node) { + $targets | each { main $in.ident --node } + } else if ($cli) { $targets | each { main $in.ident --cli } } else { $targets | each { main $in.ident } @@ -86,6 +90,7 @@ def main [ target: string, # Language, e.g.: py, ts, rust --no-opt(-n), # Compile in debug mode for dev --cli # Compile and place binaries in cli. + --node ] { let t = $targets | where ident == $target; @@ -97,7 +102,10 @@ def main [ mut profile = ""; mut tar = ""; - if ($cli) { + if ($node) { + $env.OUT_DIR = $"node-pkg-($t.ident)" + $tar = "nodejs" + } else if ($cli) { $env.OUT_DIR = $"../../../cli/wasm/($t.ident)" $tar = "deno" } else { diff --git a/backend/src/monitor.rs b/backend/src/monitor.rs index eaf83c2e4c..d85f5f3d58 100644 --- a/backend/src/monitor.rs +++ b/backend/src/monitor.rs @@ -2316,13 +2316,14 @@ async fn handle_zombie_jobs(db: &Pool, base_internal_url: &str, node_n ); let error_message = format!( - "Job timed out after no ping from job since {} (ZOMBIE_JOB_TIMEOUT: {}, reason: {:?}).\nThis likely means that the job died on worker {}, OOM are a common reason for worker crashes.\nCheck the workers around the time of the last ping and the exit code if any.", - job.last_ping.unwrap_or_default(), - *ZOMBIE_JOB_TIMEOUT, - error_kind.to_string(), - job.worker.clone().unwrap_or_default(), - ); + "Job timed out after no ping from job since {} (ZOMBIE_JOB_TIMEOUT: {}, reason: {:?}).\nThis likely means that the job died on worker {}, OOM are a common reason for worker crashes.\nCheck the workers around the time of the last ping and the exit code if any.", + job.last_ping.unwrap_or_default(), + *ZOMBIE_JOB_TIMEOUT, + error_kind.to_string(), + job.worker.clone().unwrap_or_default(), + ); let memory_peak = job.memory_peak.unwrap_or(0); + let (_, killpill_rx_never_used) = KillpillSender::new(1); let _ = handle_job_error( db, &client, @@ -2335,6 +2336,7 @@ async fn handle_zombie_jobs(db: &Pool, base_internal_url: &str, node_n "", node_name, send_result_never_used, + &killpill_rx_never_used, #[cfg(feature = "benchmark")] &mut windmill_common::bench::BenchmarkIter::new(), ) diff --git a/backend/tests/worker.rs b/backend/tests/worker.rs index 0a92dfc74d..bb18d6e397 100644 --- a/backend/tests/worker.rs +++ b/backend/tests/worker.rs @@ -217,6 +217,7 @@ async fn test_deno_flow(db: Pool) -> anyhow::Result<()> { iterator: InputTransform::Javascript { expr: "result".to_string() }, skip_failures: false, parallel: false, + squash: None, parallelism: None, modules: vec![FlowModule { id: "c".to_string(), @@ -396,6 +397,7 @@ async fn test_deno_flow_same_worker(db: Pool) -> anyhow::Result<()> { iterator: InputTransform::Static { value: windmill_common::worker::to_raw_value(&[1, 2, 3]) }, skip_failures: false, parallel: false, + squash: None, parallelism: None, modules: vec![ FlowModule { diff --git a/backend/update_sqlx.sh b/backend/update_sqlx.sh index 5425706876..669aa90dc9 100755 --- a/backend/update_sqlx.sh +++ b/backend/update_sqlx.sh @@ -2,15 +2,6 @@ set -e -# Parse arguments -while [[ "$#" -gt 0 ]]; do - case $1 in - --dir) EE_DIR="$2"; shift ;; - *) echo "Unknown parameter: $1"; exit 1 ;; - esac - shift -done - # Check if running on macOS if [[ "$(uname)" == "Darwin" ]]; then echo "Running on macOS - substituting samael..." diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index dbb61e7722..30c6b4b6ed 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.582.2 + version: 1.585.1 title: Windmill API contact: @@ -688,6 +688,22 @@ paths: schema: $ref: "#/components/schemas/UserWorkspaceList" + /w/{workspace}/workspaces/get_as_superadmin: + get: + summary: get workspace as super admin (require to be super admin) + operationId: getWorkspaceAsSuperAdmin + tags: + - workspace + parameters: + - $ref: "#/components/parameters/WorkspaceId" + responses: + "200": + description: workspace + content: + application/json: + schema: + $ref: "#/components/schemas/Workspace" + /workspaces/list_as_superadmin: get: summary: list all workspaces as super admin (require to be super admin) @@ -5217,6 +5233,14 @@ paths: Accepts multiple values as a comma-separated list. schema: type: string + - name: without_description + in: query + description: | + (default false) + If true, the description field will be omitted from the response. + schema: + type: boolean + responses: "200": description: All scripts @@ -6500,6 +6524,13 @@ paths: in: query schema: type: boolean + - name: without_description + in: query + description: | + (default false) + If true, the description field will be omitted from the response. + schema: + type: boolean responses: "200": description: All flow @@ -7729,6 +7760,9 @@ paths: type: array items: type: string + run_query_params: + type: object + description: Runnable query parameters required: - args - component @@ -12059,32 +12093,32 @@ paths: schema: type: boolean /w/{workspace}/email_triggers/setenabled/{path}: - post: - summary: enable/disable email trigger - operationId: setEmailTriggerEnabled - tags: - - email_trigger - parameters: - - $ref: "#/components/parameters/WorkspaceId" - - $ref: "#/components/parameters/Path" - requestBody: - required: true + post: + summary: enable/disable email trigger + operationId: setEmailTriggerEnabled + tags: + - email_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + "200": + description: email trigger enable/disable content: - application/json: + text/plain: schema: - type: object - properties: - enabled: - type: boolean - required: - - enabled - responses: - "200": - description: email trigger enable/disable - content: - text/plain: - schema: - type: string + type: string /groups/list: get: diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs index c7b1bd18bc..4849824b0a 100644 --- a/backend/windmill-api/src/apps.rs +++ b/backend/windmill-api/src/apps.rs @@ -10,6 +10,7 @@ use std::{collections::HashMap, sync::Arc}; use crate::{ auth::OptTokened, db::{ApiAuthed, DB}, + jobs::RunJobQuery, resources::get_resource_value_interpolated_internal, users::{require_owner_of_path, OptAuthed}, utils::{check_scopes, WithStarredInfoQuery}, @@ -1654,6 +1655,8 @@ pub struct ExecuteApp { pub force_viewer_static_fields: Option, pub force_viewer_one_of_fields: Option, pub force_viewer_allow_user_resources: Option, + /// Runnable query parameters (e.g., memory_id for chat-enabled flows) + pub run_query_params: Option, } fn digest(code: &str) -> String { @@ -1894,6 +1897,12 @@ async fn execute_component( ) .await?; + let is_flow = payload + .path + .as_ref() + .map(|p| p.starts_with("flow/")) + .unwrap_or(false); + let (job_payload, tag, on_behalf_of) = match (payload.path, payload.raw_code, payload.id) { // flow or script: (Some(path), None, None) => get_payload_tag_from_prefixed_path(&path, &db, &w_id).await?, @@ -1920,7 +1929,7 @@ async fn execute_component( let end_user_email = opt_authed.as_ref().map(|a| a.email.clone()); - let (uuid, tx) = push( + let (uuid, mut tx) = push( &db, tx, &w_id, @@ -1954,6 +1963,14 @@ async fn execute_component( None, ) .await?; + + // Apply runnable query parameters if provided + if let Some(ref run_query) = payload.run_query_params { + if is_flow { + crate::jobs::process_flow_run_query_params(&mut tx, uuid, run_query).await?; + } + } + tx.commit().await?; Ok(uuid.to_string()) diff --git a/backend/windmill-api/src/flow_conversations.rs b/backend/windmill-api/src/flow_conversations.rs index 0cbdb7aa55..4854615c18 100644 --- a/backend/windmill-api/src/flow_conversations.rs +++ b/backend/windmill-api/src/flow_conversations.rs @@ -134,6 +134,7 @@ pub async fn get_or_create_conversation_with_id( } else { title.to_string() }; + // Create new conversation with provided ID let conversation = sqlx::query_as!( FlowConversation, @@ -148,6 +149,7 @@ pub async fn get_or_create_conversation_with_id( ) .fetch_one(&mut **tx) .await?; + Ok(conversation) } diff --git a/backend/windmill-api/src/flows.rs b/backend/windmill-api/src/flows.rs index a2e8e307e6..98130e2d2d 100644 --- a/backend/windmill-api/src/flows.rs +++ b/backend/windmill-api/src/flows.rs @@ -133,7 +133,11 @@ async fn list_flows( "o.workspace_id", "o.path", "summary", - "description", + if !lq.without_description.unwrap_or(false) { + "description" + } else { + "NULL as description" + }, "fv.created_by as edited_by", "fv.created_at as edited_at", "archived", @@ -1579,6 +1583,7 @@ mod tests { skip_failures: true, parallel: false, parallelism: None, + squash: None, }), stop_after_if: Some(StopAfterIf { expr: "previous.isEmpty()".to_string(), diff --git a/backend/windmill-api/src/folders.rs b/backend/windmill-api/src/folders.rs index 9cf3c9af2b..86bc5ce7c6 100644 --- a/backend/windmill-api/src/folders.rs +++ b/backend/windmill-api/src/folders.rs @@ -96,7 +96,7 @@ async fn list_folders( let rows = sqlx::query_as!( Folder, - "SELECT workspace_id, name, display_name, owners, extra_perms, summary, created_by, edited_at FROM folder WHERE workspace_id = $1 ORDER BY name desc LIMIT $2 OFFSET $3", + "SELECT workspace_id, name, display_name, owners, extra_perms, summary, created_by, edited_at FROM folder WHERE workspace_id = $1 ORDER BY name asc LIMIT $2 OFFSET $3", w_id, per_page as i64, offset as i64 @@ -117,7 +117,7 @@ async fn list_foldernames( let mut tx = user_db.begin(&authed).await?; let rows = sqlx::query_scalar!( - "SELECT name FROM folder WHERE workspace_id = $1 ORDER BY name desc LIMIT $2 OFFSET $3", + "SELECT name FROM folder WHERE workspace_id = $1 ORDER BY name asc LIMIT $2 OFFSET $3", w_id, per_page as i64, offset as i64 diff --git a/backend/windmill-api/src/groups.rs b/backend/windmill-api/src/groups.rs index 4325a7c9c5..4a53ad838b 100644 --- a/backend/windmill-api/src/groups.rs +++ b/backend/windmill-api/src/groups.rs @@ -103,7 +103,7 @@ async fn list_groups( let rows = sqlx::query_as!( Group, - "SELECT * FROM group_ WHERE workspace_id = $1 ORDER BY name desc LIMIT $2 OFFSET $3", + "SELECT * FROM group_ WHERE workspace_id = $1 ORDER BY name asc LIMIT $2 OFFSET $3", w_id, per_page as i64, offset as i64 @@ -126,7 +126,7 @@ async fn list_group_names( ) -> JsonResult> { let rows = if !only_member_of.unwrap_or(false) { sqlx::query_scalar!( - "SELECT name FROM group_ WHERE workspace_id = $1 UNION SELECT name FROM instance_group ORDER BY name desc", + "SELECT name FROM group_ WHERE workspace_id = $1 UNION SELECT name FROM instance_group ORDER BY name asc", w_id ) .fetch_all(&db) diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index c1aa63482d..e425ec8a5c 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -1743,7 +1743,7 @@ pub struct ListableCompletedJob { pub labels: Option, } -#[derive(Deserialize, Clone, Default)] +#[derive(Debug, Deserialize, Clone, Default)] pub struct RunJobQuery { pub scheduled_for: Option>, pub scheduled_in_secs: Option, @@ -3957,7 +3957,7 @@ async fn set_flow_memory_id( memory_id: Uuid, ) -> error::Result<()> { sqlx::query!( - "UPDATE v2_job_status + "UPDATE v2_job_status SET flow_status = jsonb_set( flow_status, '{memory_id}', @@ -3972,6 +3972,19 @@ async fn set_flow_memory_id( Ok(()) } +/// Apply flow-specific query parameters after job creation +pub async fn process_flow_run_query_params( + tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, + job_id: Uuid, + run_query: &RunJobQuery, +) -> error::Result<()> { + // Set memory_id if provided (for agent memory) + if let Some(memory_id) = run_query.memory_id { + set_flow_memory_id(tx, job_id, memory_id).await?; + } + Ok(()) +} + async fn handle_chat_conversation_messages( tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, authed: &ApiAuthed, diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index 82c8864fe3..d5d3e654a9 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -41,11 +41,11 @@ use windmill_audit::ActionKind; use windmill_worker::{process_relative_imports, scoped_dependency_map::ScopedDependencyMap}; use windmill_common::{ - assets::{clear_asset_usage, insert_asset_usage, AssetUsageKind, AssetWithAltAccessType}, + assets::{AssetUsageKind, AssetWithAltAccessType, clear_asset_usage, insert_asset_usage}, error::to_anyhow, s3_helpers::upload_artifact_to_store, scripts::hash_script, - utils::WarnAfterExt, + utils::{WarnAfterExt, paginate_without_limits}, worker::{CLOUD_HOSTED, MIN_VERSION_SUPPORTS_DEBOUNCING}, }; @@ -61,7 +61,7 @@ use windmill_common::{ }, users::username_to_permissioned_as, utils::{ - not_found_if_none, paginate, query_elems_from_hub, require_admin, Pagination, StripPath, + not_found_if_none, query_elems_from_hub, require_admin, Pagination, StripPath, }, worker::to_raw_value, HUB_BASE_URL, @@ -193,7 +193,7 @@ async fn list_search_scripts( ) -> JsonResult> { let mut tx = user_db.begin(&authed).await?; #[cfg(feature = "enterprise")] - let n = 1000; + let n = 10000; #[cfg(not(feature = "enterprise"))] let n = 10; @@ -219,7 +219,7 @@ async fn list_scripts( Query(pagination): Query, Query(lq): Query, ) -> JsonResult> { - let (per_page, offset) = paginate(pagination); + let (per_page, offset) = paginate_without_limits(pagination); let mut sqlb = SqlBuilder::select_from("script as o") .fields(&[ "hash", @@ -228,6 +228,11 @@ async fn list_scripts( "COALESCE(draft.created_at, o.created_at) as created_at", "archived", "extra_perms", + if !lq.without_description.unwrap_or(false) { + "description" + } else { + "NULL as description" + }, "CASE WHEN lock_error_logs IS NOT NULL THEN true ELSE false END as has_deploy_errors", "language", "favorite.path IS NOT NULL as starred", diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index b956a7b295..14d83a132c 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -75,6 +75,7 @@ lazy_static::lazy_static! { pub fn workspaced_service() -> Router { let router = Router::new() + .route("/get_as_superadmin", get(get_workspace_as_superadmin)) .route("/list_pending_invites", get(list_pending_invites)) .route("/update", post(edit_workspace)) .route("/archive", post(archive_workspace)) @@ -2342,6 +2343,35 @@ async fn get_used_triggers( Ok(Json(websocket_used)) } +async fn get_workspace_as_superadmin( + authed: ApiAuthed, + Extension(db): Extension, + Path(w_id): Path, +) -> JsonResult { + require_super_admin(&db, &authed.email).await?; + let workspace = sqlx::query_as!( + Workspace, + "SELECT + workspace.id AS \"id!\", + workspace.name AS \"name!\", + workspace.owner AS \"owner!\", + workspace.deleted AS \"deleted!\", + workspace.premium AS \"premium!\", + workspace_settings.color AS \"color\", + workspace.parent_workspace_id AS \"parent_workspace_id\" + FROM workspace + LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id + WHERE workspace.id = $1", + w_id + ) + .fetch_optional(&db) + .await?; + + let workspace = not_found_if_none(workspace, "workspace", w_id)?; + + Ok(Json(workspace)) +} + async fn list_workspaces_as_super_admin( authed: ApiAuthed, Extension(db): Extension, @@ -2425,6 +2455,13 @@ lazy_static::lazy_static! { } }; + pub static ref DISABLE_WORKSPACE_FORK: bool = { + match std::env::var("DISABLE_WORKSPACE_FORK") { + Ok(val) => val == "true", + Err(_) => false, + } + }; + } async fn create_workspace_require_superadmin() -> String { @@ -2681,9 +2718,14 @@ async fn update_workspace_settings( WorkspaceGitSyncSettings::default() }; - // We only keep the first git sync repo, since it is considered the main one + // We only keep the first git sync repo that is sync mode (use_individual_branch = false), since it is considered the main one // Context: see WIN-1559 - git_sync_settings.repositories.truncate(1); + git_sync_settings.repositories = git_sync_settings + .repositories + .into_iter() + .filter(|r| !r.use_individual_branch.unwrap_or(false)) + .take(1) + .collect(); let serialized_config = serde_json::to_value::(git_sync_settings) .map_err(|err| Error::internal_err(err.to_string()))?; @@ -2753,6 +2795,17 @@ async fn clone_groups( .execute(&mut **tx) .await?; + sqlx::query!( + "INSERT INTO usr_to_group (workspace_id, group_, usr) + SELECT $2, group_, usr + FROM usr_to_group + WHERE workspace_id = $1", + source_workspace_id, + target_workspace_id, + ) + .execute(&mut **tx) + .await?; + Ok(()) } @@ -3123,6 +3176,10 @@ async fn create_workspace_fork_branch( ))); } + if *DISABLE_WORKSPACE_FORK { + require_super_admin(&db, &authed.email).await?; + } + Ok(Json( handle_fork_branch_creation(&authed.email, &authed.username, &db, &w_id, &nw.id).await?, )) @@ -3140,6 +3197,10 @@ async fn create_workspace_fork( ))); } + if *DISABLE_WORKSPACE_FORK { + require_super_admin(&db, &authed.email).await?; + } + let mut tx: Transaction<'_, Postgres> = db.begin().await?; // Generate unique forked workspace ID with wm-fork prefix diff --git a/backend/windmill-common/src/flow_conversations.rs b/backend/windmill-common/src/flow_conversations.rs index 8826f85b94..472c9c264c 100644 --- a/backend/windmill-common/src/flow_conversations.rs +++ b/backend/windmill-common/src/flow_conversations.rs @@ -15,6 +15,8 @@ pub enum MessageType { } /// Add a message to a conversation using an existing transaction +/// If the conversation doesn't exist, logs a warning and returns Ok (no error thrown) +/// This allows memory_id to be used for agent memory without requiring a conversation pub async fn add_message_to_conversation_tx( tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, conversation_id: Uuid, @@ -24,6 +26,23 @@ pub async fn add_message_to_conversation_tx( step_name: Option<&str>, success: bool, ) -> Result<()> { + // Check if conversation exists first + let conversation_exists = sqlx::query!( + "SELECT EXISTS(SELECT 1 FROM flow_conversation WHERE id = $1) as \"exists!\"", + conversation_id + ) + .fetch_one(&mut **tx) + .await? + .exists; + + if !conversation_exists { + tracing::warn!( + "Conversation {} does not exist. Skipping message insertion. This is expected when flows are called from apps (memory_id is used for agent memory only).", + conversation_id + ); + return Ok(()); + } + // Insert the message sqlx::query!( "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id, step_name, success) diff --git a/backend/windmill-common/src/flows.rs b/backend/windmill-common/src/flows.rs index 27044c1dd3..104f99b301 100644 --- a/backend/windmill-common/src/flows.rs +++ b/backend/windmill-common/src/flows.rs @@ -78,7 +78,8 @@ pub struct ListableFlow { pub workspace_id: String, pub path: String, pub summary: String, - pub description: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, pub edited_by: Option, pub edited_at: Option>, pub archived: bool, @@ -868,6 +869,8 @@ pub enum FlowModuleValue { parallel: bool, #[serde(skip_serializing_if = "Option::is_none")] parallelism: Option, + #[serde(skip_serializing_if = "Option::is_none")] + squash: Option, }, /// While loop node @@ -877,6 +880,8 @@ pub enum FlowModuleValue { modules_node: Option, #[serde(default = "default_false")] skip_failures: bool, + #[serde(skip_serializing_if = "Option::is_none")] + squash: Option, }, /// Branch-one node @@ -988,6 +993,7 @@ struct UntaggedFlowModuleValue { assets: Option>, tools: Option>, pass_flow_input_directly: Option, + squash: Option, } impl<'de> Deserialize<'de> for FlowModuleValue { @@ -1026,6 +1032,7 @@ impl<'de> Deserialize<'de> for FlowModuleValue { skip_failures: untagged.skip_failures.unwrap_or(true), parallel: untagged.parallel.unwrap_or(false), parallelism: untagged.parallelism, + squash: untagged.squash, }), "whileloopflow" => Ok(FlowModuleValue::WhileloopFlow { modules: untagged @@ -1033,6 +1040,7 @@ impl<'de> Deserialize<'de> for FlowModuleValue { .ok_or_else(|| serde::de::Error::missing_field("modules"))?, modules_node: untagged.modules_node, skip_failures: untagged.skip_failures.unwrap_or(false), + squash: untagged.squash, }), "branchone" => Ok(FlowModuleValue::BranchOne { branches: untagged @@ -1122,6 +1130,7 @@ where #[derive(Deserialize)] pub struct ListFlowQuery { + pub without_description: Option, pub path_start: Option, pub path_exact: Option, pub edited_by: Option, diff --git a/backend/windmill-common/src/scripts.rs b/backend/windmill-common/src/scripts.rs index 11d6758caa..a5ba95f93b 100644 --- a/backend/windmill-common/src/scripts.rs +++ b/backend/windmill-common/src/scripts.rs @@ -353,6 +353,8 @@ pub struct ListableScript { pub starred: bool, pub tag: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub has_draft: Option, #[serde(skip_serializing_if = "Option::is_none")] pub draft_only: Option, @@ -492,6 +494,7 @@ where #[derive(Debug, Deserialize)] pub struct ListScriptQuery { + pub without_description: Option, pub path_start: Option, pub path_exact: Option, pub created_by: Option, diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index c050d56659..cc29b94f1b 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -24,6 +24,9 @@ use serde::{ser::SerializeMap, Serialize}; use serde_json::{json, value::RawValue}; use sqlx::{types::Json, Pool, Postgres, Transaction}; use sqlx::{Encode, PgExecutor}; +use tokio::sync::mpsc::Sender; +use tokio::sync::oneshot; +use tokio::task::JoinHandle; use tokio::{sync::RwLock, time::sleep}; use ulid::Ulid; use uuid::Uuid; @@ -137,7 +140,7 @@ pub struct CanceledBy { pub reason: Option, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct JobCompleted { pub job: MiniCompletedJob, pub preprocessed_args: Option>>, @@ -151,6 +154,10 @@ pub struct JobCompleted { pub duration: Option, pub has_stream: Option, pub from_cache: Option, + #[serde(skip)] + pub flow_runners: Option>, + #[serde(skip)] + pub done_tx: Option>, } pub async fn cancel_single_job<'c>( @@ -2271,6 +2278,8 @@ pub struct JobAndPerms { pub parent_runnable_path: Option, pub token: String, pub precomputed_agent_info: Option, + #[serde(skip)] + pub flow_runners: Option>, } impl PulledJob { pub async fn get_job_and_perms(self, db: &DB) -> JobAndPerms { @@ -2302,6 +2311,7 @@ impl PulledJob { parent_runnable_path: self.parent_runnable_path, token, precomputed_agent_info: None, + flow_runners: None, } } } @@ -2492,6 +2502,8 @@ impl PulledJobResult { duration: None, has_stream: Some(false), from_cache: None, + flow_runners: None, + done_tx: None, }), ), PulledJobResult { job: Some(job), error_while_preprocessing: Some(e), .. } => Err( @@ -2511,6 +2523,8 @@ impl PulledJobResult { duration: None, has_stream: Some(false), from_cache: None, + flow_runners: None, + done_tx: None, }), ), PulledJobResult { job, .. } => Ok(job), @@ -5715,10 +5729,74 @@ async fn restarted_flows_resolution( )) } + + +// Wrapper struct to send both job and optional flow_runners to dedicated workers +pub struct DedicatedWorkerJob { + pub job: Arc, + pub flow_runners: Option>, + pub done_tx: Option>, +} + +#[derive(Debug)] +pub struct FlowRunners { + pub runners: HashMap>, + pub handles: Vec>, + pub job_id: Uuid, +} + +impl Drop for FlowRunners { + fn drop(&mut self) { + let total_runners = self.handles.len(); + tracing::info!("dropping {} flow runners for job {}", total_runners, self.job_id); + + // First, drop all senders to signal workers to stop gracefully + self.runners.clear(); + + // Spawn a background task to wait with timeout and abort if needed + let handles = std::mem::take(&mut self.handles); + let job_id = self.job_id; + + tokio::spawn(async move { + // Extract abort handles before consuming the join handles + let abort_handles: Vec<_> = handles.iter().map(|h| h.abort_handle()).collect(); + + // Wait up to 5 seconds for natural termination + let timeout_result = tokio::time::timeout( + tokio::time::Duration::from_secs(5), + futures::future::join_all(handles) + ).await; + + match timeout_result { + Ok(_) => { + tracing::info!("all {} flow runners for job {} terminated gracefully", total_runners, job_id); + } + Err(_) => { + // Timeout reached, abort only the handles that haven't finished + let mut aborted = 0; + for abort_handle in abort_handles { + if !abort_handle.is_finished() { + abort_handle.abort(); + aborted += 1; + } + } + let graceful = total_runners - aborted; + tracing::warn!( + "flow runners for job {}: {} terminated gracefully, {} aborted after 5s timeout", + job_id, graceful, aborted + ); + } + } + }); + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct SameWorkerPayload { pub job_id: Uuid, pub recoverable: bool, + #[serde(skip)] + pub flow_runners: Option>, } pub async fn get_same_worker_job( diff --git a/backend/windmill-queue/src/lib.rs b/backend/windmill-queue/src/lib.rs index 3ea2e2c1aa..ffd102c081 100644 --- a/backend/windmill-queue/src/lib.rs +++ b/backend/windmill-queue/src/lib.rs @@ -6,7 +6,7 @@ * LICENSE-AGPL for a copy of the license. */ -mod jobs; +pub mod jobs; #[cfg(feature = "private")] pub mod jobs_ee; pub mod jobs_oss; diff --git a/backend/windmill-worker/loader_builder.bun.js b/backend/windmill-worker/loader_builder.bun.js index 2bf0b749f2..d6d43fac54 100644 --- a/backend/windmill-worker/loader_builder.bun.js +++ b/backend/windmill-worker/loader_builder.bun.js @@ -17,7 +17,7 @@ const captureVersion = /^((?:\@[^\/\@]+\/[^\/\@]+)|(?:[^\/\@]+))(?:\@([^\/]+))?.*$/; import { semver } from "bun"; - +import { isBuiltin } from "module"; let content = await fs.readFile("./out/main.js", { encoding: "utf8" }); const imports = new Bun.Transpiler().scanImports( content.replaceAll("__require", "require") @@ -29,7 +29,7 @@ for (const i of imports) { if (name == undefined) { throw Error("Unrecognized import: " + i.path); } - if (name.startsWith("node:")) { + if (isBuiltin(name)) { continue; } let splitted = name.split("/"); diff --git a/backend/windmill-worker/src/ai/tools.rs b/backend/windmill-worker/src/ai/tools.rs index 478eca5e54..84304f232c 100644 --- a/backend/windmill-worker/src/ai/tools.rs +++ b/backend/windmill-worker/src/ai/tools.rs @@ -529,6 +529,7 @@ async fn execute_windmill_tool( &mut occupancy_metrics_spawn, &mut killpill_rx_spawn, None, + None, #[cfg(feature = "benchmark")] &mut bench_spawn, ) @@ -656,8 +657,9 @@ async fn handle_tool_execution_success( .. }) = send_result.as_ref() { + let result = result.clone(); ctx.job_completed_tx - .send(send_result.as_ref().unwrap().result.clone(), true) + .send(send_result.unwrap().result, true) .await .map_err(to_anyhow)?; result diff --git a/backend/windmill-worker/src/bun_executor.rs b/backend/windmill-worker/src/bun_executor.rs index b8723ad815..26c59b77ba 100644 --- a/backend/windmill-worker/src/bun_executor.rs +++ b/backend/windmill-worker/src/bun_executor.rs @@ -9,10 +9,8 @@ use serde_json::value::RawValue; use uuid::Uuid; use windmill_parser_ts::remove_pinned_imports; -use windmill_queue::{append_logs, CanceledBy, MiniPulledJob, PrecomputedAgentInfo}; -#[cfg(feature = "enterprise")] -use crate::common::build_envs_map; +use windmill_queue::{append_logs, CanceledBy, MiniPulledJob, PrecomputedAgentInfo}; use crate::{ common::{ @@ -38,12 +36,6 @@ use tokio::{fs::File, process::Command}; use tokio::io::AsyncReadExt; -#[cfg(feature = "enterprise")] -use tokio::sync::mpsc::Receiver; - -#[cfg(feature = "enterprise")] -use windmill_common::variables; - use windmill_common::{ error::{self, Result}, get_latest_hash_for_path, @@ -1567,10 +1559,18 @@ pub async fn get_common_bun_proc_envs(base_internal_url: Option<&str>) -> HashMa return bun_envs; } -#[cfg(feature = "enterprise")] -use crate::{dedicated_worker::handle_dedicated_process, JobCompletedSender}; +#[cfg(feature = "private")] +use crate::{ + common::build_envs_map, dedicated_worker_oss::handle_dedicated_process, JobCompletedSender, +}; +#[cfg(feature = "private")] +use tokio::sync::mpsc::Receiver; +#[cfg(feature = "private")] +use windmill_common::variables; +#[cfg(feature = "private")] +use windmill_queue::DedicatedWorkerJob; -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] pub async fn start_worker( requirements_o: Option, codebase: Option, @@ -1584,8 +1584,9 @@ pub async fn start_worker( script_path: &str, token: &str, job_completed_tx: JobCompletedSender, - jobs_rx: Receiver>, + jobs_rx: Receiver, killpill_rx: tokio::sync::broadcast::Receiver<()>, + client: windmill_common::client::AuthedClient, ) -> Result<()> { let mut logs = "".to_string(); let mut mem_peak: i32 = 0; @@ -1737,6 +1738,12 @@ BigInt.prototype.toJSON = function () {{ console.log('start'); +function getArgs(line) {{ + let {{ {spread} }} = JSON.parse(line) + {dates} + return [ {spread} ]; +}} + for await (const line of Readline.createInterface({{ input: process.stdin }})) {{ {print_lines} @@ -1744,9 +1751,8 @@ for await (const line of Readline.createInterface({{ input: process.stdin }})) { process.exit(0); }} try {{ - let {{ {spread} }} = JSON.parse(line) - {dates} - let res = await Main.main(...[ {spread} ]); + const args = getArgs(line); + const res = await Main.main(...args); console.log("wm_res[success]:" + JSON.stringify(res ?? null, (key, value) => typeof value === 'undefined' ? null : value)); }} catch (e) {{ console.log("wm_res[error]:" + JSON.stringify({{ message: e.message, name: e.name, stack: e.stack, line: line }})); @@ -1812,6 +1818,7 @@ for await (const line of Readline.createInterface({{ input: process.stdin }})) { db, &script_path, "nodejs", + client, ) .await } else { @@ -1838,6 +1845,7 @@ for await (const line of Readline.createInterface({{ input: process.stdin }})) { db, script_path, "bun", + client, ) .await } diff --git a/backend/windmill-worker/src/dedicated_worker.rs b/backend/windmill-worker/src/dedicated_worker.rs deleted file mode 100644 index e65655c94d..0000000000 --- a/backend/windmill-worker/src/dedicated_worker.rs +++ /dev/null @@ -1,759 +0,0 @@ -// use tokio::sync::mpsc; - -// pub fn create_dedicated_worker() { -// let (job_completed_tx, mut new_job) = mpsc::channel::(100); -// } - -use async_recursion::async_recursion; -use std::{collections::VecDeque, process::Stdio, sync::Arc}; -use tokio::sync::mpsc::Sender; -use tokio::{ - io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, - process::Command, - task::JoinHandle, -}; -use windmill_common::error::Error; -use windmill_common::flows::FlowValue; -use windmill_common::worker::WORKER_CONFIG; -use windmill_common::KillpillSender; -use windmill_common::{ - cache, error, - flows::{FlowModule, FlowModuleValue}, - scripts::{ScriptHash, ScriptLang}, - variables, - worker::to_raw_value, - DB, -}; -use windmill_queue::append_logs; -use windmill_queue::MiniPulledJob; - -use anyhow::Context; - -use crate::{common::start_child_process, JobCompletedSender, MAX_BUFFERED_DEDICATED_JOBS}; - -use futures::{future, Future}; -use std::{collections::HashMap, task::Poll}; - -use tokio::sync::mpsc::Receiver; - -fn conditional_polling( - fut: impl Future, - predicate: bool, -) -> impl Future { - let mut fut = Box::pin(fut); - future::poll_fn(move |cx| { - if predicate { - fut.as_mut().poll(cx) - } else { - Poll::Pending - } - }) -} - -async fn write_stdin(stdin: &mut tokio::process::ChildStdin, s: &str) -> error::Result<()> { - let _ = &stdin.write_all(format!("{s}\n").as_bytes()).await?; - stdin.flush().await.context("stdin flush")?; - Ok(()) -} - -#[cfg(feature = "enterprise")] -pub async fn handle_dedicated_process( - command_path: &String, - job_dir: &str, - context_envs: HashMap, - envs: HashMap, - reserved_variables: Vec, - common_bun_proc_envs: HashMap, - args: Vec<&str>, - mut killpill_rx: tokio::sync::broadcast::Receiver<()>, - job_completed_tx: JobCompletedSender, - token: &str, - mut jobs_rx: Receiver>, - worker_name: &str, - db: &DB, - script_path: &str, - mode: &str, -) -> std::result::Result<(), error::Error> { - //do not cache local dependencies - - use windmill_queue::{JobCompleted, MiniCompletedJob}; - - use crate::{handle_child::process_status, PROXY_ENVS}; - let cmd_name = format!("dedicated {command_path}"); - let mut child = { - let mut cmd = Command::new(command_path); - cmd.current_dir(job_dir) - .env_clear() - .envs(context_envs) - .envs(envs) - .envs(PROXY_ENVS.clone()) - .envs( - reserved_variables - .iter() - .map(|x| (x.name.clone(), x.value.clone())) - .collect::>(), - ) - .envs(common_bun_proc_envs) - .args(args) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - start_child_process(cmd, command_path, false).await? - }; - - let stdout = child - .stdout() - .take() - .expect("child did not have a handle to stdout"); - - let stderr = child - .stderr() - .take() - .expect("child did not have a handle to stderr"); - - let mut reader = BufReader::new(stdout).lines(); - - let mut err_reader = BufReader::new(stderr).lines(); - - let mut stdin = child - .stdin() - .take() - .expect("child did not have a handle to stdin"); - - // Ensure the child process is spawned in the runtime so it can - // make progress on its own while we await for any output. - let child = tokio::spawn(async move { - let status = Box::into_pin(child.wait()) - .await - .expect("child process encountered an error"); - if let Err(e) = process_status(&cmd_name, status, vec![]) { - tracing::error!("child exit status was not success: {e:#}"); - } else { - tracing::info!("child exit status was success"); - } - }); - - let mut jobs: VecDeque = VecDeque::with_capacity(MAX_BUFFERED_DEDICATED_JOBS); - // let mut i = 0; - // let mut j = 0; - let mut alive = true; - - let init_log = format!("dedicated worker {mode}: {worker_name}\n\n"); - let mut logs = init_log.clone(); - loop { - tokio::select! { - biased; - _ = killpill_rx.recv(), if alive => { - println!("received killpill for dedicated worker"); - alive = false; - if let Err(e) = write_stdin(&mut stdin, "end").await { - tracing::info!("Could not write end message to stdin: {e:?}") - } - stdin.flush().await.context("stdin flush")?; - }, - line = err_reader.next_line() => { - if let Some(line) = line.expect("line is ok") { - tracing::error!("stderr dedicated worker: {line}"); - logs.push_str("[stderr] "); - logs.push_str(&line); - logs.push_str("\n"); - } else { - tracing::info!("dedicated worker process exited {script_path}"); - let mut last_stdout = "".to_string(); - while let Some(line) = reader.next_line().await.ok().flatten() { - last_stdout = line; - last_stdout.push_str("\n"); - } - tracing::info!("Last stdout for {script_path}: {last_stdout}"); - break; - } - }, - line = reader.next_line() => { - // j += 1; - - if let Some(line) = line.expect("line is ok") { - if line == "start" { - tracing::info!("dedicated worker process started {script_path}"); - continue; - } - tracing::debug!("processed job: |{line}|"); - if line.starts_with("wm_res[") { - let job = jobs.pop_front().expect("pop"); - tracing::info!("job completed on dedicated worker {script_path}: {}", job.id); - match serde_json::from_str::>(&line.replace("wm_res[success]:", "").replace("wm_res[error]:", "")) { - Ok(result) => { - let result = Arc::new(result); - append_logs(&job.id, &job.workspace_id, logs.clone(), &db.into()).await; - if line.starts_with("wm_res[success]:") { - job_completed_tx.send_job(JobCompleted { job , result, result_columns: None, mem_peak: 0, canceled_by: None, success: true, cached_res_path: None, token: token.to_string(), duration: None, preprocessed_args: None, has_stream: Some(false), from_cache: None }, true).await.unwrap() - } else { - job_completed_tx.send_job(JobCompleted { job , result, result_columns: None, mem_peak: 0, canceled_by: None, success: false, cached_res_path: None, token: token.to_string(), duration: None, preprocessed_args: None, has_stream: Some(false), from_cache: None }, true).await.unwrap() - } - }, - Err(e) => { - tracing::error!("Could not deserialize job result `{line}`: {e:?}"); - job_completed_tx.send_job(JobCompleted { job , result: Arc::new(to_raw_value(&serde_json::json!({"error": format!("Could not deserialize job result `{line}`: {e:?}")}))), result_columns: None, mem_peak: 0, canceled_by: None, success: false, cached_res_path: None, token: token.to_string(), duration: None, preprocessed_args: None, has_stream: Some(false), from_cache: None }, true).await.unwrap(); - }, - }; - logs = init_log.clone(); - } else { - logs.push_str(&line); - logs.push_str("\n"); - } - } else { - tracing::info!("dedicated worker {script_path} process exited"); - let mut last_stderr = "".to_string(); - while let Some(line) = err_reader.next_line().await.ok().flatten() { - last_stderr = line; - last_stderr.push_str("\n"); - } - tracing::info!("Last stderr for {script_path}: {last_stderr}"); - break; - } - }, - job = conditional_polling(jobs_rx.recv(), alive && jobs.len() < MAX_BUFFERED_DEDICATED_JOBS) => { - // i += 1; - if let Some(job) = job { - let id = job.id; - let args = serde_json::to_string(&job.args).expect("serialize"); - jobs.push_back(MiniCompletedJob::from(job)); - tracing::info!("received job and adding to queue on dedicated worker for {script_path}: {} (queue_size: {})", id, jobs.len()); - - // write_stdin(&mut stdin, &serde_json::to_string(&job.args.unwrap_or_else(|| serde_json::json!({"x": job.id}))).expect("serialize")).await?; - write_stdin(&mut stdin, &args).await?; - stdin.flush().await.context("stdin flush")?; - // tracing::info!("wrote job to stdin for {script_path}: {} (queue_size: {})", id, jobs.len()); - } else { - tracing::debug!("job channel closed"); - alive = false; - if let Err(e) = write_stdin(&mut stdin, "end").await { - tracing::error!("Could not write end message to stdin: {e:?}") - } - } - } - } - } - - child - .await - .map_err(|e| anyhow::anyhow!("child process {script_path} encountered an error: {e:#}"))?; - - tracing::info!("dedicated worker {script_path} child process exited successfully"); - Ok(()) -} - -type DedicatedWorker = ( - String, - Sender>, - Option>, -); - -// spawn one dedicated worker per compatible steps of the flow, associating the node id to the dedicated worker channel send -#[async_recursion] -#[cfg(feature = "enterprise")] -async fn spawn_dedicated_workers_for_flow( - modules: &Vec, - w_id: &str, - path: &str, - killpill_tx: KillpillSender, - killpill_rx: &tokio::sync::broadcast::Receiver<()>, - db: &DB, - worker_dir: &str, - base_internal_url: &str, - worker_name: &str, - job_completed_tx: &JobCompletedSender, -) -> Vec { - let mut workers = vec![]; - let mut script_path_to_worker: HashMap>> = - HashMap::new(); - for module in modules.iter() { - let value = module.get_value(); - if let Ok(value) = value { - match &value { - FlowModuleValue::Script { path, hash, .. } => { - let key = format!( - "{}:{}", - path, - hash.clone() - .map(|x| x.to_string()) - .unwrap_or_else(|| "".to_string()) - ); - if let Some(sender) = script_path_to_worker.get(&key) { - workers.push((module.id.clone(), sender.clone(), None)); - } else { - if let Some(dedi_w) = spawn_dedicated_worker( - SpawnWorker::Script { path: path.to_string(), hash: hash.clone() }, - w_id, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - Some(module.id.clone()), - ) - .await - { - script_path_to_worker.insert(key, dedi_w.1.clone()); - workers.push(dedi_w); - } - } - } - FlowModuleValue::ForloopFlow { modules, .. } => { - let w = spawn_dedicated_workers_for_flow( - &modules, - w_id, - path, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - ) - .await; - workers.extend(w); - } - FlowModuleValue::WhileloopFlow { modules, .. } => { - let w = spawn_dedicated_workers_for_flow( - &modules, - w_id, - path, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - ) - .await; - workers.extend(w); - } - FlowModuleValue::BranchOne { branches, default, .. } => { - for modules in branches - .iter() - .map(|x| &x.modules) - .chain(std::iter::once(default)) - { - let w = spawn_dedicated_workers_for_flow( - &modules, - w_id, - path, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - ) - .await; - workers.extend(w); - } - } - FlowModuleValue::BranchAll { branches, .. } => { - for branch in branches { - let w = spawn_dedicated_workers_for_flow( - &branch.modules, - w_id, - path, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - ) - .await; - workers.extend(w); - } - } - FlowModuleValue::RawScript { content, lock, path: spath, language, .. } => { - if let Some(dedi_w) = spawn_dedicated_worker( - SpawnWorker::RawScript { - path: spath.clone().unwrap_or(path.to_string()), - content: content.to_string(), - lock: lock.clone(), - lang: language.clone(), - }, - w_id, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - Some(module.id.clone()), - ) - .await - { - workers.push(dedi_w); - } - } - FlowModuleValue::FlowScript { id, language, .. } => { - let spawn = cache::flow::fetch_script( - &windmill_common::worker::Connection::Sql(db.clone()), - *id, - ) - .await - .map(|data| SpawnWorker::RawScript { - path: "".to_string(), - content: data.code.clone(), - lock: data.lock.clone(), - lang: *language, - }); - match spawn { - Ok(spawn) => { - if let Some(dedi_w) = spawn_dedicated_worker( - spawn, - w_id, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - Some(module.id.clone()), - ) - .await - { - workers.push(dedi_w); - } - } - Err(err) => tracing::error!( - "failed to get script for module: {:?}, err: {:?}", - module, - err - ), - } - } - FlowModuleValue::Flow { .. } => (), - FlowModuleValue::Identity => (), - FlowModuleValue::AIAgent { .. } => (), - } - } else { - tracing::error!("failed to get value for module: {:?}", module); - } - } - workers -} - -pub async fn create_dedicated_worker_map( - killpill_tx: &KillpillSender, - killpill_rx: &tokio::sync::broadcast::Receiver<()>, - db: &DB, - worker_dir: &str, - base_internal_url: &str, - worker_name: &str, - job_completed_tx: &JobCompletedSender, -) -> ( - HashMap>>, - bool, - Vec>, -) { - let mut dedicated_handles = vec![]; - if let Some(_wp) = WORKER_CONFIG.read().await.dedicated_worker.clone() { - let mut hm = HashMap::new(); - let is_flow_worker; - if let Some(flow_path) = _wp.path.strip_prefix("flow/") { - is_flow_worker = true; - let value = sqlx::query_scalar!( - "SELECT flow_version.value AS \"value!: sqlx::types::Json>\" - FROM flow - LEFT JOIN flow_version - ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] - WHERE flow.path = $1 AND flow.workspace_id = $2", - flow_path, - _wp.workspace_id - ) - .fetch_optional(db) - .await; - if let Ok(v) = value { - if let Some(v) = v { - let value = serde_json::from_str::(v.get()).map_err(|err| { - Error::internal_err(format!( - "could not convert json to flow for {flow_path}: {err:?}" - )) - }); - if let Ok(flow) = value { - let workers = spawn_dedicated_workers_for_flow( - &flow.modules, - &_wp.workspace_id, - &_wp.path, - killpill_tx.clone(), - &killpill_rx, - db, - &worker_dir, - base_internal_url, - &worker_name, - &job_completed_tx, - ) - .await; - workers.into_iter().for_each(|(path, sender, handle)| { - tracing::info!("spawned dedicated worker for flow: {}", path.as_str()); - if let Some(h) = handle { - dedicated_handles.push(h); - } - hm.insert(path, sender); - }); - } - } else { - tracing::error!( - "flow present but value not found for dedicated worker. {}", - flow_path - ); - } - } else { - tracing::error!("flow not found for dedicated worker: {}. Waiting for dependency job and expected to restart.", flow_path); - } - } else { - is_flow_worker = false; - if let Some((path, sender, handle)) = spawn_dedicated_worker( - SpawnWorker::Script { path: _wp.path.clone(), hash: None }, - &_wp.workspace_id, - killpill_tx.clone(), - &killpill_rx, - db, - &worker_dir, - base_internal_url, - &worker_name, - &job_completed_tx, - None, - ) - .await - { - if let Some(h) = handle { - dedicated_handles.push(h); - } - hm.insert(path, sender); - } else { - tracing::error!( - "failed to spawn dedicated worker for {}, script not found", - _wp.path - ); - } - } - (hm, is_flow_worker, dedicated_handles) - } else { - (HashMap::new(), false, dedicated_handles) - } -} - -#[derive(Debug, Clone)] -pub enum SpawnWorker { - Script { path: String, hash: Option }, - RawScript { path: String, content: String, lock: Option, lang: ScriptLang }, -} - -// spawn one dedicated worker and return the key, the channel sender and the join handle -// note that for it will return none for language that do not support dedicated workers -// note that go using cache binary does not need dedicated workers so all languages are supported -#[cfg(feature = "enterprise")] -async fn spawn_dedicated_worker( - sw: SpawnWorker, - w_id: &str, - killpill_tx: KillpillSender, - killpill_rx: &tokio::sync::broadcast::Receiver<()>, - db: &DB, - worker_dir: &str, - base_internal_url: &str, - worker_name: &str, - job_completed_tx: &JobCompletedSender, - node_id: Option, -) -> Option { - use windmill_common::{ - error::Error, - scripts::{ScriptHash, ScriptLang}, - utils::rd_string, - }; - use windmill_queue::MiniPulledJob; - - use crate::{build_envs, get_script_content_by_hash, ContentReqLangEnvs}; - - #[cfg(not(feature = "enterprise"))] - { - tracing::error!("Dedicated worker is an enterprise feature"); - killpill_tx.send(()).expect("send"); - return None; - } - - #[cfg(feature = "enterprise")] - { - let (dedicated_worker_tx, dedicated_worker_rx) = tokio::sync::mpsc::channel::< - std::sync::Arc, - >(MAX_BUFFERED_DEDICATED_JOBS); - let killpill_rx = killpill_rx.resubscribe(); - let db2 = db.clone(); - let base_internal_url = base_internal_url.to_string(); - let worker_name = worker_name.to_string(); - let job_completed_tx = job_completed_tx.clone(); - let job_dir = format!( - "{}/dedicated{}", - worker_dir, - node_id - .as_ref() - .map(|x| format!("-{x}")) - .unwrap_or_else(|| "".to_string()) - ); - tokio::fs::create_dir_all(&job_dir) - .await - .expect("create dir"); - - let path = match &sw { - SpawnWorker::RawScript { path, .. } => path.to_string(), - SpawnWorker::Script { path, .. } => path.to_string(), - }; - - let path2 = path.clone(); - let w_id = w_id.to_string(); - - let (content, lock, language, envs, codebase) = match sw.clone() { - SpawnWorker::Script { path, hash } => { - let q = if let Some(hash) = hash { - get_script_content_by_hash(&hash, &w_id, &db2.into()) - .await - .map(|r: ContentReqLangEnvs| { - Some((r.content, r.lockfile, r.language, r.envs, r.codebase)) - }) - } else { - sqlx::query_as::<_, (String, Option, Option, Option>, bool, Option)>( - "SELECT content, lock, language, envs, codebase IS NOT NULL, hash FROM script WHERE path = $1 AND workspace_id = $2 AND - archived = false AND lock IS not NULL AND lock_error_logs IS NULL ORDER BY created_at DESC LIMIT 1", - ) - .bind(&path) - .bind(&w_id) - .fetch_optional(&db2) - .await - .map_err(|e| Error::internal_err(format!("expected content and lock: {e:#}"))) - .map(|x| x.map(|y| (y.0, y.1, y.2, y.3, if y.4 { y.5.map(|z| z.to_string()) } else { None }))) - }; - if let Ok(q) = q { - if let Some(wp) = q { - wp - } else { - tracing::error!( - "Failed to fetch script `{}` in workspace {} for dedicated worker.", - path, - w_id - ); - return None; - } - } else { - tracing::error!("Failed to fetch script for dedicated worker"); - killpill_tx.send(); - return None; - } - } - SpawnWorker::RawScript { content, lock, lang, .. } => { - (content, lock, Some(lang), None, None) - } - }; - - match language { - Some(ScriptLang::Python3) | Some(ScriptLang::Bun) | Some(ScriptLang::Deno) => {} - _ => return None, - } - - let db = db.clone(); - let handle = tokio::spawn(async move { - let token = { - let token = rd_string(32); - if let Err(e) = sqlx::query_scalar!( - "INSERT INTO token - (token, label, super_admin, email) - VALUES ($1, $2, $3, $4)", - token, - "dedicated_worker", - true, - "dedicated_worker@windmill.dev" - ) - .execute(&db) - .await - { - tracing::error!("failed to create token for dedicated worker: {:?}", e); - killpill_tx.clone().send(); - }; - token - }; - - let worker_envs = build_envs(envs.as_ref()).expect("failed to build envs"); - - if let Err(e) = match language { - Some(ScriptLang::Python3) => { - #[cfg(not(feature = "python"))] - { - tracing::error!("Python requires the python feature to be enabled"); - killpill_tx.send(); - return; - } - - #[cfg(feature = "python")] - crate::python_executor::start_worker( - lock.as_ref(), - &db, - &content, - &base_internal_url, - &job_dir, - &worker_name, - worker_envs, - &w_id, - &path, - &token, - job_completed_tx, - dedicated_worker_rx, - killpill_rx, - ) - .await - } - Some(ScriptLang::Bun) => { - crate::bun_executor::start_worker( - lock, - codebase, - &db, - &content, - &base_internal_url, - &job_dir, - &worker_name, - worker_envs, - &w_id, - &path, - &token, - job_completed_tx, - dedicated_worker_rx, - killpill_rx, - ) - .await - } - Some(ScriptLang::Deno) => { - crate::deno_executor::start_worker( - &content, - &base_internal_url, - &job_dir, - &worker_name, - worker_envs, - &w_id, - &path, - &token, - job_completed_tx, - dedicated_worker_rx, - killpill_rx, - &db, - ) - .await - } - _ => unreachable!("Non supported language for dedicated worker"), - } { - tracing::error!("error in dedicated worker for {sw:#?}: {:?}", e); - }; - killpill_tx.clone().send(); - }); - return Some((node_id.unwrap_or(path2), dedicated_worker_tx, Some(handle))); - // (Some(dedi_path), Some(dedicated_worker_tx), Some(handle)) - } -} diff --git a/backend/windmill-worker/src/dedicated_worker_oss.rs b/backend/windmill-worker/src/dedicated_worker_oss.rs new file mode 100644 index 0000000000..09e86193e0 --- /dev/null +++ b/backend/windmill-worker/src/dedicated_worker_oss.rs @@ -0,0 +1,26 @@ +#[cfg(feature = "private")] +// #[allow(unused)] +pub use crate::dedicated_worker_ee::*; + +#[cfg(not(feature = "private"))] +pub async fn spawn_flow_module_runners( + _job: &windmill_queue::MiniPulledJob, + _module: &windmill_common::flows::FlowModule, + _failure_module: Option<&Box>, + _killpill_rx: &tokio::sync::broadcast::Receiver<()>, + _db: &windmill_common::db::DB, + _worker_dir: &str, + _base_internal_url: &str, + _worker_name: &str, + _job_completed_tx: &crate::JobCompletedSender, +) -> windmill_common::error::Result<( + std::collections::HashMap< + String, + tokio::sync::mpsc::Sender, + >, + Vec>, +)> { + Err(windmill_common::error::Error::internal_err( + "Squashing flow loops is not available in OSS".to_string(), + )) +} diff --git a/backend/windmill-worker/src/deno_executor.rs b/backend/windmill-worker/src/deno_executor.rs index 332cd142db..e80eec265d 100644 --- a/backend/windmill-worker/src/deno_executor.rs +++ b/backend/windmill-worker/src/deno_executor.rs @@ -514,13 +514,14 @@ async fn build_import_map( Ok(()) as error::Result<()> } -#[cfg(feature = "enterprise")] -use crate::{dedicated_worker::handle_dedicated_process, JobCompletedSender}; - -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] +use crate::{dedicated_worker_oss::handle_dedicated_process, JobCompletedSender}; +#[cfg(feature = "private")] use tokio::sync::mpsc::Receiver; +#[cfg(feature = "private")] +use windmill_queue::DedicatedWorkerJob; -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] pub async fn start_worker( inner_content: &str, base_internal_url: &str, @@ -531,9 +532,10 @@ pub async fn start_worker( script_path: &str, token: &str, job_completed_tx: JobCompletedSender, - jobs_rx: Receiver>, + jobs_rx: Receiver, killpill_rx: tokio::sync::broadcast::Receiver<()>, db: &sqlx::Pool, + client: windmill_common::client::AuthedClient, ) -> Result<()> { use windmill_common::variables; @@ -654,6 +656,7 @@ for await (const chunk of Deno.stdin.readable) {{ db, script_path, "deno", + client, ) .await } diff --git a/backend/windmill-worker/src/duckdb_executor.rs b/backend/windmill-worker/src/duckdb_executor.rs index 4a6857ad1a..e9ec589412 100644 --- a/backend/windmill-worker/src/duckdb_executor.rs +++ b/backend/windmill-worker/src/duckdb_executor.rs @@ -603,7 +603,10 @@ async fn transform_s3_uris(query: &str) -> Result { // 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 +// and deleted by do_duckdb after the query is executed. +// +// This relies on the fact that DuckDB does not run in native worker, so +// a worker will only run a single job at a time. pub struct UseBigQueryCredentialsFile { path: String, } @@ -665,6 +668,8 @@ fn remove_comments(stmt: &str) -> &str { #[cfg(test)] mod tests { use super::*; + + // Tests for remove_comments function #[test] fn test_remove_comments_single_line() { let sql = "-- This is a comment\nSELECT * FROM table;"; @@ -695,4 +700,377 @@ mod tests { let sql = " -- Comment\n -- Comment2\n -- Comment3\n SELECT\n\n * FROM\n table\n;\n\n -- end comment "; assert_eq!(remove_comments(sql), "SELECT\n\n * FROM\n table\n;"); } + + // Tests for parse_attach_db_resource function + #[test] + fn test_parse_attach_db_resource_postgres_res_prefix() { + let query = "ATTACH '$res:u/user/my_postgres' AS mydb (TYPE POSTGRES)"; + let result = parse_attach_db_resource(query); + assert!(result.is_some()); + let parsed = result.unwrap(); + assert_eq!(parsed.resource_path, "u/user/my_postgres"); + assert_eq!(parsed.name, "mydb"); + assert_eq!(parsed.db_type, "POSTGRES"); + assert!(parsed.extra_args.is_none() || parsed.extra_args.unwrap().is_empty()); + } + + #[test] + fn test_parse_attach_db_resource_res_protocol() { + let query = "ATTACH 'res://f/folder/database' AS db (TYPE postgresql)"; + let result = parse_attach_db_resource(query); + assert!(result.is_some()); + let parsed = result.unwrap(); + assert_eq!(parsed.resource_path, "f/folder/database"); + assert_eq!(parsed.name, "db"); + assert_eq!(parsed.db_type, "postgresql"); + } + + #[test] + fn test_parse_attach_db_resource_mysql() { + let query = "ATTACH '$res:u/admin/mysql_prod' AS mysql_db (TYPE mysql)"; + let result = parse_attach_db_resource(query); + assert!(result.is_some()); + let parsed = result.unwrap(); + assert_eq!(parsed.resource_path, "u/admin/mysql_prod"); + assert_eq!(parsed.name, "mysql_db"); + assert_eq!(parsed.db_type, "mysql"); + } + + #[test] + fn test_parse_attach_db_resource_bigquery() { + let query = "ATTACH '$res:u/user/bq_resource' AS bq (TYPE bigquery)"; + let result = parse_attach_db_resource(query); + assert!(result.is_some()); + let parsed = result.unwrap(); + assert_eq!(parsed.resource_path, "u/user/bq_resource"); + assert_eq!(parsed.name, "bq"); + assert_eq!(parsed.db_type, "bigquery"); + } + + #[test] + fn test_parse_attach_db_resource_with_extra_args() { + let query = "ATTACH '$res:u/user/db' AS mydb (TYPE POSTGRES, READ_ONLY)"; + let result = parse_attach_db_resource(query); + assert!(result.is_some()); + let parsed = result.unwrap(); + assert_eq!(parsed.resource_path, "u/user/db"); + assert_eq!(parsed.name, "mydb"); + assert_eq!(parsed.db_type, "POSTGRES"); + assert_eq!(parsed.extra_args.unwrap(), ", READ_ONLY"); + } + + #[test] + fn test_parse_attach_db_resource_case_insensitive() { + let query = "attach '$res:u/user/db' as mydb (type postgres)"; + let result = parse_attach_db_resource(query); + assert!(result.is_some()); + let parsed = result.unwrap(); + assert_eq!(parsed.resource_path, "u/user/db"); + assert_eq!(parsed.name, "mydb"); + assert_eq!(parsed.db_type, "postgres"); + } + + #[test] + fn test_parse_attach_db_resource_no_match() { + let query = "SELECT * FROM table"; + let result = parse_attach_db_resource(query); + assert!(result.is_none()); + } + + #[test] + fn test_parse_attach_db_resource_regular_attach() { + // Regular ATTACH without $res: or res:// should not match + let query = "ATTACH 'mydb.duckdb' AS mydb (TYPE duckdb)"; + let result = parse_attach_db_resource(query); + assert!(result.is_none()); + } + + // Tests for format_attach_db_conn_str function + #[test] + fn test_format_attach_db_conn_str_postgres_full() { + let db_resource = json!({ + "host": "localhost", + "port": 5432, + "user": "admin", + "password": "secret123", + "dbname": "mydb", + "sslmode": "require" + }); + let result = format_attach_db_conn_str(db_resource, "postgres").unwrap(); + assert!(result.contains("dbname=mydb")); + assert!(result.contains("user=admin")); + assert!(result.contains("host=localhost")); + assert!(result.contains("password=secret123")); + assert!(result.contains("port=5432")); + assert!(result.contains("sslmode=require")); + } + + #[test] + fn test_format_attach_db_conn_str_postgres_minimal() { + let db_resource = json!({ + "host": "db.example.com", + "dbname": "production" + }); + let result = format_attach_db_conn_str(db_resource, "postgres").unwrap(); + assert!(result.contains("dbname=production")); + assert!(result.contains("host=db.example.com")); + // Optional fields should result in empty strings + assert!(!result.contains("user=")); + assert!(!result.contains("password=")); + } + + #[test] + fn test_format_attach_db_conn_str_postgresql_alias() { + let db_resource = json!({ + "host": "localhost", + "dbname": "test" + }); + let result = format_attach_db_conn_str(db_resource, "postgresql").unwrap(); + assert!(result.contains("dbname=test")); + assert!(result.contains("host=localhost")); + } + + #[test] + fn test_format_attach_db_conn_str_bigquery() { + let db_resource = json!({ + "project_id": "my-gcp-project" + }); + let result = format_attach_db_conn_str(db_resource, "bigquery").unwrap(); + assert_eq!(result, "project=my-gcp-project"); + } + + #[test] + fn test_format_attach_db_conn_str_bigquery_missing_project_id() { + let db_resource = json!({ + "other_field": "value" + }); + let result = format_attach_db_conn_str(db_resource, "bigquery"); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("project_id")); + } + + #[test] + fn test_format_attach_db_conn_str_unsupported_type() { + let db_resource = json!({}); + let result = format_attach_db_conn_str(db_resource, "oracle"); + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("Unsupported db type")); + } + + #[test] + fn test_format_attach_db_conn_str_case_insensitive() { + let db_resource = json!({ + "host": "localhost", + "dbname": "test" + }); + let result = format_attach_db_conn_str(db_resource, "POSTGRES").unwrap(); + assert!(result.contains("dbname=test")); + } + + #[cfg(feature = "mysql")] + #[test] + fn test_format_attach_db_conn_str_mysql_full() { + let db_resource = json!({ + "host": "mysql.example.com", + "port": 3306, + "user": "root", + "password": "mysecret", + "database": "app_db", + "ssl": true + }); + let result = format_attach_db_conn_str(db_resource, "mysql").unwrap(); + assert!(result.contains("database=app_db")); + assert!(result.contains("host=mysql.example.com")); + assert!(result.contains("ssl_mode=required")); + assert!(result.contains("password=mysecret")); + assert!(result.contains("port=3306")); + assert!(result.contains("user=root")); + } + + #[cfg(feature = "mysql")] + #[test] + fn test_format_attach_db_conn_str_mysql_ssl_disabled() { + let db_resource = json!({ + "host": "localhost", + "database": "test", + "ssl": false + }); + let result = format_attach_db_conn_str(db_resource, "mysql").unwrap(); + assert!(result.contains("ssl_mode=disabled")); + } + + // Tests for get_attach_db_install_str function + #[test] + fn test_get_attach_db_install_str_postgres() { + let result = get_attach_db_install_str("postgres").unwrap(); + assert_eq!(result, "INSTALL postgres;"); + } + + #[test] + fn test_get_attach_db_install_str_bigquery() { + let result = get_attach_db_install_str("bigquery").unwrap(); + assert_eq!(result, "INSTALL bigquery FROM community;"); + } + + #[test] + fn test_get_attach_db_install_str_unsupported() { + let result = get_attach_db_install_str("sqlite"); + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("Unsupported db type")); + } + + #[test] + fn test_get_attach_db_install_str_case_insensitive() { + let result = get_attach_db_install_str("POSTGRES").unwrap(); + assert_eq!(result, "INSTALL postgres;"); + } + + #[cfg(feature = "mysql")] + #[test] + fn test_get_attach_db_install_str_mysql() { + let result = get_attach_db_install_str("mysql").unwrap(); + assert_eq!(result, "INSTALL mysql;"); + } + + #[cfg(not(feature = "mysql"))] + #[test] + fn test_get_attach_db_install_str_mysql_disabled() { + let result = get_attach_db_install_str("mysql"); + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("MySQL feature is not enabled")); + } + + // Tests for transform_s3_uris function + #[tokio::test] + async fn test_transform_s3_uris_empty_storage() { + let query = "SELECT * FROM read_parquet('s3:///path/to/file.parquet')"; + let result = transform_s3_uris(query).await.unwrap(); + assert_eq!( + result, + "SELECT * FROM read_parquet('s3://_default_/path/to/file.parquet')" + ); + } + + #[tokio::test] + async fn test_transform_s3_uris_with_storage() { + // URIs with explicit storage should not be transformed + let query = "SELECT * FROM read_parquet('s3://mybucket/path/to/file.parquet')"; + let result = transform_s3_uris(query).await.unwrap(); + assert_eq!(result, query); + } + + #[tokio::test] + async fn test_transform_s3_uris_multiple_empty() { + let query = "SELECT * FROM read_parquet('s3:///file1.parquet') UNION SELECT * FROM read_parquet('s3:///file2.parquet')"; + let result = transform_s3_uris(query).await.unwrap(); + assert!(result.contains("s3://_default_/file1.parquet")); + assert!(result.contains("s3://_default_/file2.parquet")); + } + + #[tokio::test] + async fn test_transform_s3_uris_no_s3() { + let query = "SELECT * FROM my_table"; + let result = transform_s3_uris(query).await.unwrap(); + assert_eq!(result, query); + } + + #[tokio::test] + async fn test_transform_s3_uris_mixed() { + let query = "SELECT * FROM read_parquet('s3:///default.parquet'), read_csv('s3://explicit/file.csv')"; + let result = transform_s3_uris(query).await.unwrap(); + assert!(result.contains("s3://_default_/default.parquet")); + assert!(result.contains("s3://explicit/file.csv")); + } + + #[tokio::test] + async fn test_transform_s3_uris_nested_path() { + let query = "SELECT * FROM read_parquet('s3:///deep/nested/path/file.parquet')"; + let result = transform_s3_uris(query).await.unwrap(); + assert_eq!( + result, + "SELECT * FROM read_parquet('s3://_default_/deep/nested/path/file.parquet')" + ); + } + + // Tests for Arg struct + #[test] + fn test_arg_serialization() { + let arg = Arg { + name: "test_arg".to_string(), + arg_type: "string".to_string(), + json_value: json!("hello"), + }; + let serialized = serde_json::to_string(&arg).unwrap(); + assert!(serialized.contains("\"name\":\"test_arg\"")); + assert!(serialized.contains("\"arg_type\":\"string\"")); + assert!(serialized.contains("\"json_value\":\"hello\"")); + } + + #[test] + fn test_arg_serialization_number() { + let arg = Arg { + name: "count".to_string(), + arg_type: "integer".to_string(), + json_value: json!(42), + }; + let serialized = serde_json::to_string(&arg).unwrap(); + assert!(serialized.contains("\"json_value\":42")); + } + + #[test] + fn test_arg_serialization_null() { + let arg = Arg { + name: "optional".to_string(), + arg_type: "text".to_string(), + json_value: json!(null), + }; + let serialized = serde_json::to_string(&arg).unwrap(); + assert!(serialized.contains("\"json_value\":null")); + } + + #[test] + fn test_arg_serialization_array() { + let arg = Arg { + name: "items".to_string(), + arg_type: "array".to_string(), + json_value: json!([1, 2, 3]), + }; + let serialized = serde_json::to_string(&arg).unwrap(); + assert!(serialized.contains("\"json_value\":[1,2,3]")); + } + + #[test] + fn test_arg_serialization_object() { + let arg = Arg { + name: "config".to_string(), + arg_type: "object".to_string(), + json_value: json!({"key": "value"}), + }; + let serialized = serde_json::to_string(&arg).unwrap(); + assert!(serialized.contains("\"json_value\":{\"key\":\"value\"}")); + } + + #[test] + fn test_remove_comments_comment_in_string() { + let sql = "SELECT '-- not a comment' FROM table;"; + let result = remove_comments(sql); + assert_eq!(result, "SELECT '-- not a comment' FROM table;"); + } + + #[test] + fn test_remove_comments_multiple_dashes() { + let sql = "SELECT 5 - - 3;"; + let result = remove_comments(sql); + // This correctly handles the subtraction of negative number + assert_eq!(result, sql); + } } diff --git a/backend/windmill-worker/src/js_eval.rs b/backend/windmill-worker/src/js_eval.rs index 5feeab8003..cce5d8ef5e 100644 --- a/backend/windmill-worker/src/js_eval.rs +++ b/backend/windmill-worker/src/js_eval.rs @@ -190,9 +190,24 @@ fn should_add_return(expr: &str) -> bool { // Check for common statement patterns that shouldn't have return prepended let statement_prefixes = [ - "const ", "let ", "var ", "if ", "if(", "for ", "for(", - "while ", "while(", "switch ", "switch(", "try ", "try{", - "throw ", "function ", "class ", "async ", "await " + "const ", + "let ", + "var ", + "if ", + "if(", + "for ", + "for(", + "while ", + "while(", + "switch ", + "switch(", + "try ", + "try{", + "throw ", + "function ", + "class ", + "async ", + "await ", ]; for prefix in &statement_prefixes { @@ -677,7 +692,33 @@ function get_from_env(name) {{ .map(|a| { format!("let {a} = get_from_env(\"{a}\");\n",) }) .join(""), if expr.contains("error") && transform_context.contains(&"previous_result".to_string()) { - "let error = previous_result?.error;" + r#"let error = previous_result?.error; +if (!error) { + if (Array.isArray(previous_result)) { + const errors = previous_result.filter(item => item && typeof item === 'object' && 'error' in item); + if (errors.length === 1) { + error = errors[0].error; + } else if (errors.length > 1) { + error = { + name: 'MultipleErrors', + message: errors.map(({ error: e }, i) => `[${e.step_id || i}] ${e.message || e.name}`).join('; '), + errors: previous_result + }; + } else { + error = { + name: 'MultipleErrors', + message: "Could not parse errors", + errors: previous_result + }; + } + } else { + if (previous_result) { + error = { name: 'UnknownError', message: 'Could not parse the error', error: previous_result }; + } else { + error = { name: 'UnknownError', message: 'No error found' }; + } + } +}"# } else { "" }, @@ -1614,9 +1655,15 @@ multiline template`"; assert_eq!(contains_semicolon_outside_strings("x; y"), true); // Semicolons inside strings (should NOT be detected) - assert_eq!(contains_semicolon_outside_strings("\"hello; world\""), false); + assert_eq!( + contains_semicolon_outside_strings("\"hello; world\""), + false + ); assert_eq!(contains_semicolon_outside_strings("'test; string'"), false); - assert_eq!(contains_semicolon_outside_strings("`template; literal`"), false); + assert_eq!( + contains_semicolon_outside_strings("`template; literal`"), + false + ); // Mixed cases assert_eq!( diff --git a/backend/windmill-worker/src/lib.rs b/backend/windmill-worker/src/lib.rs index 4bf60f6d4a..c5db591c42 100644 --- a/backend/windmill-worker/src/lib.rs +++ b/backend/windmill-worker/src/lib.rs @@ -23,8 +23,10 @@ mod bun_executor; pub mod common; mod config; mod csharp_executor; -#[cfg(feature = "enterprise")] -mod dedicated_worker; + +#[cfg(feature = "private")] +mod dedicated_worker_ee; +mod dedicated_worker_oss; mod deno_executor; #[cfg(feature = "duckdb")] mod duckdb_executor; diff --git a/backend/windmill-worker/src/python_executor.rs b/backend/windmill-worker/src/python_executor.rs index bc84a2e19f..b417014d85 100644 --- a/backend/windmill-worker/src/python_executor.rs +++ b/backend/windmill-worker/src/python_executor.rs @@ -18,6 +18,8 @@ use tokio::{ sync::Semaphore, task, }; +use windmill_queue::MiniPulledJob; + use uuid::Uuid; #[cfg(all(feature = "enterprise", feature = "parquet", unix))] use windmill_common::ee_oss::{get_license_plan, LicensePlan}; @@ -546,7 +548,6 @@ pub async fn handle_python_job( precomputed_agent_info: Option, has_stream: &mut bool, ) -> windmill_common::error::Result> { - let script_path = crate::common::use_flow_root_path(job.runnable_path()); let annotations = PythonAnnotations::parse(inner_content); @@ -2130,16 +2131,16 @@ fn get_result_postprocessor<'a>(skip: bool) -> &'a str { } } -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] use crate::JobCompletedSender; -#[cfg(feature = "enterprise")] -use crate::{common::build_envs_map, dedicated_worker::handle_dedicated_process}; -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] +use crate::{common::build_envs_map, dedicated_worker_oss::handle_dedicated_process}; +#[cfg(feature = "private")] use windmill_common::variables; +#[cfg(feature = "private")] +use windmill_queue::DedicatedWorkerJob; -use windmill_queue::MiniPulledJob; - -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] pub async fn start_worker( requirements_o: Option<&String>, db: &sqlx::Pool, @@ -2152,10 +2153,12 @@ pub async fn start_worker( script_path: &str, token: &str, job_completed_tx: JobCompletedSender, - jobs_rx: tokio::sync::mpsc::Receiver>, + jobs_rx: tokio::sync::mpsc::Receiver, killpill_rx: tokio::sync::broadcast::Receiver<()>, + client: windmill_common::client::AuthedClient, ) -> error::Result<()> { use crate::{PyV, PyVAlias}; + tracing::info!("script path: {}", script_path); let mut mem_peak: i32 = 0; let mut canceled_by: Option = None; @@ -2346,6 +2349,7 @@ for line in sys.stdin: db, script_path, "python", + client, ) .await } diff --git a/backend/windmill-worker/src/result_processor.rs b/backend/windmill-worker/src/result_processor.rs index 1e168d3a30..e5a7a0052c 100644 --- a/backend/windmill-worker/src/result_processor.rs +++ b/backend/windmill-worker/src/result_processor.rs @@ -31,8 +31,8 @@ use windmill_common::{ use windmill_common::bench::{BenchmarkInfo, BenchmarkIter}; use windmill_queue::{ - append_logs, get_mini_completed_job, CanceledBy, JobCompleted, MiniCompletedJob, MiniPulledJob, - ValidableJson, WrappedError, INIT_SCRIPT_TAG, + append_logs, get_mini_completed_job, CanceledBy, FlowRunners, JobCompleted, MiniCompletedJob, + MiniPulledJob, ValidableJson, WrappedError, INIT_SCRIPT_TAG, }; use serde_json::{json, value::RawValue, Value}; @@ -66,6 +66,7 @@ async fn process_jc( same_worker_tx: Option<&SameWorkerSender>, job_completed_sender: &JobCompletedSender, stats_map: &JobStatsMap, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) { let success: bool = jc.success; @@ -155,6 +156,7 @@ async fn process_jc( same_worker_tx, &worker_name, job_completed_sender.clone(), + killpill_rx, #[cfg(feature = "benchmark")] bench, ) @@ -285,6 +287,7 @@ pub fn start_background_processor( Some(&same_worker_tx), &job_completed_sender, &stats_map, + &killpill_rx, #[cfg(feature = "benchmark")] &mut bench, ) @@ -350,6 +353,8 @@ pub fn start_background_processor( stop_early_override, &worker_name, job_completed_sender.clone(), + None, + &killpill_rx, #[cfg(feature = "benchmark")] &mut bench, ) @@ -413,6 +418,7 @@ pub async fn process_result( conn: &Connection, duration: Option, has_stream: bool, + flow_runners: Option>, ) -> error::Result { match result { Ok(result) => { @@ -431,6 +437,8 @@ pub async fn process_result( duration, has_stream: Some(has_stream), from_cache: None, + flow_runners, + done_tx: None, }, ) .with_context(windmill_common::otel_oss::otel_ctx()) @@ -495,6 +503,8 @@ pub async fn process_result( duration, has_stream: Some(has_stream), from_cache: None, + flow_runners, + done_tx: None, }, ) .with_context(windmill_common::otel_oss::otel_ctx()) @@ -512,6 +522,7 @@ pub async fn handle_receive_completed_job( same_worker_tx: Option<&SameWorkerSender>, worker_name: &str, job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> Option> { let token = jc.token.clone(); @@ -529,6 +540,7 @@ pub async fn handle_receive_completed_job( same_worker_tx.clone(), worker_name, job_completed_tx.clone(), + killpill_rx, #[cfg(feature = "benchmark")] bench, ) @@ -548,6 +560,7 @@ pub async fn handle_receive_completed_job( &worker_dir, worker_name, job_completed_tx, + killpill_rx, #[cfg(feature = "benchmark")] bench, ) @@ -571,6 +584,8 @@ pub async fn process_completed_job( preprocessed_args, has_stream, from_cache, + flow_runners, + done_tx, .. }: JobCompleted, client: &AuthedClient, @@ -579,6 +594,7 @@ pub async fn process_completed_job( same_worker_tx: Option<&SameWorkerSender>, worker_name: &str, job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> error::Result>> { if success { @@ -661,12 +677,19 @@ pub async fn process_completed_job( None, worker_name, job_completed_tx, + flow_runners, + killpill_rx, #[cfg(feature = "benchmark")] bench, ) .warn_after_seconds(10) .await?; add_time!(bench, "updated flow status END"); + if let Some(done_tx) = done_tx { + done_tx + .send(()) + .expect("done receiver should still be alive"); + } return Ok(r); } } @@ -707,11 +730,18 @@ pub async fn process_completed_job( None, worker_name, job_completed_tx, + flow_runners, + killpill_rx, #[cfg(feature = "benchmark")] bench, ) .warn_after_seconds(10) .await?; + if let Some(done_tx) = done_tx { + done_tx + .send(()) + .expect("done receiver should still be alive"); + } return Ok(r); } } @@ -761,6 +791,7 @@ pub async fn handle_job_error( worker_dir: &str, worker_name: &str, job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) { let err_string = format!("{}: {}", err.name(), err.to_string()); @@ -809,6 +840,8 @@ pub async fn handle_job_error( None, worker_name, job_completed_tx.clone(), + None, + killpill_rx, #[cfg(feature = "benchmark")] bench, ) diff --git a/backend/windmill-worker/src/worker.rs b/backend/windmill-worker/src/worker.rs index 5dfd09a1a0..ce946cd572 100644 --- a/backend/windmill-worker/src/worker.rs +++ b/backend/windmill-worker/src/worker.rs @@ -11,6 +11,7 @@ use anyhow::anyhow; use futures::TryFutureExt; +use tokio::sync::Mutex; use tokio::time::sleep; use tokio::time::timeout; use windmill_common::client::AuthedClient; @@ -61,6 +62,8 @@ use std::{ time::Duration, }; use windmill_parser::MainArgSignature; +use windmill_queue::DedicatedWorkerJob; +use windmill_queue::FlowRunners; use windmill_queue::MiniCompletedJob; use windmill_queue::PulledJobResultToJobErr; @@ -169,8 +172,8 @@ use crate::duckdb_executor::do_duckdb; #[cfg(all(feature = "enterprise", feature = "oracledb"))] use crate::oracledb_executor::do_oracledb; -#[cfg(feature = "enterprise")] -use crate::dedicated_worker::create_dedicated_worker_map; +#[cfg(all(feature = "private", feature = "enterprise"))] +use crate::dedicated_worker_oss::create_dedicated_worker_map; #[cfg(feature = "enterprise")] use crate::snowflake_executor::do_snowflake; @@ -534,6 +537,8 @@ lazy_static::lazy_static! { .ok() .and_then(|x| x.parse::().ok()) .unwrap_or(1000); + + pub static ref FLOW_RUNNER_RUNNING: Mutex = Mutex::new(false); } type Envs = Vec<(String, String)>; @@ -560,14 +565,14 @@ lazy_static::lazy_static! { #[derive(Debug)] pub enum NextJob { - Sql(PulledJob), + Sql { job: PulledJob, flow_runners: Option> }, Http(JobAndPerms), } impl NextJob { pub fn job(self) -> MiniPulledJob { match self { - NextJob::Sql(job) => job.job, + NextJob::Sql { job, .. } => job.job, NextJob::Http(job) => job.job, } } @@ -577,7 +582,7 @@ impl std::ops::Deref for NextJob { type Target = MiniPulledJob; fn deref(&self) -> &Self::Target { match self { - NextJob::Sql(job) => &job.job, + NextJob::Sql { job, .. } => &job.job, NextJob::Http(job) => &job.job, } } @@ -735,10 +740,10 @@ impl JobCompletedSender { impl SameWorkerSender { pub async fn send( &self, - payload: SameWorkerPayload, + message: SameWorkerPayload, ) -> Result<(), tokio::sync::mpsc::error::SendError> { self.1.fetch_add(1, Ordering::Relaxed); - self.0.send(payload).await + self.0.send(message).await } } @@ -831,18 +836,36 @@ fn add_outstanding_wait_time( async fn extract_job_and_perms(job: NextJob, conn: &Connection) -> JobAndPerms { match (job, conn) { - (NextJob::Sql(job), Connection::Sql(db)) => job.get_job_and_perms(db).await, - (NextJob::Sql(_), Connection::Http(_)) => panic!("sql job on http connection"), + (NextJob::Sql { job, flow_runners, .. }, Connection::Sql(db)) => { + JobAndPerms { flow_runners, ..job.get_job_and_perms(db).await } + } + (NextJob::Sql { .. }, Connection::Http(_)) => panic!("sql job on http connection"), (NextJob::Http(job), _) => job, } } -fn create_span(arc_job: &Arc, worker_name: &str, hostname: &str) -> Span { - let span = tracing::span!(tracing::Level::INFO, "job", - job_id = %arc_job.id, root_job = field::Empty, workspace_id = %arc_job.workspace_id, worker = %worker_name, hostname = %hostname, tag = %arc_job.tag, +pub fn create_span_with_name( + arc_job: &MiniPulledJob, + worker_name: &str, + hostname: Option<&str>, + span_name: &str, +) -> Span { + // The span macro requires a literal, so we use a fixed name and set otel.name dynamically + let span = tracing::span!( + tracing::Level::INFO, + "job", + job_id = %arc_job.id, + root_job = field::Empty, + workspace_id = %arc_job.workspace_id, + worker = %worker_name, + hostname = field::Empty, + tag = %arc_job.tag, language = field::Empty, - script_path = field::Empty, flow_step_id = field::Empty, parent_job = field::Empty, - otel.name = field::Empty); + script_path = field::Empty, + flow_step_id = field::Empty, + parent_job = field::Empty, + otel.name = field::Empty + ); let rj = arc_job.flow_innermost_root_job.unwrap_or(arc_job.id); @@ -850,10 +873,10 @@ fn create_span(arc_job: &Arc, worker_name: &str, hostname: &str) span.record("language", lg.as_str()); } if let Some(step_id) = arc_job.flow_step_id.as_ref() { - span.record("otel.name", format!("job {}", step_id).as_str()); + span.record("otel.name", format!("{} {}", span_name, step_id).as_str()); span.record("flow_step_id", step_id.as_str()); } else { - span.record("otel.name", "job"); + span.record("otel.name", span_name); } if let Some(parent_job) = arc_job.parent_job.as_ref() { span.record("parent_job", parent_job.to_string().as_str()); @@ -864,6 +887,9 @@ fn create_span(arc_job: &Arc, worker_name: &str, hostname: &str) if let Some(root_job) = arc_job.flow_innermost_root_job.as_ref() { span.record("root_job", root_job.to_string().as_str()); } + if let Some(hostname) = hostname { + span.record("hostname", hostname); + } windmill_common::otel_oss::set_span_parent(&span, &rj); span @@ -878,6 +904,7 @@ pub async fn handle_all_job_kind_error( worker_dir: &str, worker_name: &str, job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) { match conn { @@ -894,6 +921,7 @@ pub async fn handle_all_job_kind_error( &worker_dir, &worker_name, job_completed_tx.clone(), + &killpill_rx, #[cfg(feature = "benchmark")] bench, ) @@ -917,6 +945,8 @@ pub async fn handle_all_job_kind_error( duration: None, has_stream: Some(false), from_cache: None, + flow_runners: None, + done_tx: None, }, false, ) @@ -964,27 +994,21 @@ pub fn start_interactive_worker_shell( .await; match job { - Ok(j) => match j.to_pulled_job() { - Ok(j) => Ok(j.clone().map(NextJob::Sql)), - ref e @ (Err(PulledJobResultToJobErr::MissingConcurrencyKey( - ref jc, - )) - | Err(PulledJobResultToJobErr::ErrorWhilePreprocessing( - ref jc, - ))) => { - if let Err(err) = - job_completed_tx.send_job(jc.clone(), true).await - { - let e_fmt = match e { - Ok(_) => "unknown error".to_owned(), - Err(e) => e.to_string(), - }; - - tracing::error!("An error occurred while sending job completed ({e_fmt}): {:#?}", err) + Ok(j) => { + match j.to_pulled_job() { + Ok(j) => Ok(j + .clone() + .map(|job| NextJob::Sql { flow_runners: None, job })), + Err(PulledJobResultToJobErr::MissingConcurrencyKey(jc)) + | Err(PulledJobResultToJobErr::ErrorWhilePreprocessing(jc)) => { + if let Err(err) = job_completed_tx.send_job(jc, true).await + { + tracing::error!("An error occurred while sending job completed: {:#?}", err) + } + Ok(None) } - Ok(None) } - }, + } Err(err) => Err(err), } } @@ -1012,6 +1036,7 @@ pub fn start_interactive_worker_shell( parent_runnable_path, token, precomputed_agent_info: precomputed_bundle, + flow_runners, } = extract_job_and_perms(job, &conn).await; let authed_client = AuthedClient::new( @@ -1041,6 +1066,7 @@ pub fn start_interactive_worker_shell( &mut occupancy_metrics, &mut killpill_rx, precomputed_bundle, + flow_runners, #[cfg(feature = "benchmark")] &mut bench, ) @@ -1478,9 +1504,9 @@ pub async fn run_worker( // Option>>, // Option>, - #[cfg(feature = "enterprise")] + #[cfg(all(feature = "private", feature = "enterprise"))] let (dedicated_workers, is_flow_worker, dedicated_handles): ( - HashMap>>, + HashMap>, bool, Vec>, ) = match conn { @@ -1499,9 +1525,9 @@ pub async fn run_worker( Connection::Http(_) => (HashMap::new(), false, vec![]), }; - #[cfg(not(feature = "enterprise"))] + #[cfg(any(not(feature = "private"), not(feature = "enterprise")))] let (dedicated_workers, is_flow_worker, dedicated_handles): ( - HashMap>>, + HashMap>, bool, Vec>, ) = (HashMap::new(), false, vec![]); @@ -1658,7 +1684,7 @@ pub async fn run_worker( if let Ok(same_worker_job) = same_worker_rx.try_recv() { same_worker_queue_size.fetch_sub(1, Ordering::SeqCst); - tracing::debug!( + tracing::info!( worker = %worker_name, hostname = %hostname, "received {} from same worker channel", same_worker_job.job_id @@ -1678,7 +1704,12 @@ pub async fn run_worker( .expect("send kill to job completed tx"); break; } else { - job.map(|x| x.map(NextJob::Sql)) + job.map(|x| { + x.map(|job| NextJob::Sql { + flow_runners: same_worker_job.flow_runners, + job, + }) + }) } } Connection::Http(client) => client @@ -1829,22 +1860,14 @@ pub async fn run_worker( } match job { Ok(pulled_job_result) => match pulled_job_result.to_pulled_job() { - Ok(j) => Ok(j.map(NextJob::Sql)), - ref e @ (Err(PulledJobResultToJobErr::MissingConcurrencyKey( - ref jc, - )) - | Err(PulledJobResultToJobErr::ErrorWhilePreprocessing( - ref jc, - ))) => { - if let Err(err) = - job_completed_tx.send_job(jc.clone(), true).await - { - let e_fmt = match e { - Ok(_) => "unknown error".to_owned(), - Err(e) => e.to_string(), - }; - - tracing::error!("An error occurred while sending job completed ({e_fmt}): {:#?}", err) + Ok(j) => Ok(j.map(|job| NextJob::Sql { flow_runners: None, job })), + Err(PulledJobResultToJobErr::MissingConcurrencyKey(jc)) + | Err(PulledJobResultToJobErr::ErrorWhilePreprocessing(jc)) => { + if let Err(err) = job_completed_tx.send_job(jc, true).await { + tracing::error!( + "An error occurred while sending job completed: {:#?}", + err + ) } Ok(None) } @@ -1876,7 +1899,10 @@ pub async fn run_worker( tracing::debug!(worker = %worker_name, hostname = %hostname, "started handling of job {}", job.id); - if matches!(job.kind, JobKind::Script | JobKind::Preview) { + if matches!( + job.kind, + JobKind::Script | JobKind::Preview | JobKind::FlowScript + ) { if !dedicated_workers.is_empty() { let key_o = if is_flow_worker { job.flow_step_id.as_ref().map(|x| x.to_string()) @@ -1885,8 +1911,12 @@ pub async fn run_worker( }; if let Some(key) = key_o { if let Some(dedicated_worker_tx) = dedicated_workers.get(&key) { - if let Err(e) = dedicated_worker_tx.send(Arc::new(job.job())).await - { + let dedicated_job = DedicatedWorkerJob { + job: Arc::new(job.job()), + flow_runners: None, + done_tx: None, + }; + if let Err(e) = dedicated_worker_tx.send(dedicated_job).await { tracing::info!("failed to send jobs to dedicated workers. Likely dedicated worker has been shut down. This is normal: {e:?}"); } @@ -1900,6 +1930,77 @@ pub async fn run_worker( } } } + + // Extract flow_runners early to use in both dedicated workers and flow runners + let flow_runners = match &job { + NextJob::Sql { flow_runners, .. } => flow_runners.clone(), + NextJob::Http(_) => None, + }; + + if let Some(flow_runners) = flow_runners { + let key_o = job.flow_step_id.as_ref().map(|x| x.to_string()); + if let Some(key) = key_o { + if let Some(flow_runner_tx) = flow_runners.runners.get(&key) { + tracing::info!( + "sending job {} to flow runner step {}", + job.id, + key + ); + let (done_tx, done_rx) = tokio::sync::oneshot::channel::<()>(); + let flow_runners = flow_runners.clone(); + + let job = job.job(); + + let dedicated_job = DedicatedWorkerJob { + job: Arc::new(job.clone()), + flow_runners: Some(flow_runners), + done_tx: Some(done_tx), + }; + + if let Err(e) = flow_runner_tx.send(dedicated_job).await { + let token = match &conn { + Connection::Sql(db) => { + windmill_queue::jobs::create_token(db, &job, None).await + } + _ => "".to_string(), + }; + handle_all_job_kind_error( + &conn, + &AuthedClient::new( + base_internal_url.to_owned(), + job.workspace_id.clone(), + token, + None, + ), + MiniCompletedJob::from(job), + error::Error::InternalErr(format!( + "failed to send jobs to flow runners: {e:?}" + )), + Some(&same_worker_tx), + &worker_dir, + &worker_name, + job_completed_tx.clone(), + &killpill_rx, + #[cfg(feature = "benchmark")] + &mut bench, + ) + .await; + } else { + if let Err(err) = done_rx.await { + tracing::error!("Flow runner done channel has been dropped without being received: {err:?}"); + } + } + + #[cfg(feature = "benchmark")] + { + add_time!(bench, "sent to flow runner"); + infos.add_iter(bench, true); + } + + continue; + } + } + } } if matches!(job.kind, JobKind::Noop) { @@ -1919,6 +2020,8 @@ pub async fn run_worker( duration: None, has_stream: Some(false), from_cache: None, + flow_runners: None, + done_tx: None, }, true, ) @@ -2050,6 +2153,7 @@ pub async fn run_worker( parent_runnable_path, token, precomputed_agent_info: precomputed_bundle, + flow_runners, } = extract_job_and_perms(job, &conn).await; let authed_client = AuthedClient::new( @@ -2061,7 +2165,7 @@ pub async fn run_worker( let arc_job = Arc::new(job); - let span = create_span(&arc_job, &worker_name, hostname); + let span = create_span_with_name(&arc_job, &worker_name, Some(hostname), "job"); let job_result = handle_queued_job( arc_job.clone(), @@ -2081,6 +2185,7 @@ pub async fn run_worker( &mut occupancy_metrics, &mut killpill_rx2, precomputed_bundle, + flow_runners, #[cfg(feature = "benchmark")] &mut bench, ) @@ -2140,6 +2245,7 @@ pub async fn run_worker( &worker_dir, &worker_name, job_completed_tx.clone(), + &killpill_rx, #[cfg(feature = "benchmark")] &mut bench, ) @@ -2304,7 +2410,7 @@ async fn queue_init_bash_maybe<'c>( }; if let Some((uuid, content)) = uuid_content { same_worker_tx - .send(SameWorkerPayload { job_id: uuid, recoverable: false }) + .send(SameWorkerPayload { job_id: uuid, recoverable: false, flow_runners: None }) .await .map_err(to_anyhow)?; tracing::info!("Creating initial job {uuid} from initial script script: {content}"); @@ -2422,7 +2528,7 @@ async fn queue_periodic_script_bash_maybe<'c>( }; same_worker_tx - .send(SameWorkerPayload { job_id: uuid, recoverable: false }) + .send(SameWorkerPayload { job_id: uuid, recoverable: false, flow_runners: None }) .await .map_err(to_anyhow)?; tracing::info!("Creating periodic script job {uuid} from periodic script: {content}"); @@ -2434,7 +2540,6 @@ pub struct SendResult { pub time: Instant, } -#[derive(Clone)] pub enum SendResultPayload { JobCompleted(JobCompleted), UpdateFlow(UpdateFlow), @@ -2521,6 +2626,7 @@ pub async fn handle_queued_job( occupancy_metrics: &mut OccupancyMetrics, killpill_rx: &mut tokio::sync::broadcast::Receiver<()>, precomputed_agent_info: Option, + flow_runners: Option>, #[cfg(feature = "benchmark")] _bench: &mut BenchmarkIter, ) -> windmill_common::error::Result { // Extract the active span from the context @@ -2648,6 +2754,8 @@ pub async fn handle_queued_job( duration: None, has_stream: Some(false), from_cache: Some(true), + flow_runners: None, + done_tx: None, }, true, ) @@ -2683,6 +2791,8 @@ pub async fn handle_queued_job( worker_dir, job_completed_tx.clone(), worker_name, + flow_runners, + &killpill_rx, )) .warn_after_seconds(10) .await?; @@ -2913,6 +3023,7 @@ pub async fn handle_queued_job( conn, Some(started.elapsed().as_millis() as i64), has_stream, + flow_runners, ) .await } diff --git a/backend/windmill-worker/src/worker_flow.rs b/backend/windmill-worker/src/worker_flow.rs index f0bc4cfc1e..dd45d3b786 100644 --- a/backend/windmill-worker/src/worker_flow.rs +++ b/backend/windmill-worker/src/worker_flow.rs @@ -64,7 +64,7 @@ use windmill_common::{ use windmill_queue::schedule::get_schedule_opt; use windmill_queue::{ add_completed_job, add_completed_job_error, append_logs, get_mini_pulled_job, - handle_maybe_scheduled_job, insert_concurrency_key, interpolate_args, CanceledBy, + handle_maybe_scheduled_job, insert_concurrency_key, interpolate_args, CanceledBy, FlowRunners, MiniCompletedJob, MiniPulledJob, PushArgs, PushIsolationLevel, SameWorkerPayload, WrappedError, }; @@ -88,6 +88,8 @@ pub async fn update_flow_status_after_job_completion( stop_early_override: Option, worker_name: &str, job_completed_tx: JobCompletedSender, + flow_runners: Option>, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> error::Result>> { // this is manual tailrecursion because async_recursion blows up the stack @@ -121,6 +123,8 @@ pub async fn update_flow_status_after_job_completion( rec.has_triggered_error_handler, worker_name, job_completed_tx.clone(), + flow_runners.clone(), + killpill_rx, #[cfg(feature = "benchmark")] bench, )) @@ -147,6 +151,8 @@ pub async fn update_flow_status_after_job_completion( rec.has_triggered_error_handler, worker_name, job_completed_tx.clone(), + flow_runners.clone(), + killpill_rx, #[cfg(feature = "benchmark")] bench, )) @@ -285,6 +291,8 @@ pub async fn update_flow_status_after_job_completion_internal( has_triggered_error_handler: bool, worker_name: &str, job_completed_tx: JobCompletedSender, + flow_runners: Option>, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> error::Result { let mut has_triggered_error_handler = has_triggered_error_handler; @@ -434,7 +442,6 @@ pub async fn update_flow_status_after_job_completion_internal( args })); - let from_result_to_args = |args: &Result>, sqlx::Error>| { let args = args .as_ref() @@ -473,7 +480,7 @@ pub async fn update_flow_status_after_job_completion_internal( _ => None, }; let args = from_result_to_args(args.as_ref().await.get_ref())?; - + compute_bool_from_expr( &expr, Marc::new(args), @@ -742,7 +749,6 @@ pub async fn update_flow_status_after_job_completion_internal( &mut stop_early_err_msg, &mut nresult, args, - ) .await?; } @@ -1565,6 +1571,8 @@ pub async fn update_flow_status_after_job_completion_internal( worker_dir, job_completed_tx, worker_name, + flow_runners, + &killpill_rx, )) .warn_after_seconds(10) .await @@ -2044,6 +2052,8 @@ pub async fn handle_flow( worker_dir: &str, job_completed_tx: JobCompletedSender, worker_name: &str, + flow_runners: Option>, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, ) -> anyhow::Result<()> { let flow = flow_data.value(); let status = flow_job @@ -2101,6 +2111,9 @@ pub async fn handle_flow( same_worker_tx, worker_dir, worker_name, + flow_runners.clone(), + job_completed_tx.clone(), + &killpill_rx, )) .warn_after_seconds(10) .await?; @@ -2185,6 +2198,7 @@ struct PushNextFlowJobRec { flow_job: Arc, status: FlowStatus, } + // #[async_recursion] // #[instrument(level = "trace", skip_all)] async fn push_next_flow_job( @@ -2197,6 +2211,9 @@ async fn push_next_flow_job( same_worker_tx: &SameWorkerSender, worker_dir: &str, worker_name: &str, + flow_runners: Option>, + job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, ) -> error::Result { let job_root = flow_job .flow_innermost_root_job @@ -3028,6 +3045,22 @@ async fn push_next_flow_job( } }; + // only start runners if we're not already in a squash for loop + let start_runners = flow_runners.is_none() + && matches!( + next_status, + NextStatus::NextLoopIteration { start_runners: true, .. } + ); + + let do_not_pass_runners = matches!(next_status, NextStatus::NextStep { .. }) + && flow_runners + .as_ref() + .is_some_and(|fr| fr.job_id == flow_job.id); + + let continue_with_runners = (start_runners || (flow_runners.is_some() && !do_not_pass_runners)) + && module.suspend.is_none() + && module.sleep.is_none(); + // Also check `flow_job.same_worker` for [`JobKind::Flow`] jobs as it's no // more reflected to the flow value on push. let job_same_worker = flow_job.same_worker @@ -3083,6 +3116,7 @@ async fn push_next_flow_job( NextStatus::NextLoopIteration { next: ForloopNextIteration { new_args, .. }, simple_input_transforms, + .. } => { let mut args = if let Ok(args) = nargs { args.as_ref().clone() @@ -3300,7 +3334,7 @@ async fn push_next_flow_job( Some(module.id.clone()), new_job_priority_override, job_perms.as_ref(), - false, + continue_with_runners, None, None, None, @@ -3308,7 +3342,7 @@ async fn push_next_flow_job( .warn_after_seconds(2) .await?; - if continue_on_same_worker { + if continue_on_same_worker || continue_with_runners { let _ = sqlx::query!( "UPDATE v2_job_queue SET worker = $2 WHERE id = $1", uuid, @@ -3583,7 +3617,7 @@ async fn push_next_flow_job( .warn_after_seconds(3) .await?; - if continue_on_same_worker { + if continue_on_same_worker || continue_with_runners { if !is_one_uuid { return Err(Error::BadRequest( "Cannot continue on same worker with multiple jobs, parallel cannot be used in conjunction with same_worker".to_string(), @@ -3593,9 +3627,43 @@ async fn push_next_flow_job( tx.commit().warn_after_seconds(3).await?; tracing::info!(id = %flow_job.id, root_id = %job_root, "all next flow jobs pushed: {uuids:?}"); - if continue_on_same_worker { + if continue_on_same_worker || continue_with_runners { + let flow_runners = if start_runners { + tracing::info!(id = %flow_job.id, "starting flow runners for module {}", module.id); + let (new_flow_runners, new_flow_runner_handles) = + crate::dedicated_worker_oss::spawn_flow_module_runners( + &flow_job, + module, + flow.failure_module.as_ref(), + &killpill_rx, + db, + worker_dir, + &client.base_internal_url, + worker_name, + &job_completed_tx, + ) + .await + .with_context(|| { + format!( + "failed to spawn flow module runners for job: {}", + flow_job.id + ) + })?; + + let flow_runners = FlowRunners { + runners: new_flow_runners, + handles: new_flow_runner_handles, + job_id: flow_job.id, + }; + Some(Arc::new(flow_runners)) + } else if !do_not_pass_runners { + flow_runners + } else { + None + }; + same_worker_tx - .send(SameWorkerPayload { job_id: first_uuid, recoverable: true }) + .send(SameWorkerPayload { job_id: first_uuid, recoverable: true, flow_runners }) .warn_after_seconds(3) .await .map_err(to_anyhow)?; @@ -3702,6 +3770,7 @@ enum NextStatus { NextLoopIteration { next: ForloopNextIteration, simple_input_transforms: Option>, + start_runners: bool, }, AllFlowJobs { branchall: Option, @@ -3943,7 +4012,7 @@ async fn compute_next_flow_transform( NextStatus::NextStep, )) } - FlowModuleValue::WhileloopFlow { modules, modules_node, .. } => { + FlowModuleValue::WhileloopFlow { modules, modules_node, squash, .. } => { // if it's a simple single step flow, we will collapse it as an optimization and need to pass flow_input as an arg let is_simple = is_simple_modules(&modules, flow.failure_module.as_ref()); let (flow_jobs, flow_jobs_success, flow_jobs_duration) = match status_module { @@ -3960,6 +4029,8 @@ async fn compute_next_flow_transform( _ => (vec![], Some(vec![]), Some(FlowJobsDuration::new(0))), }; let next_loop_idx = flow_jobs.len(); + + let start_runners = next_loop_idx == 0 && squash.unwrap_or(false); next_loop_iteration( flow, status, @@ -3982,11 +4053,14 @@ async fn compute_next_flow_transform( db, module, delete_after_use, + start_runners, ) .await } /* forloop modules are expected set `iter: { value: Value, index: usize }` as job arguments */ - FlowModuleValue::ForloopFlow { modules, modules_node, iterator, parallel, .. } => { + FlowModuleValue::ForloopFlow { + modules, modules_node, iterator, parallel, squash, .. + } => { // if it's a simple single step flow, we will collapse it as an optimization and need to pass flow_input as an arg let is_simple = !matches!(flow_job.kind, JobKind::FlowPreview) && !parallel @@ -4025,6 +4099,7 @@ async fn compute_next_flow_transform( Ok(NextFlowTransform::EmptyInnerFlows { branch_chosen: None }) } ForLoopStatus::NextIteration(ns) => { + let start_runners = ns.index == 0 && squash.unwrap_or(false); next_loop_iteration( flow, status, @@ -4036,6 +4111,7 @@ async fn compute_next_flow_transform( db, module, delete_after_use, + start_runners, ) .await } @@ -4300,6 +4376,7 @@ async fn next_loop_iteration( db: &sqlx::Pool, module: &FlowModule, delete_after_use: bool, + start_runners: bool, ) -> Result { let inner_path = || format!("{}/loop-{}", flow_job.runnable_path(), ns.index); if is_simple { @@ -4317,7 +4394,7 @@ async fn next_loop_iteration( ContinuePayload::SingleJob( payload_from_simple_module(value, db, flow_job, module, inner_path()).await?, ), - NextStatus::NextLoopIteration { next: ns, simple_input_transforms }, + NextStatus::NextLoopIteration { next: ns, simple_input_transforms, start_runners }, )); } @@ -4341,7 +4418,7 @@ async fn next_loop_iteration( timeout: None, on_behalf_of: None, }), - NextStatus::NextLoopIteration { next: ns, simple_input_transforms: None }, + NextStatus::NextLoopIteration { next: ns, simple_input_transforms: None, start_runners }, )) } diff --git a/backend/windmill-worker/src/worker_lockfiles.rs b/backend/windmill-worker/src/worker_lockfiles.rs index 824a45c661..4ec0fa648e 100644 --- a/backend/windmill-worker/src/worker_lockfiles.rs +++ b/backend/windmill-worker/src/worker_lockfiles.rs @@ -1193,6 +1193,7 @@ async fn lock_modules<'c>( skip_failures, parallel, parallelism, + squash, } => { let nmodules; (nmodules, tx, nmodified_ids, nerrors) = Box::pin(lock_modules( @@ -1222,6 +1223,7 @@ async fn lock_modules<'c>( skip_failures, parallel, parallelism, + squash, } .into() } @@ -1258,7 +1260,7 @@ async fn lock_modules<'c>( } e.value = FlowModuleValue::BranchAll { branches: nbranches, parallel }.into() } - FlowModuleValue::WhileloopFlow { modules, modules_node, skip_failures } => { + FlowModuleValue::WhileloopFlow { modules, modules_node, skip_failures, squash } => { let nmodules; (nmodules, tx, nmodified_ids, nerrors) = Box::pin(lock_modules( modules, @@ -1284,6 +1286,7 @@ async fn lock_modules<'c>( modules: nmodules, modules_node, skip_failures, + squash, } .into() } diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index 3592faccdd..f94f88118b 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.582.2"; +export const VERSION = "v1.585.1"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/deno.lock b/cli/deno.lock index 801b233835..29195733e5 100644 --- a/cli/deno.lock +++ b/cli/deno.lock @@ -1,5 +1,5 @@ { - "version": "4", + "version": "5", "specifiers": { "jsr:@david/code-block-writer@^13.0.2": "13.0.2", "jsr:@deno/cache-dir@~0.10.3": "0.10.3", @@ -60,6 +60,8 @@ "jsr:@windmill-labs/cliffy-table@^1.0.0-rc.5": "1.0.0-rc.5", "npm:@ayonli/jsext@*": "1.8.0", "npm:@types/node@*": "22.12.0", + "npm:@windmill-labs/shared-utils@1.0.1": "1.0.1", + "npm:@windmill-labs/shared-utils@1.0.2": "1.0.2", "npm:centdix-utils@*": "1.0.15", "npm:diff@*": "8.0.2", "npm:es-main@*": "1.3.0", @@ -67,6 +69,7 @@ "npm:express@*": "5.1.0", "npm:get-port@7.1.0": "7.1.0", "npm:jszip@3.7.1": "3.7.1", + "npm:jszip@3.8.0": "3.8.0", "npm:minimatch@*": "10.0.3", "npm:open@*": "10.2.0", "npm:ws@*": "8.18.3" @@ -293,82 +296,134 @@ ] }, "@esbuild/aix-ppc64@0.25.8": { - "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==" + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", + "os": ["aix"], + "cpu": ["ppc64"] }, "@esbuild/android-arm64@0.25.8": { - "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==" + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", + "os": ["android"], + "cpu": ["arm64"] }, "@esbuild/android-arm@0.25.8": { - "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==" + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", + "os": ["android"], + "cpu": ["arm"] }, "@esbuild/android-x64@0.25.8": { - "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==" + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", + "os": ["android"], + "cpu": ["x64"] }, "@esbuild/darwin-arm64@0.25.8": { - "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==" + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", + "os": ["darwin"], + "cpu": ["arm64"] }, "@esbuild/darwin-x64@0.25.8": { - "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==" + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", + "os": ["darwin"], + "cpu": ["x64"] }, "@esbuild/freebsd-arm64@0.25.8": { - "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==" + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", + "os": ["freebsd"], + "cpu": ["arm64"] }, "@esbuild/freebsd-x64@0.25.8": { - "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==" + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", + "os": ["freebsd"], + "cpu": ["x64"] }, "@esbuild/linux-arm64@0.25.8": { - "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==" + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", + "os": ["linux"], + "cpu": ["arm64"] }, "@esbuild/linux-arm@0.25.8": { - "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==" + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", + "os": ["linux"], + "cpu": ["arm"] }, "@esbuild/linux-ia32@0.25.8": { - "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==" + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", + "os": ["linux"], + "cpu": ["ia32"] }, "@esbuild/linux-loong64@0.25.8": { - "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==" + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", + "os": ["linux"], + "cpu": ["loong64"] }, "@esbuild/linux-mips64el@0.25.8": { - "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==" + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", + "os": ["linux"], + "cpu": ["mips64el"] }, "@esbuild/linux-ppc64@0.25.8": { - "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==" + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", + "os": ["linux"], + "cpu": ["ppc64"] }, "@esbuild/linux-riscv64@0.25.8": { - "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==" + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", + "os": ["linux"], + "cpu": ["riscv64"] }, "@esbuild/linux-s390x@0.25.8": { - "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==" + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", + "os": ["linux"], + "cpu": ["s390x"] }, "@esbuild/linux-x64@0.25.8": { - "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==" + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", + "os": ["linux"], + "cpu": ["x64"] }, "@esbuild/netbsd-arm64@0.25.8": { - "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==" + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", + "os": ["netbsd"], + "cpu": ["arm64"] }, "@esbuild/netbsd-x64@0.25.8": { - "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==" + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", + "os": ["netbsd"], + "cpu": ["x64"] }, "@esbuild/openbsd-arm64@0.25.8": { - "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==" + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", + "os": ["openbsd"], + "cpu": ["arm64"] }, "@esbuild/openbsd-x64@0.25.8": { - "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==" + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", + "os": ["openbsd"], + "cpu": ["x64"] }, "@esbuild/openharmony-arm64@0.25.8": { - "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==" + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "os": ["openharmony"], + "cpu": ["arm64"] }, "@esbuild/sunos-x64@0.25.8": { - "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==" + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", + "os": ["sunos"], + "cpu": ["x64"] }, "@esbuild/win32-arm64@0.25.8": { - "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==" + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", + "os": ["win32"], + "cpu": ["arm64"] }, "@esbuild/win32-ia32@0.25.8": { - "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==" + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", + "os": ["win32"], + "cpu": ["ia32"] }, "@esbuild/win32-x64@0.25.8": { - "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==" + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", + "os": ["win32"], + "cpu": ["x64"] }, "@isaacs/balanced-match@4.0.1": { "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==" @@ -385,6 +440,12 @@ "undici-types" ] }, + "@windmill-labs/shared-utils@1.0.1": { + "integrity": "sha512-DUMzPIFCKImuGpbuHXXmGGUT3VXYlgrv/jIIEOW+Iig+9tZvYqOUxfgn32lDhm73k82xBg8MdAf+0qABzfqFeQ==" + }, + "@windmill-labs/shared-utils@1.0.2": { + "integrity": "sha512-3LwALmwMeO3MqglGlyTtBUF05/ogpdDM5GiZKGN7271AEctS+ZJi3pXMHZ+YZdLxdgi2qLNNnVHO8qG5vFud2Q==" + }, "accepts@2.0.0": { "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dependencies": [ @@ -509,7 +570,7 @@ }, "esbuild@0.25.8": { "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", - "dependencies": [ + "optionalDependencies": [ "@esbuild/aix-ppc64", "@esbuild/android-arm", "@esbuild/android-arm64", @@ -536,7 +597,9 @@ "@esbuild/win32-arm64", "@esbuild/win32-ia32", "@esbuild/win32-x64" - ] + ], + "scripts": true, + "bin": true }, "escape-html@1.0.3": { "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" @@ -659,13 +722,15 @@ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, "is-docker@3.0.0": { - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==" + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "bin": true }, "is-inside-container@1.0.0": { "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dependencies": [ "is-docker" - ] + ], + "bin": true }, "is-promise@4.0.0": { "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" @@ -688,6 +753,15 @@ "set-immediate-shim" ] }, + "jszip@3.8.0": { + "integrity": "sha512-cnpQrXvFSLdsR9KR5/x7zdf6c3m8IhZfZzSblFEHSqBaVwD2nvJ4CuCKLyvKvwBgZm08CgfSoiTBQLm5WW9hGw==", + "dependencies": [ + "lie", + "pako", + "readable-stream", + "set-immediate-shim" + ] + }, "lie@3.3.0": { "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dependencies": [ @@ -899,7 +973,8 @@ ] }, "sudo-prompt@9.2.1": { - "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==" + "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==", + "deprecated": true }, "toidentifier@1.0.1": { "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" diff --git a/cli/deps.ts b/cli/deps.ts index 23fd292365..e5fb176c84 100644 --- a/cli/deps.ts +++ b/cli/deps.ts @@ -49,7 +49,7 @@ export function yamlParseContent( export * as Diff from "npm:diff"; export { minimatch } from "npm:minimatch"; -export { default as JSZip } from "npm:jszip@3.7.1"; +export { default as JSZip } from "npm:jszip@3.8.0"; export * as express from "npm:express"; export * as http from "node:http"; @@ -57,6 +57,7 @@ export { WebSocketServer, WebSocket } from "npm:ws"; export * as getPort from "npm:get-port@7.1.0"; export * as open from "npm:open"; export * as esMain from "npm:es-main"; +export * as windmillUtils from "npm:@windmill-labs/shared-utils@1.0.2"; import { OpenAPI } from "./gen/index.ts"; diff --git a/cli/src/commands/app/apps.ts b/cli/src/commands/app/apps.ts index 4f1b41281d..9ed1c0d158 100644 --- a/cli/src/commands/app/apps.ts +++ b/cli/src/commands/app/apps.ts @@ -1,7 +1,15 @@ // deno-lint-ignore-file no-explicit-any import { requireLogin } from "../../core/auth.ts"; import { resolveWorkspace, validatePath } from "../../core/context.ts"; -import { colors, Command, log, SEP, Table, yamlParseFile } from "../../../deps.ts"; +import { + colors, + Command, + log, + SEP, + Table, + windmillUtils, + yamlParseFile, +} from "../../../deps.ts"; import * as wmill from "../../../gen/services.gen.ts"; import { ListableApp, Policy } from "../../../gen/types.gen.ts"; @@ -10,12 +18,16 @@ import { readInlinePathSync } from "../../utils/utils.ts"; export interface AppFile { value: any; + public?: boolean; summary: string; policy: Policy; } const alreadySynced: string[] = []; +export function isExecutionModeAnonymous(app: any) { + return app?.["policy"]?.["execution_mode"] == "anonymous"; +} export async function pushApp( workspace: string, remotePath: string, @@ -37,6 +49,13 @@ export async function pushApp( } catch { //ignore } + if (isExecutionModeAnonymous(app)) { + app.public = true; + } + // console.log(app); + if (app) { + app.policy = undefined; + } if (!localPath.endsWith(SEP)) { localPath += SEP; @@ -69,7 +88,9 @@ export async function pushApp( } replaceInlineScripts(localApp.value); - + // console.log(localApp, localApp?.["policy"]); + await generatingPolicy(localApp, remotePath, localApp?.["public"] ?? (localApp.policy ? isExecutionModeAnonymous(localApp) : false)); + // console.log(localApp, localApp?.["policy"]); if (app) { if (isSuperset(localApp, app)) { log.info(colors.green(`App ${remotePath} is up to date`)); @@ -98,6 +119,17 @@ export async function pushApp( } } +async function generatingPolicy(app: any, path: string, publicApp: boolean) { + log.info(colors.gray(`Generating fresh policy for app ${path}...`)); + try { + app.policy = await windmillUtils.updatePolicy(app.value, undefined); + app.policy.execution_mode = publicApp ? "anonymous" : "publisher"; + } catch (e) { + log.error(colors.red(`Error generating policy for app ${path}: ${e}`)); + throw e; + } +} + async function list(opts: GlobalOptions & { includeDraftOnly?: boolean }) { const workspace = await resolveWorkspace(opts); await requireLogin(opts); diff --git a/cli/src/commands/sync/sync.ts b/cli/src/commands/sync/sync.ts index 0c64a0d857..3ea6ced18c 100644 --- a/cli/src/commands/sync/sync.ts +++ b/cli/src/commands/sync/sync.ts @@ -67,6 +67,7 @@ import { PathAssigner, } from "../../../windmill-utils-internal/src/path-utils/path-assigner.ts"; import { extractInlineScripts as extractInlineScriptsForFlows } from "../../../windmill-utils-internal/src/inline-scripts/extractor.ts"; +import { isExecutionModeAnonymous } from "../app/apps.ts"; // Merge CLI options with effective settings, preserving CLI flags as overrides function mergeCliWithEffectiveOptions< @@ -415,6 +416,10 @@ function ZipFSElement( }; } + if (isExecutionModeAnonymous(app)) { + app.public = true; + } + app.policy = undefined; yield { isDirectory: false, path: path.join(finalPath, "app.yaml"), @@ -661,7 +666,6 @@ export async function elementsToMap( const map: { [key: string]: string } = {}; const processedBasePaths = new Set(); - for await (const entry of readDirRecursiveWithIgnore(ignore, els)) { if (entry.isDirectory || entry.ignored) continue; const path = entry.path; @@ -853,25 +857,6 @@ async function compareDynFSElement( } } return o; - } else if (k.endsWith(".app.yaml")) { - let o: any; - try { - o = yamlParseContent(k, v); - } catch (error) { - log.error(`Failed to parse app YAML content at path: ${k}`); - throw error; - } - const o2 = o["policy"]; - - if (typeof o2 == "object") { - if (o2["on_behalf_of"] != undefined) { - delete o2["on_behalf_of"]; - } - if (o2["on_behalf_of_email"] != undefined) { - delete o2["on_behalf_of_email"]; - } - } - return o; } else { try { return yamlParseContent(k, v); diff --git a/cli/src/main.ts b/cli/src/main.ts index 157eda767a..9f5d05f959 100644 --- a/cli/src/main.ts +++ b/cli/src/main.ts @@ -68,7 +68,7 @@ export { // } // }); -export const VERSION = "1.582.2"; +export const VERSION = "1.585.1"; export const WM_FORK_PREFIX = "wm-fork"; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 03c61556ae..4057257cf9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.582.2", + "version": "1.585.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.582.2", + "version": "1.585.1", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -142,7 +142,8 @@ "tar": "^7.4.3", "tslib": "^2.6.1", "typescript": "^5.5.0", - "vite": "npm:rolldown-vite@latest", + "vite": "npm:rolldown-vite@7.2.8", + "vite-plugin-dts": "^4.5.4", "vite-plugin-mkcert": "^1.17.5", "yootils": "^0.3.1" }, @@ -266,17 +267,42 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-identifier": { + "node_modules/@babel/helper-string-parser": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/runtime": { "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", @@ -286,6 +312,20 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@codingame/monaco-vscode-05a2a821-e4de-5941-b7f9-bbf01c09f229-common": { "version": "21.6.0", "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-05a2a821-e4de-5941-b7f9-bbf01c09f229-common/-/monaco-vscode-05a2a821-e4de-5941-b7f9-bbf01c09f229-common-21.6.0.tgz", @@ -1864,9 +1904,9 @@ } }, "node_modules/@emnapi/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", - "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", "dev": true, "license": "MIT", "optional": true, @@ -1876,9 +1916,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", "dev": true, "license": "MIT", "optional": true, @@ -2376,6 +2416,141 @@ "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0-next.118" } }, + "node_modules/@microsoft/api-extractor": { + "version": "7.55.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.55.0.tgz", + "integrity": "sha512-TYc5OtAK/9E3HGgd2bIfSjQDYIwPc0dysf9rPiwXZGsq916I6W2oww9bhm1OxPOeg6rMfOX3PoroGd7oCryYog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor-model": "7.32.0", + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.0", + "@rushstack/node-core-library": "5.18.0", + "@rushstack/rig-package": "0.6.0", + "@rushstack/terminal": "0.19.3", + "@rushstack/ts-command-line": "5.1.3", + "diff": "~8.0.2", + "lodash": "~4.17.15", + "minimatch": "10.0.3", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "source-map": "~0.6.1", + "typescript": "5.8.2" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.32.0.tgz", + "integrity": "sha512-QIVJSreb8fGGJy1Qx0yzGVXxvHJN1WXgkFNHFheVv1iBJNqgvp+xeT3ienJmRwXmPPc5Es/cxBrXtKZJR3i7iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.0", + "@rushstack/node-core-library": "5.18.0" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz", + "integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.18.0.tgz", + "integrity": "sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.16.0", + "ajv": "~8.12.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", @@ -2428,9 +2603,9 @@ } }, "node_modules/@oxc-project/runtime": { - "version": "0.92.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.92.0.tgz", - "integrity": "sha512-Z7x2dZOmznihvdvCvLKMl+nswtOSVxS2H2ocar+U9xx6iMfTp0VGIrX6a4xB1v80IwOPC7dT1LXIJrY70Xu3Jw==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.99.0.tgz", + "integrity": "sha512-8iE5/4OK0SLHqWzRxSvI1gjFPmIH6718s8iwkuco95rBZsCZIHq+5wy4lYsASxnH+8FOhbGndiUrcwsVG5i2zw==", "devOptional": true, "license": "MIT", "engines": { @@ -2438,9 +2613,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.94.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.94.0.tgz", - "integrity": "sha512-+UgQT/4o59cZfH6Cp7G0hwmqEQ0wE+AdIwhikdwnhWI9Dp8CgSY081+Q3O67/wq3VJu8mgUEB93J9EHHn70fOw==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.99.0.tgz", + "integrity": "sha512-LLDEhXB7g1m5J+woRSgfKsFPS3LhR9xRhTeIoEBm5WrkwMxn6eZ0Ld0c0K5eHB57ChZX6I3uSmmLjZ8pcjlRcw==", "devOptional": true, "license": "MIT", "funding": { @@ -2504,9 +2679,9 @@ "license": "SEE LICENSE IN LICENSE" }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.42.tgz", - "integrity": "sha512-W5ZKF3TP3bOWuBfotAGp+UGjxOkGV7jRmIRbBA7NFjggx7Oi6vOmGDqpHEIX7kDCiry1cnIsWQaxNvWbMdkvzQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.52.tgz", + "integrity": "sha512-MBGIgysimZPqTDcLXI+i9VveijkP5C3EAncEogXhqfax6YXj1Tr2LY3DVuEOMIjWfMPMhtQSPup4fSTAmgjqIw==", "cpu": [ "arm64" ], @@ -2521,9 +2696,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.42.tgz", - "integrity": "sha512-abw/wtgJA8OCgaTlL+xJxnN/Z01BwV1rfzIp5Hh9x+IIO6xOBfPsQ0nzi0+rWx3TyZ9FZXyC7bbC+5NpQ9EaXQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.52.tgz", + "integrity": "sha512-MmKeoLnKu1d9j6r19K8B+prJnIZ7u+zQ+zGQ3YHXGnr41rzE3eqQLovlkvoZnRoxDGPA4ps0pGiwXy6YE3lJyg==", "cpu": [ "arm64" ], @@ -2538,9 +2713,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.42.tgz", - "integrity": "sha512-Y/UrZIRVr8CvXVEB88t6PeC46r1K9/QdPEo2ASE/b/KBEyXIx+QbM6kv9QfQVWU2Atly2+SVsQzxQsIvuk3lZQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.52.tgz", + "integrity": "sha512-qpHedvQBmIjT8zdnjN3nWPR2qjQyJttbXniCEKKdHeAbZG9HyNPBUzQF7AZZGwmS9coQKL+hWg9FhWzh2dZ2IA==", "cpu": [ "x64" ], @@ -2555,9 +2730,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.42.tgz", - "integrity": "sha512-zRM0oOk7BZiy6DoWBvdV4hyEg+j6+WcBZIMHVirMEZRu8hd18kZdJkg+bjVMfCEhwpWeFUfBfZ1qcaZ5UdYzlQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.52.tgz", + "integrity": "sha512-dDp7WbPapj/NVW0LSiH/CLwMhmLwwKb3R7mh2kWX+QW85X1DGVnIEyKh9PmNJjB/+suG1dJygdtdNPVXK1hylg==", "cpu": [ "x64" ], @@ -2572,9 +2747,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.42.tgz", - "integrity": "sha512-6RjFaC52QNwo7ilU8C5H7swbGlgfTkG9pudXwzr3VYyT18s0C9gLg3mvc7OMPIGqNxnQ0M5lU8j6aQCk2DTRVg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.52.tgz", + "integrity": "sha512-9e4l6vy5qNSliDPqNfR6CkBOAx6PH7iDV4OJiEJzajajGrVy8gc/IKKJUsoE52G8ud8MX6r3PMl97NfwgOzB7g==", "cpu": [ "arm" ], @@ -2589,9 +2764,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.42.tgz", - "integrity": "sha512-LMYHM5Sf6ROq+VUwHMDVX2IAuEsWTv4SnlFEedBnMGpvRuQ14lCmD4m5Q8sjyAQCgyha9oghdGoK8AEg1sXZKg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.52.tgz", + "integrity": "sha512-V48oDR84feRU2KRuzpALp594Uqlx27+zFsT6+BgTcXOtu7dWy350J1G28ydoCwKB+oxwsRPx2e7aeQnmd3YJbQ==", "cpu": [ "arm64" ], @@ -2606,9 +2781,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.42.tgz", - "integrity": "sha512-/bNTYb9aKNhzdbPn3O4MK2aLv55AlrkUKPE4KNfBYjkoZUfDr4jWp7gsSlvTc5A/99V1RCm9axvt616ZzeXGyA==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.52.tgz", + "integrity": "sha512-ENLmSQCWqSA/+YN45V2FqTIemg7QspaiTjlm327eUAMeOLdqmSOVVyrQexJGNTQ5M8sDYCgVAig2Kk01Ggmqaw==", "cpu": [ "arm64" ], @@ -2623,9 +2798,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.42.tgz", - "integrity": "sha512-n/SLa4h342oyeGykZdch7Y3GNCNliRPL4k5wkeZ/5eQZs+c6/ZG1SHCJQoy7bZcmxiMyaXs9HoFmv1PEKrZgWg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.52.tgz", + "integrity": "sha512-klahlb2EIFltSUubn/VLjuc3qxp1E7th8ukayPfdkcKvvYcQ5rJztgx8JsJSuAKVzKtNTqUGOhy4On71BuyV8g==", "cpu": [ "x64" ], @@ -2640,9 +2815,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.42.tgz", - "integrity": "sha512-4PSd46sFzqpLHSGdaSViAb1mk55sCUMpJg+X8ittXaVocQsV3QLG/uydSH8RyL0ngHX5fy3D70LcCzlB15AgHw==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.52.tgz", + "integrity": "sha512-UuA+JqQIgqtkgGN2c/AQ5wi8M6mJHrahz/wciENPTeI6zEIbbLGoth5XN+sQe2pJDejEVofN9aOAp0kaazwnVg==", "cpu": [ "x64" ], @@ -2657,9 +2832,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.42.tgz", - "integrity": "sha512-BmWoeJJyeZXmZBcfoxG6J9+rl2G7eO47qdTkAzEegj4n3aC6CBIHOuDcbE8BvhZaEjQR0nh0nJrtEDlt65Q7Sw==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.52.tgz", + "integrity": "sha512-1BNQW8u4ro8bsN1+tgKENJiqmvc+WfuaUhXzMImOVSMw28pkBKdfZtX2qJPADV3terx+vNJtlsgSGeb3+W6Jiw==", "cpu": [ "arm64" ], @@ -2674,9 +2849,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.42.tgz", - "integrity": "sha512-2Ft32F7uiDTrGZUKws6CLNTlvTWHC33l4vpXrzUucf9rYtUThAdPCOt89Pmn13tNX6AulxjGEP2R0nZjTSW3eQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.52.tgz", + "integrity": "sha512-K/p7clhCqJOQpXGykrFaBX2Dp9AUVIDHGc+PtFGBwg7V+mvBTv/tsm3LC3aUmH02H2y3gz4y+nUTQ0MLpofEEg==", "cpu": [ "wasm32" ], @@ -2684,16 +2859,16 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.6" + "@napi-rs/wasm-runtime": "^1.0.7" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.42.tgz", - "integrity": "sha512-hC1kShXW/z221eG+WzQMN06KepvPbMBknF0iGR3VMYJLOe9gwnSTfGxFT5hf8XrPv7CEZqTWRd0GQpkSHRbGsw==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.52.tgz", + "integrity": "sha512-a4EkXBtnYYsKipjS7QOhEBM4bU5IlR9N1hU+JcVEVeuTiaslIyhWVKsvf7K2YkQHyVAJ+7/A9BtrGqORFcTgng==", "cpu": [ "arm64" ], @@ -2708,9 +2883,9 @@ } }, "node_modules/@rolldown/binding-win32-ia32-msvc": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.42.tgz", - "integrity": "sha512-AICBYromawouGjj+GS33369E8Vwhy6UwhQEhQ5evfS8jPCsyVvoICJatbDGDGH01dwtVGLD5eDFzPicUOVpe4g==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.52.tgz", + "integrity": "sha512-5ZXcYyd4GxPA6QfbGrNcQjmjbuLGvfz6728pZMsQvGHI+06LT06M6TPtXvFvLgXtexc+OqvFe1yAIXJU1gob/w==", "cpu": [ "ia32" ], @@ -2725,9 +2900,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.42.tgz", - "integrity": "sha512-XpZ0M+tjoEiSc9c+uZR7FCnOI0uxDRNs1elGOMjeB0pUP1QmvVbZGYNsyLbLoP4u7e3VQN8rie1OQ8/mB6rcJg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.52.tgz", + "integrity": "sha512-tzpnRQXJrSzb8Z9sm97UD3cY0toKOImx+xRKsDLX4zHaAlRXWh7jbaKBePJXEN7gNw7Nm03PBNwphdtA8KSUYQ==", "cpu": [ "x64" ], @@ -2742,12 +2917,55 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.42.tgz", - "integrity": "sha512-N7pQzk9CyE7q0bBN/q0J8s6Db279r5kUZc6d7/wWRe9/zXqC52HQovVyu6iXPIDY4BEzzgbVLhVFXrOuGJ22ZQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.52.tgz", + "integrity": "sha512-/L0htLJZbaZFL1g9OHOblTxbCYIGefErJjtYOwgl9ZqNx27P3L0SDfjhhHIss32gu5NWgnxuT2a2Hnnv6QGHKA==", "devOptional": true, "license": "MIT" }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.52.4", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", @@ -2761,6 +2979,169 @@ "linux" ] }, + "node_modules/@rushstack/node-core-library": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.18.0.tgz", + "integrity": "sha512-XDebtBdw5S3SuZIt+Ra2NieT8kQ3D2Ow1HxhDQ/2soinswnOu9e7S69VSwTOLlQnx5mpWbONu+5JJjDxMAb6Fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "~8.13.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1", + "fs-extra": "~11.3.0", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/node-core-library/node_modules/ajv": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/@rushstack/problem-matcher": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@rushstack/problem-matcher/-/problem-matcher-0.1.1.tgz", + "integrity": "sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/rig-package": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.6.0.tgz", + "integrity": "sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" + } + }, + "node_modules/@rushstack/terminal": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.19.3.tgz", + "integrity": "sha512-0P8G18gK9STyO+CNBvkKPnWGMxESxecTYqOcikHOVIHXa9uAuTK+Fw8TJq2Gng1w7W6wTC9uPX6hGNvrMll2wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.18.0", + "@rushstack/problem-matcher": "0.1.1", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.1.3.tgz", + "integrity": "sha512-Kdv0k/BnnxIYFlMVC1IxrIS0oGQd4T4b7vKfx52Y2+wk2WZSDFIvedr7JrhenzSlm3ou5KwtoTGTGd5nbODRug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/terminal": "0.19.3", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@rushstack/ts-command-line/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/@scalar/openapi-parser": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.15.0.tgz", @@ -3045,6 +3426,13 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", @@ -3648,12 +4036,162 @@ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, + "node_modules/@volar/language-core": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz", + "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.23" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz", + "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz", + "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.23", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, "node_modules/@vscode/iconv-lite-umd": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@vscode/iconv-lite-umd/-/iconv-lite-umd-0.7.0.tgz", "integrity": "sha512-bRRFxLfg5dtAyl5XyiVWz/ZBPahpOpPrNYnnHpOpUZvam4tKH35wdhP4Kj6PbM0+KdliOsPzbGWpkxcdpNB/sg==", "license": "MIT" }, + "node_modules/@vue/compiler-core": { + "version": "3.5.24", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.24.tgz", + "integrity": "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/shared": "3.5.24", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.24", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.24.tgz", + "integrity": "sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.24", + "@vue/shared": "3.5.24" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/@vue/language-core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.0.tgz", + "integrity": "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~2.4.11", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^0.4.9", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/language-core/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.24", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.24.tgz", + "integrity": "sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==", + "dev": true, + "license": "MIT" + }, "node_modules/@windmill-labs/svelte-dnd-action": { "version": "0.9.48", "resolved": "https://registry.npmjs.org/@windmill-labs/svelte-dnd-action/-/svelte-dnd-action-0.9.48.tgz", @@ -3849,6 +4387,13 @@ } } }, + "node_modules/alien-signals": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.4.14.tgz", + "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==", + "dev": true, + "license": "MIT" + }, "node_modules/amator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/amator/-/amator-1.1.0.tgz", @@ -3892,16 +4437,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", - "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", - "devOptional": true, - "license": "ISC", - "engines": { - "node": ">=14" - } - }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -4688,6 +5223,13 @@ "node": ">=18" } }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true, + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5123,6 +5665,13 @@ "url": "https://opencollective.com/date-fns" } }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, "node_modules/debounce-promise": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/debounce-promise/-/debounce-promise-3.1.2.tgz", @@ -6156,6 +6705,13 @@ "node": ">=6" } }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true, + "license": "MIT" + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -6422,6 +6978,21 @@ "license": "MIT", "optional": true }, + "node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -6804,6 +7375,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -7081,6 +7659,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/highlight.js": { "version": "11.11.1", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", @@ -7216,7 +7804,6 @@ "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -7514,6 +8101,13 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, "node_modules/js-base64": { "version": "3.7.8", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", @@ -7584,6 +8178,19 @@ "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==", "license": "MIT" }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsonpointer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", @@ -7631,6 +8238,13 @@ "dev": true, "license": "MIT" }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lerc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", @@ -8115,6 +8729,50 @@ "dev": true, "license": "MIT" }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/local-pkg/node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/local-pkg/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/local-pkg/node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", @@ -9437,6 +10095,13 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -11076,6 +11741,23 @@ "node": ">=8.x" } }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -11577,15 +12259,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.42.tgz", - "integrity": "sha512-xaPcckj+BbJhYLsv8gOqezc8EdMcKKe/gk8v47B0KPvgABDrQ0qmNPAiT/gh9n9Foe0bUkEv2qzj42uU5q1WRg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.52.tgz", + "integrity": "sha512-Hbnpljue+JhMJrlOjQ1ixp9me7sUec7OjFvS+A1Qm8k8Xyxmw3ZhxFu7LlSXW1s9AX3POE9W9o2oqCEeR5uDmg==", "devOptional": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.94.0", - "@rolldown/pluginutils": "1.0.0-beta.42", - "ansis": "=4.2.0" + "@oxc-project/types": "=0.99.0", + "@rolldown/pluginutils": "1.0.0-beta.52" }, "bin": { "rolldown": "bin/cli.mjs" @@ -11594,20 +12275,20 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-beta.42", - "@rolldown/binding-darwin-arm64": "1.0.0-beta.42", - "@rolldown/binding-darwin-x64": "1.0.0-beta.42", - "@rolldown/binding-freebsd-x64": "1.0.0-beta.42", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.42", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.42", - "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.42", - "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.42", - "@rolldown/binding-linux-x64-musl": "1.0.0-beta.42", - "@rolldown/binding-openharmony-arm64": "1.0.0-beta.42", - "@rolldown/binding-wasm32-wasi": "1.0.0-beta.42", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.42", - "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.42", - "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.42" + "@rolldown/binding-android-arm64": "1.0.0-beta.52", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.52", + "@rolldown/binding-darwin-x64": "1.0.0-beta.52", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.52", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.52", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.52", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.52", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.52", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.52", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.52", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.52", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.52", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.52", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.52" } }, "node_modules/run-parallel": { @@ -11984,6 +12665,13 @@ "license": "CC0-1.0", "peer": true }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -11993,6 +12681,16 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -13338,6 +14036,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -13448,18 +14156,18 @@ }, "node_modules/vite": { "name": "rolldown-vite", - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.1.16.tgz", - "integrity": "sha512-cK6tCmZyEC0KRAcXTjQ+ara+wkqmaE7WUoI0ZfZzDuvaRaZ3mtvbhTJc4cH+PjKRok++++Z1bZZaNlf3+SnnGA==", + "version": "7.2.8", + "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.2.8.tgz", + "integrity": "sha512-8wKihlF6EDF8grimwd7GPOhLkQkSIgj6Hlcp0CXhtO3HAXeUUqhgZmJmn07OF8e4PbTusMX6Yxmy1BptVRZsdw==", "devOptional": true, "license": "MIT", "dependencies": { - "@oxc-project/runtime": "0.92.0", + "@oxc-project/runtime": "0.99.0", "fdir": "^6.5.0", "lightningcss": "^1.30.2", "picomatch": "^4.0.3", "postcss": "^8.5.6", - "rolldown": "1.0.0-beta.42", + "rolldown": "1.0.0-beta.52", "tinyglobby": "^0.2.15" }, "bin": { @@ -13523,6 +14231,33 @@ } } }, + "node_modules/vite-plugin-dts": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.5.4.tgz", + "integrity": "sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor": "^7.50.1", + "@rollup/pluginutils": "^5.1.4", + "@volar/typescript": "^2.4.11", + "@vue/language-core": "2.2.0", + "compare-versions": "^6.1.1", + "debug": "^4.4.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17" + }, + "peerDependencies": { + "typescript": "*", + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, "node_modules/vite-plugin-mkcert": { "version": "1.17.9", "resolved": "https://registry.npmjs.org/vite-plugin-mkcert/-/vite-plugin-mkcert-1.17.9.tgz", diff --git a/frontend/package.json b/frontend/package.json index efa006da0b..1330ccff83 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,9 +1,10 @@ { "name": "windmill-components", - "version": "1.582.2", + "version": "1.585.1", "scripts": { "dev": "vite dev", "build": "vite build", + "build:utils": "vite build --config vite.sharedUtils.config.js", "preview": "vite preview", "postinstall": "node -e \"if (require('fs').existsSync('./scripts/untar_ui_builder.js')) { require('child_process').execSync('node ./scripts/untar_ui_builder.js', {stdio: 'inherit'}) }\"", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --threshold warning", @@ -64,7 +65,8 @@ "tar": "^7.4.3", "tslib": "^2.6.1", "typescript": "^5.5.0", - "vite": "npm:rolldown-vite@latest", + "vite": "npm:rolldown-vite@7.2.8", + "vite-plugin-dts": "^4.5.4", "vite-plugin-mkcert": "^1.17.5", "yootils": "^0.3.1" }, diff --git a/frontend/package.sharedUtils.json b/frontend/package.sharedUtils.json new file mode 100644 index 0000000000..e2ebbee6fd --- /dev/null +++ b/frontend/package.sharedUtils.json @@ -0,0 +1,12 @@ +{ + "name": "@windmill-labs/shared-utils", + "version": "1.0.2", + "type": "module", + "private": false, + "main": "./lib.es.js", + "module": "./lib.es.js", + "exports": { + ".": "./lib.es.js" + }, + "types": "./lib.d.ts" +} diff --git a/frontend/src/lib/components/ArgInput.svelte b/frontend/src/lib/components/ArgInput.svelte index f912fad49f..c46f85410d 100644 --- a/frontend/src/lib/components/ArgInput.svelte +++ b/frontend/src/lib/components/ArgInput.svelte @@ -1049,6 +1049,8 @@ {#if oneOf && oneOf.length >= 2} { oneOfSelected = detail const selectedObjProperties = diff --git a/frontend/src/lib/components/DBManagerDrawer.svelte b/frontend/src/lib/components/DBManagerDrawer.svelte index f54a211c7a..11ab468c9b 100644 --- a/frontend/src/lib/components/DBManagerDrawer.svelte +++ b/frontend/src/lib/components/DBManagerDrawer.svelte @@ -7,10 +7,7 @@ import { ArrowLeft, Expand, Loader2, Minimize, RefreshCcw } from 'lucide-svelte' import { dbSupportsSchemas, - getDbSchemas, getLanguageByResourceType, - loadAllTablesMetaData, - loadTableMetaData, type TableMetadata } from './apps/components/display/dbtable/utils' import DbManager from './DBManager.svelte' @@ -18,9 +15,7 @@ dbDeleteTableActionWithPreviewScript, dbTableOpsWithPreviewScripts, getDatabaseArg, - getDucklakeSchema, - wrapDucklakeQuery, - type DbInput + getDucklakeSchema } from './dbOps' import { makeCreateTableQuery } from './apps/components/display/dbtable/queries/createTable' import { runScriptAndPollResult } from './jobs/utils' @@ -28,6 +23,13 @@ import SqlRepl from './SqlRepl.svelte' import SimpleAgTable from './SimpleAgTable.svelte' import { untrack } from 'svelte' + import type { DbInput } from './dbTypes' + import { wrapDucklakeQuery } from './ducklake' + import { + getDbSchemas, + loadAllTablesMetaData, + loadTableMetaData + } from './apps/components/display/dbtable/metadata' let input: DbInput | undefined = $state() let open = $derived(!!input) diff --git a/frontend/src/lib/components/DBTableEditor.svelte b/frontend/src/lib/components/DBTableEditor.svelte index 2c5a1ba321..507e82236a 100644 --- a/frontend/src/lib/components/DBTableEditor.svelte +++ b/frontend/src/lib/components/DBTableEditor.svelte @@ -53,11 +53,7 @@ import { Cell } from './table' import DataTable from './table/DataTable.svelte' import Head from './table/Head.svelte' - import { - datatypeHasLength, - dbSupportsSchemas, - type DbType - } from './apps/components/display/dbtable/utils' + import { datatypeHasLength, dbSupportsSchemas } from './apps/components/display/dbtable/utils' import { DB_TYPES } from '$lib/consts' import Popover from './meltComponents/Popover.svelte' import Tooltip from './meltComponents/Tooltip.svelte' @@ -74,6 +70,7 @@ import Select from './select/Select.svelte' import { safeSelectItems } from './select/utils.svelte' import TextInput from './text_input/TextInput.svelte' + import type { DbType } from './dbTypes' const { onConfirm, dbType, previewSql, dbSchema, currentSchema }: DBTableEditorProps = $props() diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index 792b5184b8..9eb37b15ff 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -91,10 +91,10 @@ import { extToLang, langToExt } from '$lib/editorLangUtils' import { aiChatManager } from './copilot/chat/AIChatManager.svelte' import type { Selection } from 'monaco-editor' - import { getDbSchemas } from './apps/components/display/dbtable/utils' import { canHavePreprocessor, getPreprocessorModuleCode } from '$lib/script_helpers' import { setMonacoTypescriptOptions } from './monacoLanguagesOptions' import { copilotInfo } from '$lib/aiStore' + import { getDbSchemas } from './apps/components/display/dbtable/metadata' // import EditorTheme from './EditorTheme.svelte' let divEl: HTMLDivElement | null = $state(null) diff --git a/frontend/src/lib/components/ExploreAssetButton.svelte b/frontend/src/lib/components/ExploreAssetButton.svelte index 32ca1b15c3..c8bd5226f9 100644 --- a/frontend/src/lib/components/ExploreAssetButton.svelte +++ b/frontend/src/lib/components/ExploreAssetButton.svelte @@ -13,7 +13,7 @@ {#if queueState} -
+
Queue position: {queueState.position} {#if !minimal} (Waiting for an available worker) diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index df82c244ab..4b386aa363 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -379,7 +379,7 @@ if (templateScript) { script.content += '\r\n' + templateScript } - scriptEditor?.inferSchema(script.content, language, true) + scriptEditor?.inferSchema(script.content, { nlang: language, resetArgs: true }) if (script.content != editor?.getCode()) { setCode(script.content) } @@ -567,7 +567,7 @@ if (!disableHistoryChange) { history.replaceState(history.state, '', `/scripts/edit/${script.path}`) } - if (stay || script.kind !== 'script' || script.no_main_func) { + if (stay || (script.no_main_func && script.kind !== 'preprocessor')) { script.parent_hash = newHash sendUserToast('Deployed') } else { @@ -849,7 +849,7 @@ captureOn.set(true) } - function addPreprocessor() { + function addPreprocessor(e?: { detail?: { args: Record } }) { const code = editor?.getCode() if (code) { const preprocessorCode = getPreprocessorFullCode(script.language, false) @@ -865,6 +865,11 @@ } } selectedInputTab = 'preprocessor' + + // Apply provided args to the preprocessor + if (e?.detail?.args && Object.keys(e.detail.args).length > 0) { + args = { ...args, ...e.detail.args } + } } function handleDeployTrigger(trigger: Trigger) { diff --git a/frontend/src/lib/components/ScriptEditor.svelte b/frontend/src/lib/components/ScriptEditor.svelte index a9fcdc5cba..cd9356e34b 100644 --- a/frontend/src/lib/components/ScriptEditor.svelte +++ b/frontend/src/lib/components/ScriptEditor.svelte @@ -123,6 +123,8 @@ enablePreprocessorSnippet = false }: Props = $props() + let initialArgs = structuredClone($state.snapshot(args)) + $effect.pre(() => { if (schema == undefined) { schema = emptySchema() @@ -269,7 +271,18 @@ }) } - export async function inferSchema(code: string, nlang?: SupportedLanguage, resetArgs = false) { + export async function inferSchema( + code: string, + { + nlang, + resetArgs = false, + applyInitialArgs = false + }: { + nlang?: SupportedLanguage + resetArgs?: boolean + applyInitialArgs?: boolean + } = {} + ) { let nschema = schema ?? emptySchema() try { @@ -297,6 +310,10 @@ if (resetArgs) { args = {} } + if (applyInitialArgs) { + // we reapply initial args as the schema form might have cleared them between mount and the schema inference + args = initialArgs + } schema = nschema } catch (e) { validCode = false @@ -338,7 +355,7 @@ } onMount(() => { - inferSchema(code) + inferSchema(code, { applyInitialArgs: true }) loadPastTests() aiChatManager.saveAndClear() aiChatManager.changeMode(AIMode.SCRIPT) diff --git a/frontend/src/lib/components/ScriptEditorSkeleton.svelte b/frontend/src/lib/components/ScriptEditorSkeleton.svelte new file mode 100644 index 0000000000..031b8c9ee9 --- /dev/null +++ b/frontend/src/lib/components/ScriptEditorSkeleton.svelte @@ -0,0 +1,55 @@ +
+ +
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+ +
+
+
+
+
+
+
+
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/lib/components/ScriptPicker.svelte b/frontend/src/lib/components/ScriptPicker.svelte index a10f1c30fe..5fa0618edd 100644 --- a/frontend/src/lib/components/ScriptPicker.svelte +++ b/frontend/src/lib/components/ScriptPicker.svelte @@ -57,15 +57,19 @@ async function loadItems(): Promise { if (itemKind == 'flow') { - items = (await FlowService.listFlows({ workspace: $workspaceStore! })).map((flow) => ({ + items = ( + await FlowService.listFlows({ workspace: $workspaceStore!, withoutDescription: true }) + ).map((flow) => ({ value: flow.path, - label: `${flow.path}${flow.summary ? ` | ${truncate(flow.summary, 20)}` : ''}` + label: `${flow.path}${flow.summary ? ` | ${truncate(flow.summary, 20)}` : ''}`, + withoutDescription: true })) } else if (itemKind == 'script') { items = ( await ScriptService.listScripts({ workspace: $workspaceStore!, - kinds: kinds.join(',') + kinds: kinds.join(','), + withoutDescription: true }) ).map((script) => ({ value: script.path, diff --git a/frontend/src/lib/components/SqlRepl.svelte b/frontend/src/lib/components/SqlRepl.svelte index 92af361073..5560871520 100644 --- a/frontend/src/lib/components/SqlRepl.svelte +++ b/frontend/src/lib/components/SqlRepl.svelte @@ -55,7 +55,9 @@ import { getLanguageByResourceType } from './apps/components/display/dbtable/utils' import StepHistory, { type StepHistoryData } from './flows/propPicker/StepHistory.svelte' import { Pane, Splitpanes } from 'svelte-splitpanes' - import { getDatabaseArg, getDbType, wrapDucklakeQuery, type DbInput } from './dbOps' + import { getDatabaseArg, getDbType } from './dbOps' + import type { DbInput } from './dbTypes' + import { wrapDucklakeQuery } from './ducklake' type Props = { input: DbInput diff --git a/frontend/src/lib/components/TagsToListenTo.svelte b/frontend/src/lib/components/TagsToListenTo.svelte index 76c7fe15d6..e99c67223b 100644 --- a/frontend/src/lib/components/TagsToListenTo.svelte +++ b/frontend/src/lib/components/TagsToListenTo.svelte @@ -29,6 +29,9 @@ {disabled} class={disabled ? 'border-0' : ''} allowClear={!disabled} - onCreateItem={(c) => worker_tags.push(c)} + onCreateItem={(c) => { + worker_tags.push(c) + dispatch('dirty') + }} createText="Press Enter to use this tag" /> diff --git a/frontend/src/lib/components/apps/components/componentManagedFields.ts b/frontend/src/lib/components/apps/components/componentManagedFields.ts new file mode 100644 index 0000000000..0a9f39854d --- /dev/null +++ b/frontend/src/lib/components/apps/components/componentManagedFields.ts @@ -0,0 +1,97 @@ +/** + * Component-Managed Fields Registry + * + * This module provides a centralized registry of fields that are automatically + * managed by components at runtime, rather than being configured by users. + * + * These fields should never be treated as static fields in force_viewer_static_fields, + * as their values are determined dynamically by user interactions (pagination, + * sorting, search, chat input, etc.) + */ + +import type { AppInput } from '$lib/components/apps/inputType' + +/** + * Registry of component types to their managed field names + */ +export const COMPONENT_MANAGED_FIELDS: Record = { + aggridinfinitecomponent: ['offset', 'limit', 'orderBy', 'isDesc', 'search'], + aggridinfinitecomponentee: ['offset', 'limit', 'orderBy', 'isDesc', 'search'], + chatcomponent: ['user_message'] +} + +/** + * Get the list of managed fields for a given component type + */ +export function getManagedFields(componentType: string): string[] { + return COMPONENT_MANAGED_FIELDS[componentType] ?? [] +} + +/** + * Check if a field is managed by a specific component type + */ +export function isFieldManagedByComponent(componentType: string, fieldName: string): boolean { + const managedFields = getManagedFields(componentType) + return managedFields.includes(fieldName) +} + +/** + * Convert component-managed fields from static to evalv2 type + * This ensures they are properly handled at runtime and not added to force_viewer_static_fields + */ +export function convertManagedFieldsToEvalv2( + componentType: string, + componentId: string, + fields: Record +): Record { + const managedFieldNames = getManagedFields(componentType) + + if (managedFieldNames.length === 0) { + return fields + } + + const convertedFields = { ...fields } + + for (const fieldName of managedFieldNames) { + if (convertedFields[fieldName]) { + // Determine the expression based on component type + let expr: string + + if ( + componentType === 'aggridinfinitecomponent' || + componentType === 'aggridinfinitecomponentee' + ) { + // AgGrid components use params.{fieldName} + expr = `${componentId}.params.${fieldName}` + } else if (componentType === 'chatcomponent') { + // Chat component uses userMessage output + expr = `${componentId}.userMessage` + } else { + // Default pattern for future components + expr = `${componentId}.${fieldName}` + } + + // Convert to evalv2 type while preserving fieldType + convertedFields[fieldName] = { + type: 'evalv2', + expr, + fieldType: convertedFields[fieldName].fieldType ?? 'string', + connections: [] + } as AppInput + } + } + + return convertedFields +} + +/** + * Get all managed field names across all component types + * Useful for generic checks + */ +export function getAllManagedFieldNames(): string[] { + const allFields = new Set() + Object.values(COMPONENT_MANAGED_FIELDS).forEach((fields) => { + fields.forEach((field) => allFields.add(field)) + }) + return Array.from(allFields) +} diff --git a/frontend/src/lib/components/apps/components/display/AppChat.svelte b/frontend/src/lib/components/apps/components/display/AppChat.svelte new file mode 100644 index 0000000000..49e6f5d2a1 --- /dev/null +++ b/frontend/src/lib/components/apps/components/display/AppChat.svelte @@ -0,0 +1,338 @@ + + + + +{#each Object.keys(components['chatcomponent'].initialData.configuration) as key (key)} + +{/each} + +{#each Object.keys(css ?? {}) as key (key)} + +{/each} + + + {#if render} +
+ +
+ {#if messages.length === 0} +
+ No messages yet. Start a conversation! +
+ {:else} +
+ {#each messages as message (message.id)} + + {/each} + {#if loading} +
+ + Processing... +
+ {/if} +
+ {/if} +
+ + +
+ +
+
+ {/if} +
diff --git a/frontend/src/lib/components/apps/components/display/AppMap.svelte b/frontend/src/lib/components/apps/components/display/AppMap.svelte index 91731f5c30..a630226d7b 100644 --- a/frontend/src/lib/components/apps/components/display/AppMap.svelte +++ b/frontend/src/lib/components/apps/components/display/AppMap.svelte @@ -6,17 +6,18 @@ import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types' import { twMerge } from 'tailwind-merge' import { Map, View, Feature } from 'ol' - import { useGeographic } from 'ol/proj' - import { OSM, Vector as VectorSource } from 'ol/source' - import { Vector as VectorLayer, Tile as TileLayer } from 'ol/layer' - import { Point } from 'ol/geom' - import { defaults as defaultControls } from 'ol/control' - import { findGridItem, initConfig, initOutput } from '../../editor/appUtils' + import { useGeographic } from 'ol/proj.js' + import { OSM, Vector as VectorSource } from 'ol/source.js' + import { Vector as VectorLayer, Tile as TileLayer } from 'ol/layer.js' + import { Point } from 'ol/geom.js' + import { defaults as defaultControls } from 'ol/control.js' + import { initConfig, initOutput } from '../../editor/appUtils' import InitializeComponent from '../helpers/InitializeComponent.svelte' import ResolveStyle from '../helpers/ResolveStyle.svelte' import { components } from '../../editor/component' import ResolveConfig from '../helpers/ResolveConfig.svelte' - import { Style, Circle, Fill, Stroke, Text } from 'ol/style' + import { Style, Circle, Fill, Stroke, Text } from 'ol/style.js' + import { findGridItem } from '../../editor/appUtilsCore' interface Marker { lon: number lat: number diff --git a/frontend/src/lib/components/apps/components/display/InsertRowDrawerButton.svelte b/frontend/src/lib/components/apps/components/display/InsertRowDrawerButton.svelte index d2f0f98a8c..0bba753338 100644 --- a/frontend/src/lib/components/apps/components/display/InsertRowDrawerButton.svelte +++ b/frontend/src/lib/components/apps/components/display/InsertRowDrawerButton.svelte @@ -2,7 +2,8 @@ import { Drawer, DrawerContent, Button } from '$lib/components/common' import { CornerDownLeft, Plus } from 'lucide-svelte' import InsertRow from './dbtable/InsertRow.svelte' - import type { ColumnDef, DbType } from './dbtable/utils' + import type { ColumnDef } from './dbtable/utils' + import type { DbType } from '$lib/components/dbTypes' type Props = { columnDefs: ColumnDef[] diff --git a/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte b/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte index 9450debfaa..246fd90ff0 100644 --- a/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte +++ b/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte @@ -8,16 +8,8 @@ } from '../../../types' import { components, type TableAction } from '$lib/components/apps/editor/component' import ResolveConfig from '../../helpers/ResolveConfig.svelte' - import { findGridItem, initConfig, initOutput } from '$lib/components/apps/editor/appUtils' - import { - getDbSchemas, - loadTableMetaData, - type TableMetadata, - getPrimaryKeys, - type ColumnDef, - type DbType, - getTablesByResource - } from './utils' + import { initConfig, initOutput } from '$lib/components/apps/editor/appUtils' + import { type TableMetadata, getPrimaryKeys, type ColumnDef } from './utils' import { getContext, tick, untrack } from 'svelte' import UpdateCell from './UpdateCell.svelte' import { workspaceStore, type DBSchemas } from '$lib/stores' @@ -38,7 +30,10 @@ import RefreshButton from '$lib/components/apps/components/helpers/RefreshButton.svelte' import RunnableWrapper from '../../helpers/RunnableWrapper.svelte' import InsertRowDrawerButton from '../InsertRowDrawerButton.svelte' - import { getDucklakeSchema, type DbInput } from '$lib/components/dbOps' + import { getDucklakeSchema } from '$lib/components/dbOps' + import { findGridItem } from '$lib/components/apps/editor/appUtilsCore' + import type { DbInput, DbType } from '$lib/components/dbTypes' + import { getDbSchemas, getTablesByResource, loadTableMetaData } from './metadata' interface Props { id: string diff --git a/frontend/src/lib/components/apps/components/display/dbtable/DbExplorerCount.svelte b/frontend/src/lib/components/apps/components/display/dbtable/DbExplorerCount.svelte index 66b97cbdaf..3d9bceeed7 100644 --- a/frontend/src/lib/components/apps/components/display/dbtable/DbExplorerCount.svelte +++ b/frontend/src/lib/components/apps/components/display/dbtable/DbExplorerCount.svelte @@ -7,7 +7,7 @@ import { initOutput } from '../../../editor/appUtils' import { type ColumnDef } from './utils' import { getCountInput } from './queries/count' - import type { DbInput } from '$lib/components/dbOps' + import type { DbInput } from '$lib/components/dbTypes' interface Props { id: string diff --git a/frontend/src/lib/components/apps/components/display/dbtable/DeleteRow.svelte b/frontend/src/lib/components/apps/components/display/dbtable/DeleteRow.svelte index 36227305af..f17aa0a3a9 100644 --- a/frontend/src/lib/components/apps/components/display/dbtable/DeleteRow.svelte +++ b/frontend/src/lib/components/apps/components/display/dbtable/DeleteRow.svelte @@ -8,7 +8,7 @@ import { getPrimaryKeys, type ColumnDef } from './utils' import { sendUserToast } from '$lib/toast' import { getDeleteInput } from './queries/delete' - import type { DbInput } from '$lib/components/dbOps' + import type { DbInput } from '$lib/components/dbTypes' interface Props { id: string diff --git a/frontend/src/lib/components/apps/components/display/dbtable/InsertRow.svelte b/frontend/src/lib/components/apps/components/display/dbtable/InsertRow.svelte index 149544dac0..0483bbd272 100644 --- a/frontend/src/lib/components/apps/components/display/dbtable/InsertRow.svelte +++ b/frontend/src/lib/components/apps/components/display/dbtable/InsertRow.svelte @@ -1,6 +1,6 @@ diff --git a/frontend/src/lib/components/apps/editor/contextPanel/components/IdEditor.svelte b/frontend/src/lib/components/apps/editor/contextPanel/components/IdEditor.svelte index 80acbfe23c..408decb8a2 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/components/IdEditor.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/components/IdEditor.svelte @@ -1,10 +1,10 @@ + +
+ + {#if showCancelButton && onCancel} +
diff --git a/frontend/src/lib/components/chat/ChatMessage.svelte b/frontend/src/lib/components/chat/ChatMessage.svelte new file mode 100644 index 0000000000..f811abd0a2 --- /dev/null +++ b/frontend/src/lib/components/chat/ChatMessage.svelte @@ -0,0 +1,127 @@ + + +
+ {#if stepName} +
+ {stepName} +
+ {/if} + + {#if role === 'user'} +

{content}

+ {:else if loading} +
+ + Processing... +
+ {:else if content} + {#if s3Object} +
+ +
+ {:else if enableMarkdown} +
+ {#if role === 'tool'} + {#if success !== false} + + {:else} + + {/if} + {/if} +
+ +
+
+ {:else} +

{content}

+ {/if} + {:else} +

No result

+ {/if} +
diff --git a/frontend/src/lib/components/chat/utils.ts b/frontend/src/lib/components/chat/utils.ts new file mode 100644 index 0000000000..60f59fce10 --- /dev/null +++ b/frontend/src/lib/components/chat/utils.ts @@ -0,0 +1,30 @@ +export function parseStreamDeltas(streamData: string): { + content: string + type?: string + success?: boolean +} { + const lines = streamData.trim().split('\n') + let content = '' + let type = 'message' + let success = true + + for (const line of lines) { + if (!line.trim()) continue + try { + const parsed = JSON.parse(line) + if (parsed.type === 'tool_result') { + type = 'tool_result' + success = parsed.success + const toolName = parsed.function_name + content = success ? `Used ${toolName} tool` : `Failed to use ${toolName} tool` + } + if (parsed.type === 'token_delta' && parsed.content) { + content += parsed.content + } + } catch (e) { + console.error('Failed to parse stream line:', line, e) + } + } + + return { content, type, success } +} diff --git a/frontend/src/lib/components/common/confirmationModal/DraftTriggersConfirmationModal.svelte b/frontend/src/lib/components/common/confirmationModal/DraftTriggersConfirmationModal.svelte index cf43ab8672..e8fec0b907 100644 --- a/frontend/src/lib/components/common/confirmationModal/DraftTriggersConfirmationModal.svelte +++ b/frontend/src/lib/components/common/confirmationModal/DraftTriggersConfirmationModal.svelte @@ -10,6 +10,7 @@ import ToggleButtonGroup from '../toggleButton-v2/ToggleButtonGroup.svelte' import ToggleButton from '../toggleButton-v2/ToggleButton.svelte' import { userStore } from '$lib/stores' + import Badge from '../badge/Badge.svelte' interface Props { open?: boolean @@ -132,32 +133,22 @@ value={'discard'} {item} small - class="data-[state=on]:text-white data-[state=on]:bg-red-400 w-[54px] justify-center" + class="data-[state=on]:text-white data-[state=on]:bg-red-400 justify-center" /> {/snippet}
{:else if permission === 'admin-only'} -
- Admin only -
+ Admin only {:else if permission === 'invalid-config'} -
- Invalid config -
+ Invalid config {/if} diff --git a/frontend/src/lib/components/common/table/ScriptRow.svelte b/frontend/src/lib/components/common/table/ScriptRow.svelte index 840bac9526..1fa78d86cd 100644 --- a/frontend/src/lib/components/common/table/ScriptRow.svelte +++ b/frontend/src/lib/components/common/table/ScriptRow.svelte @@ -112,7 +112,7 @@ match + attach) -} - export function getDatabaseArg(input: DbInput | undefined) { if (input?.type === 'database') { if (input.resourcePath.startsWith('datatable://')) { diff --git a/frontend/src/lib/components/dbTypes.ts b/frontend/src/lib/components/dbTypes.ts new file mode 100644 index 0000000000..6e002efa06 --- /dev/null +++ b/frontend/src/lib/components/dbTypes.ts @@ -0,0 +1,18 @@ +export type DbInput = + | { + type: 'database' + resourceType: DbType + resourcePath: string + } + | { type: 'ducklake'; ducklake: string } + +export type DbType = (typeof dbTypes)[number] +export const dbTypes = [ + 'mysql', + 'ms_sql_server', + 'postgresql', + 'snowflake', + 'bigquery', + 'duckdb' +] as const +export const isDbType = (str?: string): str is DbType => !!str && dbTypes.includes(str as DbType) diff --git a/frontend/src/lib/components/details/DetailPageHeader.svelte b/frontend/src/lib/components/details/DetailPageHeader.svelte index c8185e2746..818c3ea76d 100644 --- a/frontend/src/lib/components/details/DetailPageHeader.svelte +++ b/frontend/src/lib/components/details/DetailPageHeader.svelte @@ -58,7 +58,7 @@
diff --git a/frontend/src/lib/components/ducklake.ts b/frontend/src/lib/components/ducklake.ts new file mode 100644 index 0000000000..fa73149b3a --- /dev/null +++ b/frontend/src/lib/components/ducklake.ts @@ -0,0 +1,4 @@ +export function wrapDucklakeQuery(query: string, ducklake: string): string { + let attach = `ATTACH 'ducklake://${ducklake}' AS dl;USE dl;\n` + return query.replace(/^(--.*\n)*/, (match) => match + attach) +} diff --git a/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte b/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte index f0288e6533..f5ca067eeb 100644 --- a/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte +++ b/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte @@ -64,7 +64,8 @@ initialPathStore, fakeInitialPath, previewArgs, - flowInputEditorState + flowInputEditorState, + stepsInputArgs } = getContext('FlowEditorContext') const selectedId = $derived(selectionManager.getSelectedId()) @@ -115,10 +116,11 @@ {:else if selectedId === 'Trigger'} { + on:addPreprocessor={async (e) => { await insertNewPreprocessorModule(flowStore, flowStateStore, { language: 'bun' }) + stepsInputArgs.setStepArgs('preprocessor', e.detail.args ?? {}) selectionManager.selectId('preprocessor') }} on:updateSchema={(e) => { diff --git a/frontend/src/lib/components/flows/content/FlowInputsFlow.svelte b/frontend/src/lib/components/flows/content/FlowInputsFlow.svelte index faee8fb3d9..9f16d95bab 100644 --- a/frontend/src/lib/components/flows/content/FlowInputsFlow.svelte +++ b/frontend/src/lib/components/flows/content/FlowInputsFlow.svelte @@ -6,28 +6,38 @@ import { workspaceStore } from '$lib/stores' import { emptyString } from '$lib/utils' - import { createEventDispatcher } from 'svelte' + import { createEventDispatcher, untrack } from 'svelte' import { flip } from 'svelte/animate' import { fade } from 'svelte/transition' + interface Props { + children?: import('svelte').Snippet + } + + let { children }: Props = $props() // export let failureModule: boolean const dispatch = createEventDispatcher() - let items: Flow[] | undefined = undefined - let filteredItems: (Flow & { marked?: string })[] | undefined = undefined - let filter = '' - $: $workspaceStore && loadFlows() + let items = $state(undefined) as Flow[] | undefined + let filteredItems = $state(undefined) as (Flow & { marked?: string })[] | undefined + let filter = $state('') - let ownerFilter: string | undefined = undefined - $: prefilteredItems = ownerFilter ? items?.filter((x) => x.path.startsWith(ownerFilter!)) : items - - $: owners = Array.from( - new Set(filteredItems?.map((x) => x.path.split('/').slice(0, 2).join('/')) ?? []) - ).sort() + let ownerFilter: string | undefined = $state(undefined) async function loadFlows() { - items = await FlowService.listFlows({ workspace: $workspaceStore! }) + items = await FlowService.listFlows({ workspace: $workspaceStore!, withoutDescription: true }) } + $effect(() => { + $workspaceStore && untrack(() => loadFlows()) + }) + let prefilteredItems = $derived( + ownerFilter ? items?.filter((x) => x.path.startsWith(ownerFilter!)) : items + ) + let owners = $derived( + Array.from( + new Set(filteredItems?.map((x) => x.path.split('/').slice(0, 2).join('/')) ?? []) + ).sort() + )

Pick a Workspace Flow

- + {@render children?.()} - - {/each} - - {:else} - {#each Array(10).fill(0) as _} - - {/each} - {/if} -
diff --git a/frontend/src/lib/components/flows/content/FlowLoop.svelte b/frontend/src/lib/components/flows/content/FlowLoop.svelte index 50e7bd2a82..4169f49f34 100644 --- a/frontend/src/lib/components/flows/content/FlowLoop.svelte +++ b/frontend/src/lib/components/flows/content/FlowLoop.svelte @@ -32,6 +32,7 @@ import { slide } from 'svelte/transition' import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte' import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte' + import Badge from '$lib/components/common/badge/Badge.svelte' const { previewArgs, flowStateStore, flowStore, currentEditor } = getContext('FlowEditorContext') @@ -186,6 +187,33 @@ class="whitespace-nowrap" />
+
+
Squash + + Beta + This can result in unexpected behavior, use at your own risk for now.
+ Squashing a for loop runs all iterations on the same worker, using a single runner + per step for the entire loop. This eliminates cold starts between iterations for supported + languages (Bun, Deno, and Python). +
+
+
+ { + ;(mod.value as ForloopFlow).squash = detail + }} + options={{ + right: 'Squash' + }} + class="whitespace-nowrap" + disabled={mod.value.parallel} + /> +
Run in parallel
diff --git a/frontend/src/lib/components/flows/content/FlowWhileLoop.svelte b/frontend/src/lib/components/flows/content/FlowWhileLoop.svelte index 81bf6c4c11..6983f7c1c6 100644 --- a/frontend/src/lib/components/flows/content/FlowWhileLoop.svelte +++ b/frontend/src/lib/components/flows/content/FlowWhileLoop.svelte @@ -14,12 +14,13 @@ import FlowModuleSleep from './FlowModuleSleep.svelte' import FlowModuleMock from './FlowModuleMock.svelte' import { Play } from 'lucide-svelte' - import type { FlowModule, Job } from '$lib/gen' + import type { FlowModule, Job, WhileloopFlow } from '$lib/gen' import FlowLoopIterationPreview from '$lib/components/FlowLoopIterationPreview.svelte' import FlowModuleDeleteAfterUse from './FlowModuleDeleteAfterUse.svelte' import FlowModuleSkip from './FlowModuleSkip.svelte' import TabsV2 from '$lib/components/common/tabs/TabsV2.svelte' import { useUiIntent } from '$lib/components/copilot/chat/flow/useUiIntent' + import Badge from '$lib/components/common/badge/Badge.svelte' const { flowStateStore } = getContext('FlowEditorContext') @@ -86,7 +87,7 @@ {#if mod.value.type === 'whileloopflow'}
-
+
Skip failures
+
+
Squash + + Beta + This can result in unexpected behavior, use at your own risk for now.
+ Squashing a for loop runs all iterations on the same worker, using a single runner + per step for the entire loop. This eliminates cold starts between iterations for supported + languages (Bun, Deno, and Python). +
+
+
+ { + ;(mod.value as WhileloopFlow).squash = detail + }} + options={{ + right: 'Squash' + }} + class="whitespace-nowrap" + /> +
diff --git a/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte b/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte index 7bbad19d25..99e3c84f88 100644 --- a/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte +++ b/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte @@ -1,8 +1,8 @@ - -
- {#if message.step_name} -
{message.step_name}
- {/if} - - {#if message.message_type === 'user'} -

{message.content}

- {:else if message.loading} -
- - Processing... -
- {:else if message.content} - {#if s3Object} -
- -
- {:else} -
- {#if message.message_type === 'tool'} - {#if message.success !== false} - - {:else} - - {/if} - {/if} -
- -
-
- {/if} - {:else} -

No result

- {/if} -
diff --git a/frontend/src/lib/components/flows/map/InsertModuleButton.svelte b/frontend/src/lib/components/flows/map/InsertModuleButton.svelte index 43068966bf..9645ec7422 100644 --- a/frontend/src/lib/components/flows/map/InsertModuleButton.svelte +++ b/frontend/src/lib/components/flows/map/InsertModuleButton.svelte @@ -11,7 +11,7 @@ let { Icon = Plus, title, id }: Props = $props() -
diff --git a/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte b/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte index c5700622d4..6d8bd34919 100644 --- a/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte +++ b/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte @@ -50,7 +50,7 @@ const validation = $derived(idx !== null ? gitSyncContext.getValidation(idx) : null) const gitSyncTestJob = $derived(idx !== null ? gitSyncContext.gitSyncTestJobs?.[idx] : null) let confirmingDelete = $state(false) - let targetBranch = $state('main') // Default to main, will be updated when resource is available + let targetBranch = $state(undefined) // Default to main, will be updated when resource is available // Update target branch when repository changes $effect(() => { @@ -108,12 +108,13 @@ ) // Determine display description based on variant and mode + const targetOrDefaultBranch = $derived(targetBranch ? `'${targetBranch}'` : 'repo\'s default' ) const displayDescription = $derived( variant === 'primary-sync' || variant === 'primary-promotion' ? mode === 'sync' - ? `Changes will be committed directly to the ${targetBranch} branch` + ? `Changes will be committed directly to the ${targetOrDefaultBranch} branch` : mode === 'promotion' - ? `Changes will be made to new branches whose promotion target is ${targetBranch}` + ? `Changes will be made to new branches whose promotion target is the ${targetOrDefaultBranch} branch` : null : null ) diff --git a/frontend/src/lib/components/graph/FlowGraphV2.svelte b/frontend/src/lib/components/graph/FlowGraphV2.svelte index 9be2534b9f..7664bae49a 100644 --- a/frontend/src/lib/components/graph/FlowGraphV2.svelte +++ b/frontend/src/lib/components/graph/FlowGraphV2.svelte @@ -397,7 +397,7 @@ }, select: (modId) => { // AI tools are not selectable by the flow. Selection has to be refactored to be simplier. - if (nodes.find((n) => n.data?.moduleId === modId)?.type === 'aiTool') { + if (nodes.find((n) => n.data?.moduleId === modId)?.type === 'aiTool' || modId === 'Trigger') { selectionManager.selectId(modId) } if (!notSelectable) { diff --git a/frontend/src/lib/components/graph/renderers/nodes/InputNode.svelte b/frontend/src/lib/components/graph/renderers/nodes/InputNode.svelte index dc76c013b6..705a07b879 100644 --- a/frontend/src/lib/components/graph/renderers/nodes/InputNode.svelte +++ b/frontend/src/lib/components/graph/renderers/nodes/InputNode.svelte @@ -12,6 +12,7 @@ import { MessageSquare, DiffIcon } from 'lucide-svelte' import { Button } from '$lib/components/common' import { getGraphContext } from '../../graphContext' + import FunnelCog from '$lib/components/icons/FunnelCog.svelte' interface Props { data: InputN['data'] @@ -71,7 +72,11 @@ }} > {#snippet trigger()} - + {/snippet}
diff --git a/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte b/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte index 048f39d9c4..d064cedf77 100644 --- a/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte +++ b/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte @@ -246,10 +246,10 @@ aiId={`trigger-button-${type}`} aiDescription={`Trigger button for ${type}`} class={twMerge( - 'hover:bg-surface-hover rounded-md shadow-sm text-xs relative center-center cursor-pointer bg-slate-100 dark:bg-slate-700', - 'dark:outline dark:outline-1 outline-tertiary/20 group', - isSelected ? 'outline-tertiary outline' : '', - small ? 'w-[23px] h-[23px] outline-[1.5px]' : 'p-2 outline-[2px]' + 'hover:bg-surface-hover rounded-md text-xs relative center-center cursor-pointer border border-border-light', + 'group', + isSelected ? 'bg-surface-accent-selected text-accent border-border-selected' : '', + small ? 'w-[23px] h-[23px]' : 'p-2' )} on:click={(e) => { e.stopPropagation() diff --git a/frontend/src/lib/components/home/ItemsList.svelte b/frontend/src/lib/components/home/ItemsList.svelte index 8e35713d4f..5b8eaeb9ac 100644 --- a/frontend/src/lib/components/home/ItemsList.svelte +++ b/frontend/src/lib/components/home/ItemsList.svelte @@ -85,7 +85,8 @@ workspace: $workspaceStore!, showArchived: archived ? true : undefined, includeWithoutMain: includeWithoutMain ? true : undefined, - includeDraftOnly: true + includeDraftOnly: true, + withoutDescription: true }) scripts = loadedScripts.map((script: Script) => { @@ -102,7 +103,8 @@ await FlowService.listFlows({ workspace: $workspaceStore!, showArchived: archived ? true : undefined, - includeDraftOnly: true + includeDraftOnly: true, + withoutDescription: true }) ).map((x: Flow) => { return { diff --git a/frontend/src/lib/components/icons/FunnelCog.svelte b/frontend/src/lib/components/icons/FunnelCog.svelte new file mode 100644 index 0000000000..12602f6849 --- /dev/null +++ b/frontend/src/lib/components/icons/FunnelCog.svelte @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/lib/components/search/GlobalSearchModal.svelte b/frontend/src/lib/components/search/GlobalSearchModal.svelte index 2463343402..51ddca9217 100644 --- a/frontend/src/lib/components/search/GlobalSearchModal.svelte +++ b/frontend/src/lib/components/search/GlobalSearchModal.svelte @@ -484,10 +484,12 @@ async function fetchCombinedItems() { const scripts = await ScriptService.listScripts({ - workspace: $workspaceStore! + workspace: $workspaceStore!, + withoutDescription: true }) const flows = await FlowService.listFlows({ - workspace: $workspaceStore! + workspace: $workspaceStore!, + withoutDescription: true }) const apps = await AppService.listApps({ workspace: $workspaceStore! }) const raw_apps = await RawAppService.listRawApps({ workspace: $workspaceStore! }) diff --git a/frontend/src/lib/components/settings/CreateToken.svelte b/frontend/src/lib/components/settings/CreateToken.svelte index ec06cabf7a..417c911d43 100644 --- a/frontend/src/lib/components/settings/CreateToken.svelte +++ b/frontend/src/lib/components/settings/CreateToken.svelte @@ -202,7 +202,8 @@ const scripts = await ScriptService.listScripts({ starredOnly: favoriteOnly, workspace, - pathStart + pathStart, + withoutDescription: true }) return scripts.map((x) => x.path) } @@ -219,7 +220,8 @@ const flows = await FlowService.listFlows({ starredOnly: favoriteOnly, workspace, - pathStart + pathStart, + withoutDescription: true }) return flows.map((x) => x.path) } diff --git a/frontend/src/lib/components/sidebar/changelogs.ts b/frontend/src/lib/components/sidebar/changelogs.ts index 777b2b73d0..80851e64ec 100644 --- a/frontend/src/lib/components/sidebar/changelogs.ts +++ b/frontend/src/lib/components/sidebar/changelogs.ts @@ -5,6 +5,12 @@ export type Changelog = { } const changelogs: Changelog[] = [ + { + label: 'AWS Bedrock support for Windmill AI', + href: 'https://www.windmill.dev/changelog/aws-bedrock', + date: '2025-11-19' + }, + { label: 'Dynamic select for flows', href: 'https://www.windmill.dev/changelog/dynamic-select-flows', diff --git a/frontend/src/lib/components/triggers/AddTriggersButton.svelte b/frontend/src/lib/components/triggers/AddTriggersButton.svelte index 6e056ef07d..1c71bcdb24 100644 --- a/frontend/src/lib/components/triggers/AddTriggersButton.svelte +++ b/frontend/src/lib/components/triggers/AddTriggersButton.svelte @@ -23,7 +23,7 @@ setDropdownWidthToButtonWidth = false, children, class: className, - placement = 'bottom', + placement = 'bottom-start', isEditor = false, onAddDraftTrigger, onAddScheduledPoll, diff --git a/frontend/src/lib/components/triggers/CaptureSection.svelte b/frontend/src/lib/components/triggers/CaptureSection.svelte index 366b03dc1a..eebfe3c1a7 100644 --- a/frontend/src/lib/components/triggers/CaptureSection.svelte +++ b/frontend/src/lib/components/triggers/CaptureSection.svelte @@ -14,7 +14,7 @@ import AnimatedButton from '../common/button/AnimatedButton.svelte' import PulseButton from '../common/button/PulseButton.svelte' import Button from '../common/button/Button.svelte' - import { CircleStop, History, Play, Loader2 } from 'lucide-svelte' + import { CircleStop, History, Play, Loader2, ExternalLink } from 'lucide-svelte' import ConnectionIndicator, { type ConnectionInfo } from '../common/alert/ConnectionIndicator.svelte' @@ -67,7 +67,7 @@ const dispatch = createEventDispatcher<{ captureToggle: { disableOnly?: boolean } updateSchema: { payloadData: Record; redirect: boolean; args?: boolean } - addPreprocessor: null + addPreprocessor: { args: Record } | null testWithArgs: Record applyArgs: { kind: 'main' | 'preprocessor'; args: Record } }>() @@ -121,6 +121,7 @@ let lastCaptureId: number | undefined = undefined let displayResult: DisplayResult | undefined = $state(undefined) let toolbarLocation: 'internal' | 'external' | undefined = $state(undefined) + let showRawPayload = $state(false) function selectCapture(capture: Capture) { selectedCapture = capture @@ -225,13 +226,14 @@ } } - function getCapturePayload(capture: Capture) { + function getCapturePayload(capture: Capture | undefined, showRawPayload: boolean) { + if (!capture) return {} let payloadData: any = {} const preprocessor_args = isObject(capture.preprocessor_args) ? capture.preprocessor_args : {} if ('wm_trigger' in preprocessor_args) { // v1 payloadData = - testKind === 'preprocessor' + testKind === 'preprocessor' || showRawPayload ? { ...(typeof capture.main_args === 'object' ? capture.main_args : {}), ...preprocessor_args @@ -239,11 +241,20 @@ : capture.main_args } else { // v2 - payloadData = testKind === 'preprocessor' ? capture.preprocessor_args : capture.main_args + payloadData = + testKind === 'preprocessor' || showRawPayload + ? capture.preprocessor_args + : capture.main_args } return payloadData } + function toggleRawPayload() { + showRawPayload = !showRawPayload + } + + const payloadData = $derived(getCapturePayload(selectedCapture, showRawPayload)) + // Start or stop capture listening based on active state $effect(() => { if (captureInfo.active) { @@ -380,16 +391,16 @@ {#if selectedCapture} {@const SvelteComponent = triggerIconMap[captureType]}
- + Capture {formatDateShort(selectedCapture?.created_at)}
{/if} - {#if selectedCapture} + {#if selectedCapture && !showRawPayload} {@const label = isFlow && testKind === 'main' ? 'Test flow with args' : 'Apply args'} {@const title = isFlow && testKind === 'main' @@ -455,26 +466,73 @@ /> {/if}
-
- {#if isLoadingBigPayload} - - {:else if selectedCapture?.main_args} -
- { - toolbarLocation = detail - }} - /> +
+
+ {#if isLoadingBigPayload} + + {:else if selectedCapture?.main_args} +
+ {#if showRawPayload} + +
+
+ Add a preprocessor to use the raw payload data in the flow. + + Learn more about preprocessors + + +
+
+ +
+
+
+ {/if} + { + toolbarLocation = detail + }} + /> +
+ {:else} +
No captures to show yet.
+ {/if} +
+ + {#if !hasPreprocessor && !isLoadingBigPayload && selectedCapture?.main_args} +
+ {showRawPayload ? '' : 'Need more data about the trigger event?'} +
- {:else} -
No captures to show yet.
{/if}
diff --git a/frontend/src/lib/components/triggers/CaptureTable.svelte b/frontend/src/lib/components/triggers/CaptureTable.svelte index 20f3703921..f6bc1d209f 100644 --- a/frontend/src/lib/components/triggers/CaptureTable.svelte +++ b/frontend/src/lib/components/triggers/CaptureTable.svelte @@ -71,7 +71,7 @@ kind: 'main' | 'preprocessor' args: Record | undefined } - addPreprocessor: null + addPreprocessor: { args: Record } | undefined updateSchema: { payloadData: any redirect: boolean diff --git a/frontend/src/lib/components/triggers/DeleteTriggerButton.svelte b/frontend/src/lib/components/triggers/DeleteTriggerButton.svelte index 1b4d6f8954..b7fed3d6d0 100644 --- a/frontend/src/lib/components/triggers/DeleteTriggerButton.svelte +++ b/frontend/src/lib/components/triggers/DeleteTriggerButton.svelte @@ -39,12 +39,12 @@ @@ -59,8 +59,11 @@ {@const SvelteComponent = triggerIconMap[trigger.type]} onSelect?.(index)} use:triggerableByAI={{ @@ -69,12 +72,9 @@ callback: () => onSelect?.(index) }} > - +
- + {#if trigger.isPrimary} diff --git a/frontend/src/lib/components/triggers/TriggersWrapper.svelte b/frontend/src/lib/components/triggers/TriggersWrapper.svelte index 5030069f10..973931ceb2 100644 --- a/frontend/src/lib/components/triggers/TriggersWrapper.svelte +++ b/frontend/src/lib/components/triggers/TriggersWrapper.svelte @@ -16,7 +16,6 @@ import ClipboardPanel from '../details/ClipboardPanel.svelte' import CliHelpBox from '../CliHelpBox.svelte' import TriggerLabel from './TriggerLabel.svelte' - import { twMerge } from 'tailwind-merge' interface Props { selectedTrigger: Trigger @@ -178,10 +177,7 @@ {#snippet customLabel()} {@const IconComponent = triggerIconMap[selectedTrigger.type]}
- +
{/snippet} diff --git a/frontend/src/lib/components/tutorials/utils.ts b/frontend/src/lib/components/tutorials/utils.ts index 066d052f9c..c762a225a5 100644 --- a/frontend/src/lib/components/tutorials/utils.ts +++ b/frontend/src/lib/components/tutorials/utils.ts @@ -1,7 +1,8 @@ import type { FlowModule, OpenFlow } from '$lib/gen' import { deepEqual } from 'fast-equals' -import { emptyApp, findGridItem } from '../apps/editor/appUtils' +import { emptyApp } from '../apps/editor/appUtils' import type { App } from '../apps/types' +import { findGridItem } from '../apps/editor/appUtilsCore' export function setInputBySelector(selector: string, value: string) { const input = document.querySelector(selector) as HTMLInputElement diff --git a/frontend/src/lib/components/wizards/AgChartWizard.svelte b/frontend/src/lib/components/wizards/AgChartWizard.svelte index a5840778c2..372ef68113 100644 --- a/frontend/src/lib/components/wizards/AgChartWizard.svelte +++ b/frontend/src/lib/components/wizards/AgChartWizard.svelte @@ -6,7 +6,7 @@ import Button from '../common/button/Button.svelte' import OneOfInputSpecsEditor from '../apps/editor/settingsPanel/OneOfInputSpecsEditor.svelte' import type { AppViewerContext, GridItem, RichConfiguration } from '../apps/types' - import { findGridItem } from '../apps/editor/appUtils' + import { findGridItem } from '../apps/editor/appUtilsCore' const { selectedComponent, app } = getContext('AppViewerContext') diff --git a/frontend/src/lib/consts.ts b/frontend/src/lib/consts.ts index 32f54f723c..7630838a4f 100644 --- a/frontend/src/lib/consts.ts +++ b/frontend/src/lib/consts.ts @@ -1,4 +1,4 @@ -import type { DbType } from './components/apps/components/display/dbtable/utils' +import type { DbType } from './components/dbTypes' export const DEFAULT_WEBHOOK_TYPE: 'async' | 'sync' = 'async' diff --git a/frontend/src/lib/hub.ts b/frontend/src/lib/hub.ts index 13e702a2bf..78a617397b 100644 --- a/frontend/src/lib/hub.ts +++ b/frontend/src/lib/hub.ts @@ -98,6 +98,7 @@ type HubPaths = { teamsSuccessHandler: string emailErrorHandler: string cloneRepoToS3forGitRepoViewer: string + appReport: string } export const hubPaths = JSON.parse(rawHubPaths) as HubPaths diff --git a/frontend/src/lib/hubPaths.json b/frontend/src/lib/hubPaths.json index e5244469ea..80ec7eff19 100644 --- a/frontend/src/lib/hubPaths.json +++ b/frontend/src/lib/hubPaths.json @@ -16,7 +16,8 @@ "gitSync_14": "hub/19803/sync-script-to-git-repo-windmill", "gitSync_15": "hub/19816/sync-script-to-git-repo-windmill", "gitSync_16": "hub/19818/sync-script-to-git-repo-windmill", - "gitSync": "hub/28073/sync-script-to-git-repo-windmill", + "gitSync_17": "hub/28073/sync-script-to-git-repo-windmill", + "gitSync": "hub/28078/sync-script-to-git-repo-windmill", "gitSyncTest_0": "hub/9073/git-repo-test-read-write-windmill", "gitSyncTest_1": "hub/11499/git-repo-test-read-write-windmill", "gitSyncTest_2": "hub/11667/git-repo-test-read-write-windmill", @@ -25,7 +26,8 @@ "gitInitRepo_0": "hub/19787/git-sync%3A-init-repository-windmill", "gitInitRepo_1": "hub/19797/git-sync%3A-init-repository-windmill", "gitInitRepo_2": "hub/19817/git-sync%3A-init-repository-windmill", - "gitInitRepo": "hub/28072/git-sync%3A-init-repository-windmill", + "gitInitRepo_3": "hub/28072/git-sync%3A-init-repository-windmill", + "gitInitRepo": "hub/28077/git-sync%3A-init-repository-windmill", "slackErrorHandler": "hub/19741/workspace-or-schedule-error-handler-slack", "slackErrorHandler_0": "hub/9079/workspace-or-schedule-error-handler-slack", "slackErrorHandler_1": "hub/9206/workspace-or-schedule-error-handler-slack", @@ -39,6 +41,7 @@ "slackReport": "hub/9084/slack", "discordReport": "hub/9085/discord", "smtpReport": "hub/9086/smtp", + "appReport": "hub/28076/app-report", "cloneRepoToS3forGitRepoViewer_0": "hub/19825/clone_repo_and_upload_to_instance_storage", "cloneRepoToS3forGitRepoViewer": "hub/19827/clone_repo_and_upload_to_instance_storage" } diff --git a/frontend/src/lib/script_helpers.ts b/frontend/src/lib/script_helpers.ts index 532c11cab1..58bec208de 100644 --- a/frontend/src/lib/script_helpers.ts +++ b/frontend/src/lib/script_helpers.ts @@ -691,16 +691,21 @@ export const TS_PREPROCESSOR_FLOW_INTRO = `/** * Learn more: https://www.windmill.dev/docs/core_concepts/preprocessors */\n` -export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( - event: - | { +export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor(event: TriggerEvent) { + return { + // return the args to be passed to the runnable + }; +} + +type TriggerEvent = + | { kind: "webhook"; body: any; raw_string: string | null; query: Record; headers: Record; } - | { + | { kind: "http"; body: any; raw_string: string | null; @@ -711,21 +716,21 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( query: Record; headers: Record; } - | { + | { kind: "email"; parsed_email: any; raw_email: string; email_extra_args?: Record; } - | { kind: "websocket"; msg: string; url: string } - | { + | { kind: "websocket"; msg: string; url: string } + | { kind: "kafka"; payload: string; brokers: string[]; topic: string; group_id: string; } - | { + | { kind: "nats"; payload: string; servers: string[]; @@ -735,7 +740,7 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( description?: string; length: number; } - | { + | { kind: "sqs"; msg: string; queue_url: string; @@ -747,7 +752,7 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( { string_value?: string; data_type: string } >; } - | { + | { kind: "mqtt"; payload: string; topic: string; @@ -764,7 +769,7 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( content_type?: string; }; } - | { + | { kind: "gcp"; payload: string; message_id: string; @@ -776,19 +781,14 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( publish_time?: string; ack_id?: string; } - | { + | { kind: "postgres"; - transaction_type: "insert" | "update" | "delete", - schema_name: string, - table_name: string, - old_row?: Record, - row: Record - } -) { - return { - // return the args to be passed to the runnable - }; -} + transaction_type: "insert" | "update" | "delete"; + schema_name: string; + table_name: string; + old_row?: Record; + row: Record; + }; ` const PYTHON_INIT_CODE_APPROVAL = `import wmill diff --git a/frontend/src/lib/stores.ts b/frontend/src/lib/stores.ts index 91ecfd1262..5632bff47a 100644 --- a/frontend/src/lib/stores.ts +++ b/frontend/src/lib/stores.ts @@ -3,9 +3,11 @@ import { derived, type Readable, writable } from 'svelte/store' import type { IntrospectionQuery } from 'graphql' import { + CancelablePromise, type OperatorSettings, type TokenResponse, type UserWorkspaceList, + type Workspace, type WorkspaceDefaultScripts, WorkspaceService } from './gen' @@ -168,32 +170,40 @@ export const instanceSettingsSelectedTab = writable('Core') export const isCriticalAlertsUIOpen = writable(false) +let getWorkspacePromise: CancelablePromise | null = null export const workspaceColor: Readable = derived( [workspaceStore, usersWorkspaceStore, superadmin], ([workspaceStore, usersWorkspaceStore, superadmin], set: (value: string | undefined) => void) => { - if (!workspaceStore) { - set(undefined) + if (!workspaceStore || !usersWorkspaceStore) { return } // First try to get the color from usersWorkspaceStore - const color = usersWorkspaceStore?.workspaces.find((w) => w.id === workspaceStore)?.color + const workspace = usersWorkspaceStore.workspaces.find((w) => w.id === workspaceStore) - if (color) { - set(color) + if (workspace) { + set(workspace.color) return } - // If not found and user is superadmin, try to get it from superadmin list + // If workspace not found and user is superadmin, get it as superadmin if (!superadmin) { set(undefined) return } - WorkspaceService.listWorkspacesAsSuperAdmin().then((workspaces) => { - const superadminColor = workspaces.find((w) => w.id === workspaceStore)?.color - set(superadminColor) + getWorkspacePromise?.cancel() + + getWorkspacePromise = WorkspaceService.getWorkspaceAsSuperAdmin({ + workspace: workspaceStore }) + + getWorkspacePromise + .then((workspace) => set(workspace.color)) + .catch((error) => { + console.error('error getting workspace as superadmin', error) + set(undefined) + }) } ) diff --git a/frontend/src/routes/(root)/(logged)/+layout.svelte b/frontend/src/routes/(root)/(logged)/+layout.svelte index b0328df532..032961cd9a 100644 --- a/frontend/src/routes/(root)/(logged)/+layout.svelte +++ b/frontend/src/routes/(root)/(logged)/+layout.svelte @@ -155,11 +155,13 @@ const scripts = await ScriptService.listScripts({ workspace: $workspaceStore ?? '', starredOnly: true, - includeWithoutMain: true + includeWithoutMain: true, + withoutDescription: true }) const flows = await FlowService.listFlows({ workspace: $workspaceStore ?? '', - starredOnly: true + starredOnly: true, + withoutDescription: true }) const apps = await AppService.listApps({ workspace: $workspaceStore ?? '', diff --git a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte index 45df378067..5858307037 100644 --- a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte @@ -27,8 +27,13 @@ let nodraft = page.url.searchParams.get('nodraft') const initialState = nodraft ? undefined : localStorage.getItem(`flow-${page.params.path}`) let stateLoadedFromUrl = initialState != undefined ? decodeState(initialState) : undefined + + const urlArgs = page.url.searchParams.get('initial_args') + let initialArgs = $state({}) - if ($initialArgsStore) { + if (urlArgs) { + initialArgs = decodeState(urlArgs) + } else if ($initialArgsStore) { initialArgs = $initialArgsStore $initialArgsStore = undefined } diff --git a/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte index 43eeab456b..55c0b4f775 100644 --- a/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte @@ -33,10 +33,10 @@ GitFork, Play, History, - Columns, Pen, Eye, - HistoryIcon + HistoryIcon, + LayoutDashboard } from 'lucide-svelte' import DetailPageHeader from '$lib/components/details/DetailPageHeader.svelte' @@ -238,7 +238,7 @@ buttonProps: { href: `${base}/flows/add?template=${flow.path}`, variant: 'subtle', - size: 'xs', + unifiedSize: 'md', startIcon: GitFork } }) @@ -252,7 +252,7 @@ label: `Runs`, buttonProps: { href: `${base}/runs/${flow.path}`, - size: 'xs', + unifiedSize: 'md', variant: 'subtle', startIcon: Play } @@ -262,7 +262,7 @@ label: `History`, buttonProps: { onClick: () => flowHistory?.open(), - size: 'xs', + unifiedSize: 'md', variant: 'subtle', startIcon: History } @@ -281,9 +281,9 @@ $importStore = JSON.parse(JSON.stringify(app)) await goto('/apps/add?nodraft=true') }, - size: 'xs', - variant: 'accent', - startIcon: Columns + unifiedSize: 'md', + variant: 'subtle', + startIcon: LayoutDashboard } }) @@ -291,8 +291,8 @@ label: 'Edit', buttonProps: { href: `${base}/flows/edit/${path}?nodraft=true`, - variant: 'accent-secondary', - size: 'xs', + variant: 'accent', + unifiedSize: 'md', disabled: !can_write, startIcon: Pen } diff --git a/frontend/src/routes/(root)/(logged)/resources/+page.svelte b/frontend/src/routes/(root)/(logged)/resources/+page.svelte index 0452b14ffe..54a88584e8 100644 --- a/frontend/src/routes/(root)/(logged)/resources/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/resources/+page.svelte @@ -34,6 +34,7 @@ import { canWrite, classNames, + debounce, emptySchema, removeMarkdown, truncate, @@ -95,6 +96,7 @@ formatExtension: undefined }) let isNewResourceTypeNameValid: boolean = $state(false) + let resourceTypeNameExists: boolean = $state(false) let editResourceType = $state({ name: '', @@ -224,8 +226,26 @@ } const startNewType = () => { + // Find a unique name by checking for duplicates and appending a number + const baseName = 'my_resource_type' + let uniqueName = baseName + let counter = 2 + + // Check if the base name or numbered variants exist + while (true) { + const fullName = (disableCustomPrefix ? '' : 'c_') + uniqueName + const exists = resourceTypes?.some((rt) => rt.name === fullName) ?? false + + if (!exists) { + break + } + + uniqueName = `${baseName}_${counter}` + counter++ + } + newResourceType = { - name: 'my_resource_type', + name: uniqueName, schema: emptySchema(), description: '', formatExtension: undefined @@ -327,8 +347,25 @@ function validateResourceTypeName() { const snakeCaseRegex = /^[a-z0-9]+(_[a-z0-9]+)*$/ isNewResourceTypeNameValid = snakeCaseRegex.test(newResourceType.name) + checkResourceTypeNameExists.debounced() } + const checkResourceTypeNameExists = debounce(() => { + if (!newResourceType.name) { + resourceTypeNameExists = false + return + } + const fullName = (disableCustomPrefix ? '' : 'c_') + newResourceType.name + resourceTypeNameExists = resourceTypes?.some((rt) => rt.name === fullName) ?? false + }, 300) + + // Re-check when prefix setting changes + $effect(() => { + if (disableCustomPrefix !== undefined) { + checkResourceTypeNameExists.debounced() + } + }) + function toSnakeCase() { newResourceType.name = newResourceType.name .replace(/([a-z0-9])([A-Z])/g, '$1_$2') @@ -576,7 +613,7 @@ Save {/snippet}
@@ -620,6 +657,10 @@ >Name must be snake_case!

+ {:else if resourceTypeNameExists} +

A resource type with this name already exists!

{/if} {/if} diff --git a/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte b/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte index b9bcfe9a6a..0418cb9a08 100644 --- a/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte @@ -320,7 +320,8 @@ flow: { value: job?.raw_flow }, path: job?.script_path + '_fork' } - window.open(`/flows/add#${encodeState(state)}`) + const encodedArgs = encodeState(job?.args) + window.open(`/flows/add?initial_args=${encodedArgs}#${encodeState(state)}`) } else { $initialArgsStore = job?.args let n: NewScript = { @@ -328,9 +329,11 @@ summary: 'Fork of preview of ' + job?.script_path, language: job?.language as NewScript['language'], description: '', - content: job?.raw_code ?? '' + content: job?.raw_code ?? '', + kind: 'script' } - window.open(`/scripts/add#${encodeState(n)}`) + const encodedArgs = encodeState(job?.args) + window.open(`/scripts/add?initial_args=${encodedArgs}#${encodeState(n)}`) } } diff --git a/frontend/src/routes/(root)/(logged)/scripts/add/+page.svelte b/frontend/src/routes/(root)/(logged)/scripts/add/+page.svelte index d6f933ce2c..ec264673bb 100644 --- a/frontend/src/routes/(root)/(logged)/scripts/add/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/scripts/add/+page.svelte @@ -1,11 +1,11 @@ - { - goto(`/scripts/get/${e.hash}?workspace=${$workspaceStore}`) - }} - onSaveInitial={(e) => { - goto(`/scripts/edit/${e.path}`) - }} - searchParams={$page.url.searchParams} - bind:script - {showMeta} - replaceStateFn={(path) => replaceState(path, $page.state)} -> - - +{#if script} + { + goto(`/scripts/get/${e.hash}?workspace=${$workspaceStore}`) + }} + onSaveInitial={(e) => { + goto(`/scripts/edit/${e.path}`) + }} + searchParams={$page.url.searchParams} + bind:script + {showMeta} + replaceStateFn={(path) => replaceState(path, $page.state)} + > + + +{:else} + +{/if} diff --git a/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte b/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte index 76f22642bd..0dbe481e9f 100644 --- a/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte @@ -58,10 +58,10 @@ Pen, ChevronUpSquare, Share, - Table2, Trash, Play, - ClipboardCopy + ClipboardCopy, + LayoutDashboard } from 'lucide-svelte' import { SCRIPT_VIEW_SHOW_PUBLISH_TO_HUB } from '$lib/consts' import { scriptToHubUrl } from '$lib/hub' @@ -339,8 +339,8 @@ }, unifiedSize: 'md', - variant: 'accent', - startIcon: Table2 + variant: 'subtle', + startIcon: LayoutDashboard } }) @@ -367,7 +367,7 @@ }`, unifiedSize: 'md', startIcon: Pen, - variant: 'accent-secondary', + variant: 'accent', disabled: !can_write } }) @@ -783,6 +783,9 @@ on:selected_args={(e) => { const nargs = JSON.parse(JSON.stringify(e.detail)) args = nargs + if (jsonView) { + runForm?.setCode(JSON.stringify(args ?? {}, null, '\t')) + } }} /> {/if} diff --git a/frontend/src/routes/(root)/(logged)/workers/+page.svelte b/frontend/src/routes/(root)/(logged)/workers/+page.svelte index 4afc391e88..e127ba9a36 100644 --- a/frontend/src/routes/(root)/(logged)/workers/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/workers/+page.svelte @@ -112,6 +112,70 @@ } } + function parseLicenseKey(key: string): { + valid: boolean + expiration?: Date + } { + let splitted = key.split('.') + if (splitted.length >= 3) { + try { + let i = parseInt(splitted[1]) + let date = new Date(i * 1000) + const stringDate = date.toLocaleDateString() + if (stringDate !== 'Invalid Date') { + return { + valid: date.getTime() > Date.now(), + expiration: date + } + } + } catch {} + } + return { + valid: false + } + } + + async function checkLicenseExpiration() { + if (!$superadmin || !$enterpriseLicense) { + return + } + + try { + const licenseKey = (await SettingService.getGlobal({ + key: 'license_key' + })) as string + + if (!licenseKey) { + return + } + + const { valid, expiration } = parseLicenseKey(licenseKey) + + if (!valid && expiration) { + // License is expired + sendUserToast( + `Enterprise license key expired on ${expiration.toLocaleDateString()}. Please renew your license key to continue using Windmill.`, + true + ) + } else if (expiration) { + // Check if expires within 7 days + const daysUntilExpiration = Math.floor( + (expiration.getTime() - Date.now()) / (1000 * 60 * 60 * 24) + ) + + if (daysUntilExpiration <= 7 && daysUntilExpiration >= 0) { + sendUserToast( + `Enterprise license key expires in ${daysUntilExpiration} day${daysUntilExpiration !== 1 ? 's' : ''} on ${expiration.toLocaleDateString()}. Please renew your license key to continue using Windmill.`, + true + ) + } + } + } catch (err) { + // Silently fail - don't show errors for license check + console.error('Failed to check license expiration:', err) + } + } + onMount(() => { intervalId = setInterval(() => { loadWorkers() @@ -126,6 +190,7 @@ loadWorkerGroups() loadCustomTags() $: ($superadmin || $devopsRole) && loadDefaultTagsPerWorkspace() + $: $superadmin && $enterpriseLicense && checkLicenseExpiration() onDestroy(() => { if (intervalId) { diff --git a/frontend/vite.sharedUtils.config.js b/frontend/vite.sharedUtils.config.js new file mode 100644 index 0000000000..24428edc10 --- /dev/null +++ b/frontend/vite.sharedUtils.config.js @@ -0,0 +1,59 @@ +import { defineConfig } from 'vite' +import { resolve } from 'path' +import { copyFileSync, readFileSync, writeFileSync } from 'fs' +import dts from 'vite-plugin-dts' + +export default defineConfig({ + build: { + lib: { + entry: resolve(__dirname, 'src/lib/components/apps/editor/appPolicy.ts'), + name: 'sharedUtils', + fileName: (format) => `lib.${format}.js`, + formats: ['es'] + }, + outDir: 'dist/sharedUtils', + rollupOptions: { + // Externalize dependencies you don't want bundled + external: [], + output: { + globals: {} + } + } + }, + plugins: [ + dts({ + include: ['src/lib/components/apps/editor/appPolicy.ts'], + outDir: 'dist/sharedUtils', + rollupTypes: false, + // Generate individual .d.ts files + insertTypesEntry: false, + // Skip diagnostics to avoid TypeScript errors from other files + skipDiagnostics: true, + tsconfigPath: './tsconfig.json', + entryRoot: 'src/lib/components/apps/editor' + }), + { + name: 'rename-and-fix-types', + closeBundle() { + const dtsPath = resolve(__dirname, 'dist/sharedUtils/appPolicy.d.ts') + const targetPath = resolve(__dirname, 'dist/sharedUtils/lib.d.ts') + + // Read the generated .d.ts file + const content = readFileSync(dtsPath, 'utf-8') + + // Write to lib.d.ts (main entry point for types) + writeFileSync(targetPath, content) + } + }, + { + name: 'copy-package-json', + closeBundle() { + // Copy package.json to dist + copyFileSync( + resolve(__dirname, 'package.sharedUtils.json'), + resolve(__dirname, 'dist/sharedUtils/package.json') + ) + } + } + ] +}) diff --git a/lsp/Pipfile b/lsp/Pipfile index 108c9edfb9..cd1c2f7c31 100644 --- a/lsp/Pipfile +++ b/lsp/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -wmill = ">=1.582.2" -wmill_pg = ">=1.582.2" +wmill = ">=1.585.1" +wmill_pg = ">=1.585.1" sendgrid = "*" mysql-connector-python = "*" pymongo = "*" diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index 3fcee0134e..babeb61cfc 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.582.2 + version: 1.585.1 title: OpenFlow Spec contact: name: Ruben Fiszel @@ -447,6 +447,8 @@ components: type: boolean parallelism: $ref: "#/components/schemas/InputTransform" + squash: + type: boolean required: - modules - iterator @@ -470,6 +472,8 @@ components: type: boolean parallelism: $ref: "#/components/schemas/InputTransform" + squash: + type: boolean required: - modules - skip_failures diff --git a/powershell-client/WindmillClient/WindmillClient.psd1 b/powershell-client/WindmillClient/WindmillClient.psd1 index b90734f2ba..44fe48eec6 100644 --- a/powershell-client/WindmillClient/WindmillClient.psd1 +++ b/powershell-client/WindmillClient/WindmillClient.psd1 @@ -12,7 +12,7 @@ RootModule = 'WindmillClient.psm1' # Version number of this module. - ModuleVersion = '1.582.2' + ModuleVersion = '1.585.1' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/python-client/wmill/pyproject.toml b/python-client/wmill/pyproject.toml index d6b7b52fda..1bc8342d33 100644 --- a/python-client/wmill/pyproject.toml +++ b/python-client/wmill/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill" -version = "1.582.2" +version = "1.585.1" description = "A client library for accessing Windmill server wrapping the Windmill client API" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/python-client/wmill_pg/pyproject.toml b/python-client/wmill_pg/pyproject.toml index c0cef5f1e0..309ed062d0 100644 --- a/python-client/wmill_pg/pyproject.toml +++ b/python-client/wmill_pg/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill-pg" -version = "1.582.2" +version = "1.585.1" description = "An extension client for the wmill client library focused on pg" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/typescript-client/jsr.json b/typescript-client/jsr.json index ea73dfeca0..4aad846d4a 100644 --- a/typescript-client/jsr.json +++ b/typescript-client/jsr.json @@ -1,6 +1,6 @@ { "name": "@windmill/windmill", - "version": "1.582.2", + "version": "1.585.1", "exports": "./src/index.ts", "publish": { "exclude": ["!src", "./s3Types.ts", "./sqlUtils.ts", "./client.ts"] diff --git a/typescript-client/package.json b/typescript-client/package.json index 1fb003024e..b2a49a5f3a 100644 --- a/typescript-client/package.json +++ b/typescript-client/package.json @@ -1,7 +1,7 @@ { "name": "windmill-client", "description": "Windmill SDK client for browsers and Node.js", - "version": "1.582.2", + "version": "1.585.1", "author": "Ruben Fiszel", "license": "Apache 2.0", "devDependencies": { diff --git a/version.txt b/version.txt index e5791defc6..26ec7f16a6 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.582.2 +1.585.1