diff --git a/.github/workflows/backend-check.yml b/.github/workflows/backend-check.yml index 309fa4d994..901a30cca6 100644 --- a/.github/workflows/backend-check.yml +++ b/.github/workflows/backend-check.yml @@ -1,10 +1,9 @@ name: Backend check on: - pull_request: - types: [opened, synchronize, reopened] - paths: - - "backend/**" - - ".github/workflows/backend-check.yml" + workflow_run: + workflows: ["Change versions"] + types: + - completed push: paths: - "backend/**" diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index b48ad1c990..195821b2dd 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -37,10 +37,10 @@ jobs: steps: - uses: denoland/setup-deno@v2 with: - deno-version: v1.x + deno-version: v2.x - name: benchmark timeout-minutes: 30 - run: deno run --unstable -A -r + run: deno run -A -r https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/benchmark_suite.ts -c https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/suite_config.json @@ -79,10 +79,10 @@ jobs: steps: - uses: denoland/setup-deno@v2 with: - deno-version: v1.x + deno-version: v2.x - name: benchmark timeout-minutes: 20 - run: deno run --unstable -A -r + run: deno run -A -r https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/benchmark_suite.ts --no-warm-up -c https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/suite_dedicated.json @@ -154,10 +154,10 @@ jobs: steps: - uses: denoland/setup-deno@v2 with: - deno-version: v1.x + deno-version: v2.x - name: benchmark timeout-minutes: 20 - run: deno run --unstable -A -r + run: deno run -A -r https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/benchmark_suite.ts -c https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/suite_config.json @@ -274,10 +274,10 @@ jobs: steps: - uses: denoland/setup-deno@v2 with: - deno-version: v1.x + deno-version: v2.x - name: benchmark timeout-minutes: 20 - run: deno run --unstable -A -r + run: deno run -A -r https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/benchmark_suite.ts -c https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/suite_config.json @@ -300,7 +300,7 @@ jobs: steps: - uses: denoland/setup-deno@v2 with: - deno-version: v1.x + deno-version: v2.x - uses: actions/checkout@v4 with: ref: benchmarks @@ -309,7 +309,7 @@ jobs: with: merge-multiple: true - name: graphs - run: deno run --unstable -A -r + run: deno run -A -r https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/benchmark_graphs.ts -c https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/graphs_config.json diff --git a/.github/workflows/build-publish-rh-image.yml b/.github/workflows/build-publish-rh-image.yml index 01a1f4fa97..10d2fe43d9 100644 --- a/.github/workflows/build-publish-rh-image.yml +++ b/.github/workflows/build-publish-rh-image.yml @@ -64,7 +64,7 @@ jobs: platforms: linux/amd64 push: true build-args: | - features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,mqtt_trigger,websocket,python,smtp,csharp,static_frontend,rust,nu + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages secrets: | rh_username=${{ secrets.RH_USERNAME }} rh_password=${{ secrets.RH_PASSWORD }} @@ -81,7 +81,7 @@ jobs: platforms: linux/arm64 push: true build-args: | - features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,mqtt_trigger,websocket,python,smtp,csharp,static_frontend,rust,nu + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages secrets: | rh_username=${{ secrets.RH_USERNAME }} rh_password=${{ secrets.RH_PASSWORD }} diff --git a/.github/workflows/build_windows_worker_.yml b/.github/workflows/build_windows_worker_.yml index 7cc5a56902..785ade3201 100644 --- a/.github/workflows/build_windows_worker_.yml +++ b/.github/workflows/build_windows_worker_.yml @@ -51,8 +51,7 @@ jobs: $env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static" mkdir frontend/build && cd backend New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force - cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,php,mysql,mssql,bigquery,oracledb,postgres_trigger,mqtt_trigger,websocket,python,smtp,csharp,static_frontend,rust,nu - + cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages - name: Rename binary with corresponding architecture run: | Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe" diff --git a/.github/workflows/docker-image-rpi4.yml b/.github/workflows/docker-image-rpi4.yml index 8dad6651f8..ed4fd7810b 100644 --- a/.github/workflows/docker-image-rpi4.yml +++ b/.github/workflows/docker-image-rpi4.yml @@ -67,7 +67,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=embedding,parquet,openidconnect,deno_core,license,http_trigger,zip,oauth2,php,mysql,mssql,bigquery,oracledb,postgres_trigger,mqtt_trigger,websocket,python,smtp,csharp,static_frontend,rust,nu + features=embedding,parquet,openidconnect,license,http_trigger,zip,oauth2,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:dev ${{ steps.meta-public.outputs.tags }} diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index cf95bcd108..4b5b19c74a 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -95,7 +95,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=embedding,parquet,openidconnect,jemalloc,deno_core,license,http_trigger,zip,oauth2,dind,php,mysql,mssql,bigquery,oracledb,postgres_trigger,mqtt_trigger,websocket,python,smtp,csharp,static_frontend,rust,nu + features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,agent_worker_server,all_languages tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }} ${{ steps.meta-public.outputs.tags }} @@ -157,7 +157,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,php,mysql,mssql,bigquery,oracledb,postgres_trigger,mqtt_trigger,websocket,python,smtp,csharp,static_frontend,rust,nu + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,agent_worker_server,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }} ${{ steps.meta-ee-public.outputs.tags }} diff --git a/.github/workflows/frontend-check.yml b/.github/workflows/frontend-check.yml index 4245949f33..a838ab3627 100644 --- a/.github/workflows/frontend-check.yml +++ b/.github/workflows/frontend-check.yml @@ -1,10 +1,9 @@ name: check frontend build on: - pull_request: - types: [opened, synchronize, reopened] - paths: - - "frontend/**" - - ".github/workflows/frontend-check.yml" + workflow_run: + workflows: ["Change versions"] + types: + - completed merge_group: push: @@ -22,5 +21,6 @@ jobs: node-version: 18 - name: "npm check" timeout-minutes: 5 - run: cd frontend && npm ci && npm run generate-backend-client && npm run + run: + cd frontend && npm ci && npm run generate-backend-client && npm run check diff --git a/.github/workflows/npm_on_release.yml b/.github/workflows/npm_on_release.yml index 352109a0da..18c52cb38d 100644 --- a/.github/workflows/npm_on_release.yml +++ b/.github/workflows/npm_on_release.yml @@ -27,7 +27,7 @@ jobs: registry-url: "https://registry.npmjs.org" - uses: denoland/setup-deno@v2 with: - deno-version: v1.x + deno-version: v2.x - run: cd cli && ./build.sh && cd npm && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish_windows_worker.yml b/.github/workflows/publish_windows_worker.yml index 1ef3d32b99..5b591abc3c 100644 --- a/.github/workflows/publish_windows_worker.yml +++ b/.github/workflows/publish_windows_worker.yml @@ -53,8 +53,7 @@ jobs: $env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static" mkdir frontend/build && cd backend New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force - cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,mqtt_trigger,websocket,python,smtp,csharp,static_frontend,rust,nu - + cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages - name: Rename binary with corresponding architecture run: | Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe" diff --git a/.gitignore b/.gitignore index 60c80becbf..b157a1679a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ CaddyfileRemoteMalo .direnv .vscode .dev-docker-wrapper* +backend/.minio-data diff --git a/CHANGELOG.md b/CHANGELOG.md index 88026c4f38..3a133b737a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,97 @@ # Changelog +## [1.481.0](https://github.com/windmill-labs/windmill/compare/v1.480.1...v1.481.0) (2025-04-02) + + +### Features + +* mssql support cert configuration ([#5559](https://github.com/windmill-labs/windmill/issues/5559)) ([e5519f7](https://github.com/windmill-labs/windmill/commit/e5519f79aaa83f04014364c7d1ec11157044011d)) + +## [1.480.1](https://github.com/windmill-labs/windmill/compare/v1.480.0...v1.480.1) (2025-04-02) + + +### Bug Fixes + +* aad_token can be empty string ([#5557](https://github.com/windmill-labs/windmill/issues/5557)) ([3fd7a5c](https://github.com/windmill-labs/windmill/commit/3fd7a5ce9c02332be40c34c0b6da57894b0b3d55)) +* improve workspace selection for default tag settings ([7083efd](https://github.com/windmill-labs/windmill/commit/7083efd051aeb7f653cccc97db099f4d9b2591a0)) +* mssql aad_token can be empty string ([#5556](https://github.com/windmill-labs/windmill/issues/5556)) ([dd30692](https://github.com/windmill-labs/windmill/commit/dd30692617e3cbc852239c4b1c50f975ff247c33)) + +## [1.480.0](https://github.com/windmill-labs/windmill/compare/v1.479.3...v1.480.0) (2025-03-31) + + +### Features + +* ms sql aad authentication support ([#5539](https://github.com/windmill-labs/windmill/issues/5539)) ([c230e2a](https://github.com/windmill-labs/windmill/commit/c230e2aed9b7fafb86548a4f4151939d5aca5127)) +* put db resources in ai context ([#5507](https://github.com/windmill-labs/windmill/issues/5507)) ([f7c8654](https://github.com/windmill-labs/windmill/commit/f7c86549879582c7f9dc72d52524f3a394f493f3)) + + +### Bug Fixes + +* correctly run empty flow with preprocessor from UI ([#5537](https://github.com/windmill-labs/windmill/issues/5537)) ([3d32501](https://github.com/windmill-labs/windmill/commit/3d3250194d43aee1a640a57505bc7a6afee62c84)) +* **frontend:** use custom caret position function ([#5544](https://github.com/windmill-labs/windmill/issues/5544)) ([ca0cda3](https://github.com/windmill-labs/windmill/commit/ca0cda3ecf5bd449f9c371cf5102c11d880c9822)) +* ignore invalid chunks in completion stream: empty choices when using azure ([#5545](https://github.com/windmill-labs/windmill/issues/5545)) ([b31090c](https://github.com/windmill-labs/windmill/commit/b31090cb544632680947492dc28f7b7c1a9c7287)) +* only format valid resource types ([#5541](https://github.com/windmill-labs/windmill/issues/5541)) ([113f038](https://github.com/windmill-labs/windmill/commit/113f038fc0e53e37c3bc319f85b3f7fa780c6fe5)) + +## [1.479.3](https://github.com/windmill-labs/windmill/compare/v1.479.2...v1.479.3) (2025-03-28) + + +### Bug Fixes + +* **cli:** pin encodeHex to 1.0.4 to work with dnt ([4703e3c](https://github.com/windmill-labs/windmill/commit/4703e3c848c9b06603b83885267023ccf84316c3)) + + +### Performance Improvements + +* improve hub resource type pulling when using the cli ([#5535](https://github.com/windmill-labs/windmill/issues/5535)) ([dd488a2](https://github.com/windmill-labs/windmill/commit/dd488a2bdbc0c9c7311c06dc25504a1336661cde)) + +## [1.479.2](https://github.com/windmill-labs/windmill/compare/v1.479.1...v1.479.2) (2025-03-28) + + +### Bug Fixes + +* fetch correct resource for interactive slack when multiple workspaces connected ([#5532](https://github.com/windmill-labs/windmill/issues/5532)) ([08e8283](https://github.com/windmill-labs/windmill/commit/08e8283c58c94f773936bac09d56bc6430382bbb)) + +## [1.479.1](https://github.com/windmill-labs/windmill/compare/v1.479.0...v1.479.1) (2025-03-27) + + +### Bug Fixes + +* pin backend deps half to 2.4.1 ([6cd2dc7](https://github.com/windmill-labs/windmill/commit/6cd2dc7178c62530f893d69f6e76b6cbc465e419)) + +## [1.479.0](https://github.com/windmill-labs/windmill/compare/v1.478.1...v1.479.0) (2025-03-27) + + +### Features + +* add description option to schedule page ([#5500](https://github.com/windmill-labs/windmill/issues/5500)) ([4c6f600](https://github.com/windmill-labs/windmill/commit/4c6f60010fec7d82181867e0082079e446797ce2)) +* add java support ([#5458](https://github.com/windmill-labs/windmill/issues/5458)) ([59740c0](https://github.com/windmill-labs/windmill/commit/59740c047816ad90d7383b15c846302db1a2e354)) +* add nu-lang support ([#5217](https://github.com/windmill-labs/windmill/issues/5217)) ([a3faea1](https://github.com/windmill-labs/windmill/commit/a3faea16e77796a1b989db4285b3fef722ac55b2)) +* api key/basic/hmac auth for http triggers ([#5476](https://github.com/windmill-labs/windmill/issues/5476)) ([e920101](https://github.com/windmill-labs/windmill/commit/e920101107256589bb5aee09fa8f04f5bd9707e4)) +* autocomplete v2 + AI chat ([#5323](https://github.com/windmill-labs/windmill/issues/5323)) ([234b20f](https://github.com/windmill-labs/windmill/commit/234b20f8bd55ea19b17b80f08d9ff1e0e00ba739)) +* github app token instead of pat for git sync ([#5279](https://github.com/windmill-labs/windmill/issues/5279)) ([b822c66](https://github.com/windmill-labs/windmill/commit/b822c66262f7c4c01ea4baad9383a12d138b0815)) +* list references upon renaming a script or a flow ([#5487](https://github.com/windmill-labs/windmill/issues/5487)) ([e868fe2](https://github.com/windmill-labs/windmill/commit/e868fe2bf5695b968151e27826854def3e847eb1)) +* make custom ai CE + add together AI provider ([#5522](https://github.com/windmill-labs/windmill/issues/5522)) ([a28c78d](https://github.com/windmill-labs/windmill/commit/a28c78dd920c695c3dfac05bc48c82f1477b022d)) +* **python:** fully qualified imports mapping ([#5511](https://github.com/windmill-labs/windmill/issues/5511)) ([1a5566b](https://github.com/windmill-labs/windmill/commit/1a5566b8c29773d94a681c86676d4cdb0b7c7777)) +* remove stripe dep ([#5508](https://github.com/windmill-labs/windmill/issues/5508)) ([7a62527](https://github.com/windmill-labs/windmill/commit/7a625275752ba69e26d7e3b41416e335496eff84)) +* unsafe parameters for sql queries (table names, column names) ([#5488](https://github.com/windmill-labs/windmill/issues/5488)) ([38ee018](https://github.com/windmill-labs/windmill/commit/38ee0183aaa014c740da7b54d66928ec851fb522)) + + +### Bug Fixes + +* add missing privileged hub script for app slack reports ([#5515](https://github.com/windmill-labs/windmill/issues/5515)) ([63fe9c1](https://github.com/windmill-labs/windmill/commit/63fe9c1852c1f87901f42eff8904c3482f7ceb43)) +* clean job dirs between flow locks ([8129672](https://github.com/windmill-labs/windmill/commit/8129672d9e8c6b591c1a46c30060a9d4f207e499)) +* **cli:** add --dry-run option ([4667507](https://github.com/windmill-labs/windmill/commit/466750752f6ffcb098cecd4ef6d6f33fb42d39ba)) +* correct private hub url in CLI for resource types sync ([#5513](https://github.com/windmill-labs/windmill/issues/5513)) ([9fd224c](https://github.com/windmill-labs/windmill/commit/9fd224cc469ae6f47c3ba9839ed43c85ff4d2181)) +* **frontend:** use stable path for capture tables + nits ([#5495](https://github.com/windmill-labs/windmill/issues/5495)) ([e16d629](https://github.com/windmill-labs/windmill/commit/e16d6299f52564def484e78fb2f48e9bf39cbd3d)) +* improve cancel for flows with many substeps ([ec11d57](https://github.com/windmill-labs/windmill/commit/ec11d577c6089df0b6019cd05064f5ea63fb317c)) + + +### Performance Improvements + +* cache workspace env variables to avoid one query ([#5499](https://github.com/windmill-labs/windmill/issues/5499)) ([a3f6db7](https://github.com/windmill-labs/windmill/commit/a3f6db7dca983a4dfd62b30423340f899c4d1da6)) +* cache workspace premium check ([5573d88](https://github.com/windmill-labs/windmill/commit/5573d886954182efcac71b3baa54d455f5086b30)) +* optimize number of queries needed for job run ([#5504](https://github.com/windmill-labs/windmill/issues/5504)) ([3edca4b](https://github.com/windmill-labs/windmill/commit/3edca4bc91ee9a1f1c0a98d39bc673dc56f899b6)) + ## [1.478.1](https://github.com/windmill-labs/windmill/compare/v1.478.0...v1.478.1) (2025-03-20) diff --git a/Caddyfile b/Caddyfile index 67925e6492..933407b98d 100644 --- a/Caddyfile +++ b/Caddyfile @@ -12,7 +12,7 @@ bind {$ADDRESS} reverse_proxy /ws/* http://lsp:3001 # reverse_proxy /ws_mp/* http://multiplayer:3002 - # reverse_proxy /api/srch/* http://windmill_indexer:8001 + # reverse_proxy /api/srch/* http://windmill_indexer:8002 reverse_proxy /* http://windmill_server:8000 # tls /certs/cert.pem /certs/key.pem } diff --git a/Dockerfile b/Dockerfile index 4d3e2655f2..d00275f925 100644 --- a/Dockerfile +++ b/Dockerfile @@ -221,9 +221,10 @@ RUN cp -r /root/.cache /home/windmill/.cache RUN mkdir -p /tmp/windmill/logs && \ mkdir -p /tmp/windmill/search -RUN chown -R windmill:windmill ${APP} && \ - chown -R windmill:windmill /tmp/windmill && \ - chown -R windmill:windmill /home/windmill/.cache +# Make directories world-readable and writable +RUN chmod -R 777 ${APP} && \ + chmod -R 777 /tmp/windmill && \ + chmod -R 777 /home/windmill/.cache USER root diff --git a/backend/.sqlx/query-0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef.json b/backend/.sqlx/query-0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef.json new file mode 100644 index 0000000000..06390d0ce9 --- /dev/null +++ b/backend/.sqlx/query-0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef.json @@ -0,0 +1,128 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n gcp_resource_path,\n subscription_id,\n topic_id,\n workspace_id,\n delivery_type AS \"delivery_type: _\",\n delivery_config AS \"delivery_config: _\",\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM \n gcp_trigger\n WHERE \n workspace_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "gcp_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "subscription_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "topic_id", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "delivery_type: _", + "type_info": { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + } + }, + { + "ordinal": 5, + "name": "delivery_config: _", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 11, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 12, + "name": "server_id", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "last_server_ping", + "type_info": "Timestamptz" + }, + { + "ordinal": 14, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 15, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 16, + "name": "enabled", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false + ] + }, + "hash": "0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef" +} diff --git a/backend/.sqlx/query-ceda377fa534656ac12a7f41db77db1f054ec751855c8db7352b0e9c20b63ef8.json b/backend/.sqlx/query-0689cdc6c7676f5e1984792a0e0b172ea9a70835bfba6cef56142556197e9767.json similarity index 56% rename from backend/.sqlx/query-ceda377fa534656ac12a7f41db77db1f054ec751855c8db7352b0e9c20b63ef8.json rename to backend/.sqlx/query-0689cdc6c7676f5e1984792a0e0b172ea9a70835bfba6cef56142556197e9767.json index a309a03762..27c1d1d2d8 100644 --- a/backend/.sqlx/query-ceda377fa534656ac12a7f41db77db1f054ec751855c8db7352b0e9c20b63ef8.json +++ b/backend/.sqlx/query-0689cdc6c7676f5e1984792a0e0b172ea9a70835bfba6cef56142556197e9767.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT ai_resource FROM workspace_settings WHERE workspace_id = $1", + "query": "SELECT ai_config FROM workspace_settings WHERE workspace_id = $1", "describe": { "columns": [ { "ordinal": 0, - "name": "ai_resource", + "name": "ai_config", "type_info": "Jsonb" } ], @@ -18,5 +18,5 @@ true ] }, - "hash": "ceda377fa534656ac12a7f41db77db1f054ec751855c8db7352b0e9c20b63ef8" + "hash": "0689cdc6c7676f5e1984792a0e0b172ea9a70835bfba6cef56142556197e9767" } diff --git a/backend/.sqlx/query-070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb.json b/backend/.sqlx/query-070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb.json new file mode 100644 index 0000000000..280db517dd --- /dev/null +++ b/backend/.sqlx/query-070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET \n enabled = $1, \n email = $2, \n edited_by = $3, \n edited_at = now(), \n server_id = NULL, \n error = NULL\n WHERE \n path = $4 AND \n workspace_id = $5 \n RETURNING 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Bool", + "Varchar", + "Varchar", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb" +} diff --git a/backend/.sqlx/query-08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7.json b/backend/.sqlx/query-08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7.json index 4bcf3c6ce3..388fd55418 100644 --- a/backend/.sqlx/query-08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7.json +++ b/backend/.sqlx/query-08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7.json @@ -65,7 +65,7 @@ }, { "ordinal": 12, - "name": "ai_resource", + "name": "ai_config", "type_info": "Jsonb" }, { @@ -100,58 +100,48 @@ }, { "ordinal": 19, - "name": "automatic_billing", - "type_info": "Bool" - }, - { - "ordinal": 20, "name": "default_scripts", "type_info": "Jsonb" }, { - "ordinal": 21, + "ordinal": 20, "name": "deploy_ui", "type_info": "Jsonb" }, { - "ordinal": 22, + "ordinal": 21, "name": "mute_critical_alerts", "type_info": "Bool" }, { - "ordinal": 23, + "ordinal": 22, "name": "color", "type_info": "Varchar" }, { - "ordinal": 24, + "ordinal": 23, "name": "operator_settings", "type_info": "Jsonb" }, { - "ordinal": 25, - "name": "ai_models", - "type_info": "VarcharArray" - }, - { - "ordinal": 26, - "name": "code_completion_model", - "type_info": "Varchar" - }, - { - "ordinal": 27, + "ordinal": 24, "name": "teams_command_script", "type_info": "Text" }, { - "ordinal": 28, + "ordinal": 25, "name": "teams_team_id", "type_info": "Text" }, { - "ordinal": 29, + "ordinal": 26, "name": "teams_team_name", "type_info": "Text" + }, + { + "ordinal": 27, + "name": "git_app_installations", + "type_info": "Jsonb" } ], "parameters": { @@ -179,17 +169,15 @@ true, true, true, - false, true, true, true, true, true, - false, true, true, true, - true + false ] }, "hash": "08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7" diff --git a/backend/.sqlx/query-0e52a588f3edeb8fb58d6d62247b8590e51171e2811c62737bdb81fb0ac8f182.json b/backend/.sqlx/query-0e52a588f3edeb8fb58d6d62247b8590e51171e2811c62737bdb81fb0ac8f182.json deleted file mode 100644 index f23cf3f710..0000000000 --- a/backend/.sqlx/query-0e52a588f3edeb8fb58d6d62247b8590e51171e2811c62737bdb81fb0ac8f182.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE worker_ping SET \n ping_at = now(), \n jobs_executed = 1, \n current_job_id = $1, \n current_job_workspace_id = 'admins' \n WHERE worker = $2", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid", - "Text" - ] - }, - "nullable": [] - }, - "hash": "0e52a588f3edeb8fb58d6d62247b8590e51171e2811c62737bdb81fb0ac8f182" -} diff --git a/backend/.sqlx/query-0ee14619dd81df460b2b8cc6df2b89646279f77469c35deffca8e17a11d7f6c8.json b/backend/.sqlx/query-0ee14619dd81df460b2b8cc6df2b89646279f77469c35deffca8e17a11d7f6c8.json new file mode 100644 index 0000000000..ac882aec64 --- /dev/null +++ b/backend/.sqlx/query-0ee14619dd81df460b2b8cc6df2b89646279f77469c35deffca8e17a11d7f6c8.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n (elem->>'installation_id')::bigint as installation_id,\n elem->>'account_id' as account_id\n FROM workspace_settings,\n LATERAL jsonb_array_elements(git_app_installations) AS elem\n WHERE workspace_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "installation_id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "account_id", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "0ee14619dd81df460b2b8cc6df2b89646279f77469c35deffca8e17a11d7f6c8" +} diff --git a/backend/.sqlx/query-103ef3cf5cf4d25d780e4aefd5b290d810a5e8ea6458d9f9fd484ced549ea82e.json b/backend/.sqlx/query-103ef3cf5cf4d25d780e4aefd5b290d810a5e8ea6458d9f9fd484ced549ea82e.json deleted file mode 100644 index 15d772ab16..0000000000 --- a/backend/.sqlx/query-103ef3cf5cf4d25d780e4aefd5b290d810a5e8ea6458d9f9fd484ced549ea82e.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT value, resource_type FROM resource WHERE path = $1 AND workspace_id = $2", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "value", - "type_info": "Jsonb" - }, - { - "ordinal": 1, - "name": "resource_type", - "type_info": "Varchar" - } - ], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [ - true, - false - ] - }, - "hash": "103ef3cf5cf4d25d780e4aefd5b290d810a5e8ea6458d9f9fd484ced549ea82e" -} diff --git a/backend/.sqlx/query-122090a0f89e5248a0a0f199ebd24582fdb302883aebd2da187ac0084e767ea3.json b/backend/.sqlx/query-122090a0f89e5248a0a0f199ebd24582fdb302883aebd2da187ac0084e767ea3.json deleted file mode 100644 index a329998c95..0000000000 --- a/backend/.sqlx/query-122090a0f89e5248a0a0f199ebd24582fdb302883aebd2da187ac0084e767ea3.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT set_config('session.pgroups', $1, true)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "set_config", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "122090a0f89e5248a0a0f199ebd24582fdb302883aebd2da187ac0084e767ea3" -} diff --git a/backend/.sqlx/query-157090e958a907a09554c2491cabf9a8108c436cba1d2b770e9104d1c8590bcb.json b/backend/.sqlx/query-144e4eccfd1c1e729e3c864bd5dc3316248719dfa8a6c9e1d15a7931638e86db.json similarity index 73% rename from backend/.sqlx/query-157090e958a907a09554c2491cabf9a8108c436cba1d2b770e9104d1c8590bcb.json rename to backend/.sqlx/query-144e4eccfd1c1e729e3c864bd5dc3316248719dfa8a6c9e1d15a7931638e86db.json index df4a83bdb4..e573bfdab7 100644 --- a/backend/.sqlx/query-157090e958a907a09554c2491cabf9a8108c436cba1d2b770e9104d1c8590bcb.json +++ b/backend/.sqlx/query-144e4eccfd1c1e729e3c864bd5dc3316248719dfa8a6c9e1d15a7931638e86db.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT \n workspace_id, \n path, \n route_path, \n route_path_key,\n workspaced_route,\n script_path, \n is_flow, \n http_method as \"http_method: _\", \n edited_by, \n email, \n edited_at, \n extra_perms, \n is_async, \n requires_auth, \n static_asset_config as \"static_asset_config: _\", \n is_static_website,\n wrap_body,\n raw_string\n FROM \n http_trigger\n WHERE \n workspace_id = $1 AND \n path = $2\n ", + "query": "\n SELECT \n workspace_id, \n path, \n route_path, \n route_path_key,\n workspaced_route,\n script_path, \n is_flow, \n http_method as \"http_method: _\", \n edited_by, \n email, \n edited_at, \n extra_perms, \n is_async, \n authentication_method as \"authentication_method: _\", \n static_asset_config as \"static_asset_config: _\", \n is_static_website,\n authentication_resource_path,\n wrap_body,\n raw_string\n FROM \n http_trigger\n WHERE \n workspace_id = $1 AND \n path = $2\n ", "describe": { "columns": [ { @@ -83,8 +83,22 @@ }, { "ordinal": 13, - "name": "requires_auth", - "type_info": "Bool" + "name": "authentication_method: _", + "type_info": { + "Custom": { + "name": "authentication_method", + "kind": { + "Enum": [ + "none", + "windmill", + "api_key", + "basic_http", + "custom_script", + "signature" + ] + } + } + } }, { "ordinal": 14, @@ -98,11 +112,16 @@ }, { "ordinal": 16, + "name": "authentication_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 17, "name": "wrap_body", "type_info": "Bool" }, { - "ordinal": 17, + "ordinal": 18, "name": "raw_string", "type_info": "Bool" } @@ -130,9 +149,10 @@ false, true, false, + true, false, false ] }, - "hash": "157090e958a907a09554c2491cabf9a8108c436cba1d2b770e9104d1c8590bcb" + "hash": "144e4eccfd1c1e729e3c864bd5dc3316248719dfa8a6c9e1d15a7931638e86db" } diff --git a/backend/.sqlx/query-15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json b/backend/.sqlx/query-15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json new file mode 100644 index 0000000000..5f76c31d8b --- /dev/null +++ b/backend/.sqlx/query-15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json @@ -0,0 +1,126 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n gcp_resource_path,\n subscription_id,\n topic_id,\n workspace_id,\n delivery_type AS \"delivery_type: _\",\n delivery_config AS \"delivery_config: _\",\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM\n gcp_trigger\n WHERE\n delivery_type != 'push'::DELIVERY_MODE AND\n enabled IS TRUE\n AND (last_server_ping IS NULL OR\n last_server_ping < now() - interval '15 seconds'\n )\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "gcp_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "subscription_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "topic_id", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "delivery_type: _", + "type_info": { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + } + }, + { + "ordinal": 5, + "name": "delivery_config: _", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 11, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 12, + "name": "server_id", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "last_server_ping", + "type_info": "Timestamptz" + }, + { + "ordinal": 14, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 15, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 16, + "name": "enabled", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false + ] + }, + "hash": "15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18" +} diff --git a/backend/.sqlx/query-187e8f85a71dea958e89fdfdf96c913a19eef8678dc7890c2f0e1ef8758ec43b.json b/backend/.sqlx/query-187e8f85a71dea958e89fdfdf96c913a19eef8678dc7890c2f0e1ef8758ec43b.json new file mode 100644 index 0000000000..db7d3ab2ec --- /dev/null +++ b/backend/.sqlx/query-187e8f85a71dea958e89fdfdf96c913a19eef8678dc7890c2f0e1ef8758ec43b.json @@ -0,0 +1,58 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n http_trigger \n SET \n route_path = $1, \n route_path_key = $2, \n workspaced_route = $3,\n wrap_body = $4,\n raw_string = $5,\n authentication_resource_path = $6,\n script_path = $7, \n path = $8, \n is_flow = $9, \n http_method = $10, \n static_asset_config = $11, \n edited_by = $12, \n email = $13, \n is_async = $14, \n authentication_method = $15, \n edited_at = now(), \n is_static_website = $16\n WHERE \n workspace_id = $17 AND \n path = $18\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Bool", + "Bool", + "Bool", + "Varchar", + "Varchar", + "Varchar", + "Bool", + { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + }, + "Jsonb", + "Varchar", + "Varchar", + "Bool", + { + "Custom": { + "name": "authentication_method", + "kind": { + "Enum": [ + "none", + "windmill", + "api_key", + "basic_http", + "custom_script", + "signature" + ] + } + } + }, + "Bool", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "187e8f85a71dea958e89fdfdf96c913a19eef8678dc7890c2f0e1ef8758ec43b" +} diff --git a/backend/.sqlx/query-18ddbb9eb4c0ec03e6170f8c70634546cddaf1029618ed14015fd7b0a7017441.json b/backend/.sqlx/query-18ddbb9eb4c0ec03e6170f8c70634546cddaf1029618ed14015fd7b0a7017441.json new file mode 100644 index 0000000000..c1258697c9 --- /dev/null +++ b/backend/.sqlx/query-18ddbb9eb4c0ec03e6170f8c70634546cddaf1029618ed14015fd7b0a7017441.json @@ -0,0 +1,27 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT set_session_context($1, $2, $3, $4, $5, $6)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "set_session_context", + "type_info": "Void" + } + ], + "parameters": { + "Left": [ + "Bool", + "Text", + "Text", + "Text", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "18ddbb9eb4c0ec03e6170f8c70634546cddaf1029618ed14015fd7b0a7017441" +} diff --git a/backend/.sqlx/query-197590e7ab74f64bbf374f23128850bed8f435ea5de16ba796f346fba51d9437.json b/backend/.sqlx/query-197590e7ab74f64bbf374f23128850bed8f435ea5de16ba796f346fba51d9437.json new file mode 100644 index 0000000000..28d629c587 --- /dev/null +++ b/backend/.sqlx/query-197590e7ab74f64bbf374f23128850bed8f435ea5de16ba796f346fba51d9437.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT ai_config as \"ai_config: sqlx::types::Json\" FROM workspace_settings WHERE workspace_id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "ai_config: sqlx::types::Json", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + true + ] + }, + "hash": "197590e7ab74f64bbf374f23128850bed8f435ea5de16ba796f346fba51d9437" +} diff --git a/backend/.sqlx/query-1bbef6baa5b8e2522d685df2979bb1e4b9022f5e841afd9eeb08a81688f6c0c8.json b/backend/.sqlx/query-1bbef6baa5b8e2522d685df2979bb1e4b9022f5e841afd9eeb08a81688f6c0c8.json deleted file mode 100644 index 4fcd1f0969..0000000000 --- a/backend/.sqlx/query-1bbef6baa5b8e2522d685df2979bb1e4b9022f5e841afd9eeb08a81688f6c0c8.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE workspace_settings SET ai_resource = NULL, code_completion_model = $1, ai_models = '{}' WHERE workspace_id = $2", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Text" - ] - }, - "nullable": [] - }, - "hash": "1bbef6baa5b8e2522d685df2979bb1e4b9022f5e841afd9eeb08a81688f6c0c8" -} diff --git a/backend/.sqlx/query-1e659916501e668913e591eb7282d3881fa44468ed5330a501daa0d61c84cb71.json b/backend/.sqlx/query-1e659916501e668913e591eb7282d3881fa44468ed5330a501daa0d61c84cb71.json deleted file mode 100644 index 2cb0d351da..0000000000 --- a/backend/.sqlx/query-1e659916501e668913e591eb7282d3881fa44468ed5330a501daa0d61c84cb71.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE workspace_settings SET automatic_billing = false WHERE workspace_id = $1", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [] - }, - "hash": "1e659916501e668913e591eb7282d3881fa44468ed5330a501daa0d61c84cb71" -} diff --git a/backend/.sqlx/query-22888025706d457da65207ea9d592079c7274ca0827dc2a26b29394c12b3f7fc.json b/backend/.sqlx/query-22888025706d457da65207ea9d592079c7274ca0827dc2a26b29394c12b3f7fc.json deleted file mode 100644 index f4e752cc71..0000000000 --- a/backend/.sqlx/query-22888025706d457da65207ea9d592079c7274ca0827dc2a26b29394c12b3f7fc.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO http_trigger (\n workspace_id, \n path, \n route_path, \n route_path_key,\n workspaced_route,\n wrap_body,\n raw_string,\n script_path, \n is_flow, \n is_async, \n requires_auth, \n http_method, \n static_asset_config, \n edited_by, \n email, \n edited_at, \n is_static_website\n ) \n VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, now(), $16\n )\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Varchar", - "Varchar", - "Varchar", - "Bool", - "Bool", - "Bool", - "Varchar", - "Bool", - "Bool", - "Bool", - { - "Custom": { - "name": "http_method", - "kind": { - "Enum": [ - "get", - "post", - "put", - "delete", - "patch" - ] - } - } - }, - "Jsonb", - "Varchar", - "Varchar", - "Bool" - ] - }, - "nullable": [] - }, - "hash": "22888025706d457da65207ea9d592079c7274ca0827dc2a26b29394c12b3f7fc" -} diff --git a/backend/.sqlx/query-e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039.json b/backend/.sqlx/query-23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2.json similarity index 53% rename from backend/.sqlx/query-e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039.json rename to backend/.sqlx/query-23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2.json index 7b30e079f0..5b810738b3 100644 --- a/backend/.sqlx/query-e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039.json +++ b/backend/.sqlx/query-23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT trigger_config as \"trigger_config: _\", owner, email\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'", + "query": "\n SELECT \n trigger_config AS \"trigger_config: _\", \n owner, \n email\n FROM \n capture_config\n WHERE \n workspace_id = $1\n AND path = $2\n AND is_flow = $3\n AND trigger_kind = $4\n AND last_client_ping > NOW() - INTERVAL '10 seconds'\n AND (\n $5::bool IS FALSE\n OR (\n trigger_config IS NOT NULL\n AND trigger_config ->> 'delivery_type' = 'push'\n )\n )\n ", "describe": { "columns": [ { @@ -37,11 +37,13 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } - } + }, + "Bool" ] }, "nullable": [ @@ -50,5 +52,5 @@ false ] }, - "hash": "e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039" + "hash": "23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2" } diff --git a/backend/.sqlx/query-240cf4ba63ec39a7ccfa8360824259d2fdc6681bbbd44e3ccde0a3893f6cf9a0.json b/backend/.sqlx/query-240cf4ba63ec39a7ccfa8360824259d2fdc6681bbbd44e3ccde0a3893f6cf9a0.json deleted file mode 100644 index 134cb58d17..0000000000 --- a/backend/.sqlx/query-240cf4ba63ec39a7ccfa8360824259d2fdc6681bbbd44e3ccde0a3893f6cf9a0.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT \n MAX (created_at) AS last_deploy, \n COUNT (*) AS deploys_count \n , 'python' AS language\n FROM metrics \n WHERE id = 'no_uv_usage_py'\n\n UNION ALL\n \n SELECT \n MAX (created_at) AS last_deploy, \n COUNT (*) AS deploys_count \n , 'ansible' AS language\n FROM metrics \n WHERE id = 'no_uv_usage_ansible'\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "last_deploy", - "type_info": "Timestamptz" - }, - { - "ordinal": 1, - "name": "deploys_count", - "type_info": "Int8" - }, - { - "ordinal": 2, - "name": "language", - "type_info": "Text" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - null, - null, - null - ] - }, - "hash": "240cf4ba63ec39a7ccfa8360824259d2fdc6681bbbd44e3ccde0a3893f6cf9a0" -} diff --git a/backend/.sqlx/query-299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63.json b/backend/.sqlx/query-299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63.json new file mode 100644 index 0000000000..d64d8f404b --- /dev/null +++ b/backend/.sqlx/query-299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture_config \n SET \n server_id = $1,\n last_server_ping = now(), \n error = 'Connecting...' \n WHERE \n last_client_ping > NOW() - INTERVAL '10 seconds' AND \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'gcp' AND \n (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') \n RETURNING true\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Text", + "Bool" + ] + }, + "nullable": [ + null + ] + }, + "hash": "299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63" +} diff --git a/backend/.sqlx/query-29fbc3a8c35845a997cd548ed417b9cc3c82d815d99b3d435adcfbb5a9246124.json b/backend/.sqlx/query-29fbc3a8c35845a997cd548ed417b9cc3c82d815d99b3d435adcfbb5a9246124.json deleted file mode 100644 index 72f3f1f469..0000000000 --- a/backend/.sqlx/query-29fbc3a8c35845a997cd548ed417b9cc3c82d815d99b3d435adcfbb5a9246124.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT set_config('session.folders_read', $1, true)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "set_config", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "29fbc3a8c35845a997cd548ed417b9cc3c82d815d99b3d435adcfbb5a9246124" -} diff --git a/backend/.sqlx/query-2ae44acae7ac80e191b37071baa26e57488489177fe596940d3698d843a93666.json b/backend/.sqlx/query-2ae44acae7ac80e191b37071baa26e57488489177fe596940d3698d843a93666.json new file mode 100644 index 0000000000..405902863c --- /dev/null +++ b/backend/.sqlx/query-2ae44acae7ac80e191b37071baa26e57488489177fe596940d3698d843a93666.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT script_path FROM v2_as_queue WHERE id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "script_path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + true + ] + }, + "hash": "2ae44acae7ac80e191b37071baa26e57488489177fe596940d3698d843a93666" +} diff --git a/backend/.sqlx/query-2d4d4564108376ab310cb4a50fa2fa84fefbb3df8bb1bc9996c40a86d464b8a1.json b/backend/.sqlx/query-2d4d4564108376ab310cb4a50fa2fa84fefbb3df8bb1bc9996c40a86d464b8a1.json deleted file mode 100644 index 8c26257ef8..0000000000 --- a/backend/.sqlx/query-2d4d4564108376ab310cb4a50fa2fa84fefbb3df8bb1bc9996c40a86d464b8a1.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE workspace_settings SET automatic_billing = TRUE WHERE workspace_id = $1", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [] - }, - "hash": "2d4d4564108376ab310cb4a50fa2fa84fefbb3df8bb1bc9996c40a86d464b8a1" -} diff --git a/backend/.sqlx/query-2ebb0463b790ddf7ba0ee22d8c9afc88eb57c4110a202775003fb48b2f4e317f.json b/backend/.sqlx/query-2ebb0463b790ddf7ba0ee22d8c9afc88eb57c4110a202775003fb48b2f4e317f.json new file mode 100644 index 0000000000..49e6e6c6ae --- /dev/null +++ b/backend/.sqlx/query-2ebb0463b790ddf7ba0ee22d8c9afc88eb57c4110a202775003fb48b2f4e317f.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE v2_job_status SET\n workflow_as_code_status = jsonb_set(\n jsonb_set(\n COALESCE(workflow_as_code_status, '{}'::jsonb),\n array[$1],\n COALESCE(workflow_as_code_status->$1, '{}'::jsonb)\n ),\n array[$1, 'started_at'],\n to_jsonb(now()::text)\n )\n WHERE id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "2ebb0463b790ddf7ba0ee22d8c9afc88eb57c4110a202775003fb48b2f4e317f" +} diff --git a/backend/.sqlx/query-6ff7a025f529c077c1b6c9632a367aa29e2f0fdac3f1984550484d5a06a6ea21.json b/backend/.sqlx/query-2faa27519624249f16cf89814ab5efe8f8daf928c1194cecacfa8223165fb9f2.json similarity index 50% rename from backend/.sqlx/query-6ff7a025f529c077c1b6c9632a367aa29e2f0fdac3f1984550484d5a06a6ea21.json rename to backend/.sqlx/query-2faa27519624249f16cf89814ab5efe8f8daf928c1194cecacfa8223165fb9f2.json index b045ed2b07..dbe3786571 100644 --- a/backend/.sqlx/query-6ff7a025f529c077c1b6c9632a367aa29e2f0fdac3f1984550484d5a06a6ea21.json +++ b/backend/.sqlx/query-2faa27519624249f16cf89814ab5efe8f8daf928c1194cecacfa8223165fb9f2.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE v2_job_runtime r SET\n memory_peak = $1,\n ping = now()\n FROM v2_job_queue q\n WHERE r.id = $2 AND q.id = r.id\n RETURNING canceled_by, canceled_reason", + "query": "UPDATE v2_job_runtime r SET\n memory_peak = $1,\n ping = now()\n FROM v2_job_queue q\n WHERE r.id = $2 AND q.id = r.id\n RETURNING canceled_by, canceled_reason", "describe": { "columns": [ { @@ -25,5 +25,5 @@ true ] }, - "hash": "6ff7a025f529c077c1b6c9632a367aa29e2f0fdac3f1984550484d5a06a6ea21" + "hash": "2faa27519624249f16cf89814ab5efe8f8daf928c1194cecacfa8223165fb9f2" } diff --git a/backend/.sqlx/query-30483ae46f6d0452126eb2cd07fc4d960961cc6ee61cf065113b7a48f97caecc.json b/backend/.sqlx/query-30483ae46f6d0452126eb2cd07fc4d960961cc6ee61cf065113b7a48f97caecc.json new file mode 100644 index 0000000000..959b66239f --- /dev/null +++ b/backend/.sqlx/query-30483ae46f6d0452126eb2cd07fc4d960961cc6ee61cf065113b7a48f97caecc.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT value as \"value: sqlx::types::Json>\" FROM resource WHERE path = $1 AND workspace_id = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value: sqlx::types::Json>", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + true + ] + }, + "hash": "30483ae46f6d0452126eb2cd07fc4d960961cc6ee61cf065113b7a48f97caecc" +} diff --git a/backend/.sqlx/query-31b6fccad46b22bcbba6bbce22209ccb1825116004ed72682854ce3352f454a5.json b/backend/.sqlx/query-31b6fccad46b22bcbba6bbce22209ccb1825116004ed72682854ce3352f454a5.json deleted file mode 100644 index 0871986a4e..0000000000 --- a/backend/.sqlx/query-31b6fccad46b22bcbba6bbce22209ccb1825116004ed72682854ce3352f454a5.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT \n \n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\", \n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\",\n EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS \"mqtt_used!\",\n EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS \"sqs_used!\"\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "websocket_used!", - "type_info": "Bool" - }, - { - "ordinal": 1, - "name": "http_routes_used!", - "type_info": "Bool" - }, - { - "ordinal": 2, - "name": "kafka_used!", - "type_info": "Bool" - }, - { - "ordinal": 3, - "name": "nats_used!", - "type_info": "Bool" - }, - { - "ordinal": 4, - "name": "postgres_used!", - "type_info": "Bool" - }, - { - "ordinal": 5, - "name": "mqtt_used!", - "type_info": "Bool" - }, - { - "ordinal": 6, - "name": "sqs_used!", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - null, - null, - null, - null, - null, - null, - null - ] - }, - "hash": "31b6fccad46b22bcbba6bbce22209ccb1825116004ed72682854ce3352f454a5" -} diff --git a/backend/.sqlx/query-31df83e9eb6078e93ec5fe4168306caccb849db9e0f71d86da655b01c6a3e8d0.json b/backend/.sqlx/query-31df83e9eb6078e93ec5fe4168306caccb849db9e0f71d86da655b01c6a3e8d0.json deleted file mode 100644 index b96c05d674..0000000000 --- a/backend/.sqlx/query-31df83e9eb6078e93ec5fe4168306caccb849db9e0f71d86da655b01c6a3e8d0.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority)\n VALUES ($1, $2, $3, COALESCE($4, now()), CASE WHEN $3 THEN now() END, $5, $6) RETURNING id AS \"id!\"", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id!", - "type_info": "Uuid" - } - ], - "parameters": { - "Left": [ - "Varchar", - "Uuid", - "Bool", - "Timestamptz", - "Varchar", - "Int2" - ] - }, - "nullable": [ - false - ] - }, - "hash": "31df83e9eb6078e93ec5fe4168306caccb849db9e0f71d86da655b01c6a3e8d0" -} diff --git a/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json b/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json index 85c0412f3b..7f79e83137 100644 --- a/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json +++ b/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json @@ -12,7 +12,7 @@ "parameters": { "Left": [ "Varchar", - "Json", + "Jsonb", "Text" ] }, diff --git a/backend/.sqlx/query-3376b42d273c2499f3517c7754f4cdb6eae2e71e56bc8e5215559af967c81bd8.json b/backend/.sqlx/query-3376b42d273c2499f3517c7754f4cdb6eae2e71e56bc8e5215559af967c81bd8.json new file mode 100644 index 0000000000..7229d4053f --- /dev/null +++ b/backend/.sqlx/query-3376b42d273c2499f3517c7754f4cdb6eae2e71e56bc8e5215559af967c81bd8.json @@ -0,0 +1,79 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT \n j.id,\n j.kind AS \"kind: _\",\n COALESCE(s.path, f.path) AS \"script_path!\",\n COALESCE(s.hash, f.id) AS \"script_hash!: _\",\n COALESCE(jc.started_at, jq.scheduled_for, make_date(1970, 1, 1)) AS \"scheduled_for!: _\",\n args AS input\n FROM v2_job j\n LEFT JOIN script s ON j.runnable_id = s.hash AND j.kind = 'script'\n LEFT JOIN flow_version f ON j.runnable_id = f.id AND j.runnable_path = f.path AND j.kind = 'flow'\n LEFT JOIN v2_job_completed jc ON jc.id = j.id\n LEFT JOIN v2_job_queue jq ON jq.id = j.id\n WHERE j.id = ANY($1)\n AND j.workspace_id = $2\n AND COALESCE(s.hash, f.id) IS NOT NULL\n AND COALESCE(s.path, f.path) IS NOT NULL", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "kind: _", + "type_info": { + "Custom": { + "name": "job_kind", + "kind": { + "Enum": [ + "script", + "preview", + "flow", + "dependencies", + "flowpreview", + "script_hub", + "identity", + "flowdependencies", + "http", + "graphql", + "postgresql", + "noop", + "appdependencies", + "deploymentcallback", + "singlescriptflow", + "flowscript", + "flownode", + "appscript" + ] + } + } + } + }, + { + "ordinal": 2, + "name": "script_path!", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "script_hash!: _", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "scheduled_for!: _", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "input", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "UuidArray", + "Text" + ] + }, + "nullable": [ + false, + false, + null, + null, + null, + true + ] + }, + "hash": "3376b42d273c2499f3517c7754f4cdb6eae2e71e56bc8e5215559af967c81bd8" +} diff --git a/backend/.sqlx/query-33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517.json b/backend/.sqlx/query-33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517.json new file mode 100644 index 0000000000..9b7581526e --- /dev/null +++ b/backend/.sqlx/query-33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT EXISTS(\n SELECT \n 1 \n FROM \n gcp_trigger \n WHERE \n path = $1 AND \n workspace_id = $2\n )", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517" +} diff --git a/backend/.sqlx/query-348f73fa8222ec195bb5b2260d1595e6e9fa9d73779cf352e94039fd47de4294.json b/backend/.sqlx/query-348f73fa8222ec195bb5b2260d1595e6e9fa9d73779cf352e94039fd47de4294.json new file mode 100644 index 0000000000..4f9e060ead --- /dev/null +++ b/backend/.sqlx/query-348f73fa8222ec195bb5b2260d1595e6e9fa9d73779cf352e94039fd47de4294.json @@ -0,0 +1,217 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE schedule SET\n schedule = $1,\n timezone = $2,\n args = $3,\n on_failure = $4,\n on_failure_times = $5,\n on_failure_exact = $6,\n on_failure_extra_args = $7,\n on_recovery = $8,\n on_recovery_times = $9,\n on_recovery_extra_args = $10,\n on_success = $11,\n on_success_extra_args = $12,\n ws_error_handler_muted = $13,\n retry = $14,\n summary = $15,\n no_flow_overlap = $16,\n tag = $17,\n paused_until = $18,\n path = $19,\n workspace_id = $20,\n cron_version = COALESCE($21, cron_version),\n description = $22\n WHERE path = $19 AND workspace_id = $20\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "schedule", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "timezone", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "enabled", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 10, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 11, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 12, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 13, + "name": "on_failure", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "on_failure_times", + "type_info": "Int4" + }, + { + "ordinal": 15, + "name": "on_failure_exact", + "type_info": "Bool" + }, + { + "ordinal": 16, + "name": "on_failure_extra_args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 17, + "name": "on_recovery", + "type_info": "Varchar" + }, + { + "ordinal": 18, + "name": "on_recovery_times", + "type_info": "Int4" + }, + { + "ordinal": 19, + "name": "on_recovery_extra_args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 20, + "name": "on_success", + "type_info": "Varchar" + }, + { + "ordinal": 21, + "name": "on_success_extra_args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 22, + "name": "ws_error_handler_muted", + "type_info": "Bool" + }, + { + "ordinal": 23, + "name": "retry", + "type_info": "Jsonb" + }, + { + "ordinal": 24, + "name": "no_flow_overlap", + "type_info": "Bool" + }, + { + "ordinal": 25, + "name": "summary", + "type_info": "Varchar" + }, + { + "ordinal": 26, + "name": "description", + "type_info": "Text" + }, + { + "ordinal": 27, + "name": "tag", + "type_info": "Varchar" + }, + { + "ordinal": 28, + "name": "paused_until", + "type_info": "Timestamptz" + }, + { + "ordinal": 29, + "name": "cron_version", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Jsonb", + "Varchar", + "Int4", + "Bool", + "Jsonb", + "Varchar", + "Int4", + "Jsonb", + "Varchar", + "Jsonb", + "Bool", + "Jsonb", + "Varchar", + "Bool", + "Varchar", + "Timestamptz", + "Text", + "Text", + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true + ] + }, + "hash": "348f73fa8222ec195bb5b2260d1595e6e9fa9d73779cf352e94039fd47de4294" +} diff --git a/backend/.sqlx/query-37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d.json b/backend/.sqlx/query-37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d.json new file mode 100644 index 0000000000..5ab1ed1bc3 --- /dev/null +++ b/backend/.sqlx/query-37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture\n SET \n path = $1\n WHERE \n path = $2 \n AND workspace_id = $3 \n AND is_flow = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d" +} diff --git a/backend/.sqlx/query-3734117167a1269f78b3949eed005db96faeec6c18500ad96087cd06c2c85a8b.json b/backend/.sqlx/query-3734117167a1269f78b3949eed005db96faeec6c18500ad96087cd06c2c85a8b.json new file mode 100644 index 0000000000..6a3afafb5e --- /dev/null +++ b/backend/.sqlx/query-3734117167a1269f78b3949eed005db96faeec6c18500ad96087cd06c2c85a8b.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT EXISTS (SELECT 1\n FROM workspace_settings\n WHERE workspace_id <> $1\n AND slack_command_script IS NOT NULL\n AND slack_team_id IS NOT NULL\n AND slack_team_id = (SELECT slack_team_id FROM workspace_settings WHERE workspace_id = $1))\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "3734117167a1269f78b3949eed005db96faeec6c18500ad96087cd06c2c85a8b" +} diff --git a/backend/.sqlx/query-38c20dba51b1e2b4b28e5eed51f9071e1d3cf78e89ec467927823177c5a439cc.json b/backend/.sqlx/query-38c20dba51b1e2b4b28e5eed51f9071e1d3cf78e89ec467927823177c5a439cc.json new file mode 100644 index 0000000000..66681c2377 --- /dev/null +++ b/backend/.sqlx/query-38c20dba51b1e2b4b28e5eed51f9071e1d3cf78e89ec467927823177c5a439cc.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT workspace_id FROM usr WHERE email = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "workspace_id", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "38c20dba51b1e2b4b28e5eed51f9071e1d3cf78e89ec467927823177c5a439cc" +} diff --git a/backend/.sqlx/query-3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605.json b/backend/.sqlx/query-3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605.json new file mode 100644 index 0000000000..b225a5a1da --- /dev/null +++ b/backend/.sqlx/query-3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO gcp_trigger (\n gcp_resource_path,\n subscription_id,\n topic_id,\n delivery_type,\n delivery_config,\n workspace_id, \n path, \n script_path, \n is_flow, \n email, \n enabled, \n edited_by\n ) \n VALUES (\n $1, \n $2, \n $3, \n $4,\n $5,\n $6, \n $7, \n $8, \n $9,\n $10,\n $11,\n $12\n )", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + }, + "Jsonb", + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Varchar", + "Bool", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605" +} diff --git a/backend/.sqlx/query-54798bea6f75ab6d3c680b1085f0462df32172ad0d67321495c94bf2d59010f5.json b/backend/.sqlx/query-4053f0bb30f651ddf2214115748daca0ea457da8252394eeeead0897d184f6da.json similarity index 63% rename from backend/.sqlx/query-54798bea6f75ab6d3c680b1085f0462df32172ad0d67321495c94bf2d59010f5.json rename to backend/.sqlx/query-4053f0bb30f651ddf2214115748daca0ea457da8252394eeeead0897d184f6da.json index cafdebb2c3..ff3968567c 100644 --- a/backend/.sqlx/query-54798bea6f75ab6d3c680b1085f0462df32172ad0d67321495c94bf2d59010f5.json +++ b/backend/.sqlx/query-4053f0bb30f651ddf2214115748daca0ea457da8252394eeeead0897d184f6da.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT \n path, \n script_path, \n is_flow, \n route_path, \n workspace_id, \n is_async, \n requires_auth, \n edited_by, \n email, \n static_asset_config AS \"static_asset_config: _\",\n wrap_body,\n raw_string,\n workspaced_route,\n is_static_website\n FROM \n http_trigger \n WHERE \n http_method = $1\n ", + "query": "\n SELECT \n path, \n script_path, \n is_flow, \n route_path, \n authentication_resource_path,\n workspace_id, \n is_async, \n authentication_method AS \"authentication_method: _\", \n edited_by, \n email, \n static_asset_config AS \"static_asset_config: _\",\n wrap_body,\n raw_string,\n workspaced_route,\n is_static_website\n FROM \n http_trigger \n WHERE \n http_method = $1\n ", "describe": { "columns": [ { @@ -25,51 +25,70 @@ }, { "ordinal": 4, - "name": "workspace_id", + "name": "authentication_resource_path", "type_info": "Varchar" }, { "ordinal": 5, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 6, "name": "is_async", "type_info": "Bool" }, { - "ordinal": 6, - "name": "requires_auth", - "type_info": "Bool" + "ordinal": 7, + "name": "authentication_method: _", + "type_info": { + "Custom": { + "name": "authentication_method", + "kind": { + "Enum": [ + "none", + "windmill", + "api_key", + "basic_http", + "custom_script", + "signature" + ] + } + } + } }, { - "ordinal": 7, + "ordinal": 8, "name": "edited_by", "type_info": "Varchar" }, { - "ordinal": 8, + "ordinal": 9, "name": "email", "type_info": "Varchar" }, { - "ordinal": 9, + "ordinal": 10, "name": "static_asset_config: _", "type_info": "Jsonb" }, { - "ordinal": 10, + "ordinal": 11, "name": "wrap_body", "type_info": "Bool" }, { - "ordinal": 11, + "ordinal": 12, "name": "raw_string", "type_info": "Bool" }, { - "ordinal": 12, + "ordinal": 13, "name": "workspaced_route", "type_info": "Bool" }, { - "ordinal": 13, + "ordinal": 14, "name": "is_static_website", "type_info": "Bool" } @@ -97,6 +116,7 @@ false, false, false, + true, false, false, false, @@ -109,5 +129,5 @@ false ] }, - "hash": "54798bea6f75ab6d3c680b1085f0462df32172ad0d67321495c94bf2d59010f5" + "hash": "4053f0bb30f651ddf2214115748daca0ea457da8252394eeeead0897d184f6da" } diff --git a/backend/.sqlx/query-41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7.json b/backend/.sqlx/query-41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7.json deleted file mode 100644 index 0df0167c42..0000000000 --- a/backend/.sqlx/query-41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "DELETE FROM capture WHERE id = $1", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - }, - "hash": "41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7" -} diff --git a/backend/.sqlx/query-c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534.json b/backend/.sqlx/query-42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2.json similarity index 59% rename from backend/.sqlx/query-c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534.json rename to backend/.sqlx/query-42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2.json index 8c2a88d485..c1a38be77e 100644 --- a/backend/.sqlx/query-c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534.json +++ b/backend/.sqlx/query-42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE capture_config SET last_client_ping = now() WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4", + "query": "\n UPDATE \n capture_config\n SET \n last_client_ping = NOW()\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3 \n AND trigger_kind = $4\n ", "describe": { "columns": [], "parameters": { @@ -21,7 +21,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -30,5 +31,5 @@ }, "nullable": [] }, - "hash": "c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534" + "hash": "42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2" } diff --git a/backend/.sqlx/query-43aa468aac174529a74e6108af55a383f8a20e98b8c502929f4dc5041a55e72f.json b/backend/.sqlx/query-43aa468aac174529a74e6108af55a383f8a20e98b8c502929f4dc5041a55e72f.json deleted file mode 100644 index e33b0dc0b8..0000000000 --- a/backend/.sqlx/query-43aa468aac174529a74e6108af55a383f8a20e98b8c502929f4dc5041a55e72f.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT EXISTS (\n SELECT 1 FROM v2_as_completed_job \n WHERE workspace_id = $2 \n AND (job_kind = 'appscript' OR job_kind = 'preview')\n AND created_by = 'anonymous' \n AND started_at > now() - interval '3 hours'\n AND script_path LIKE $3 || '/%' \n AND result @> ('{\"s3\":\"' || $1 || '\"}')::jsonb \n )", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "exists", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Text", - "Text", - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "43aa468aac174529a74e6108af55a383f8a20e98b8c502929f4dc5041a55e72f" -} diff --git a/backend/.sqlx/query-43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda.json b/backend/.sqlx/query-43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda.json new file mode 100644 index 0000000000..7d6ecdbf32 --- /dev/null +++ b/backend/.sqlx/query-43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture_config \n SET \n error = $1, \n server_id = NULL, \n last_server_ping = NULL \n WHERE \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'gcp'\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda" +} diff --git a/backend/.sqlx/query-443bd83bcea1d37c79cb080095343c98104529879f991c49585cd181e34aa827.json b/backend/.sqlx/query-443bd83bcea1d37c79cb080095343c98104529879f991c49585cd181e34aa827.json new file mode 100644 index 0000000000..65b21050c0 --- /dev/null +++ b/backend/.sqlx/query-443bd83bcea1d37c79cb080095343c98104529879f991c49585cd181e34aa827.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT content FROM script WHERE path = $1 AND workspace_id = $2\n AND created_at = (SELECT max(created_at) FROM script WHERE path = $1 AND\n workspace_id = $2)\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "content", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "443bd83bcea1d37c79cb080095343c98104529879f991c49585cd181e34aa827" +} diff --git a/backend/.sqlx/query-44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd.json b/backend/.sqlx/query-44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd.json new file mode 100644 index 0000000000..87d384f5a1 --- /dev/null +++ b/backend/.sqlx/query-44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd.json @@ -0,0 +1,36 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET \n gcp_resource_path = $1,\n subscription_id = $2,\n topic_id = $3,\n delivery_type = $4,\n delivery_config = $5,\n is_flow = $6, \n edited_by = $7, \n email = $8,\n script_path = $9,\n path = $10,\n enabled = $11,\n edited_at = now(), \n error = NULL,\n server_id = NULL\n WHERE \n workspace_id = $12 AND \n path = $13\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + }, + "Jsonb", + "Bool", + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd" +} diff --git a/backend/.sqlx/query-45d616c92ebcbe30a563e1fa7d2d0e53392e238144b039cfe042587d7fe1dea3.json b/backend/.sqlx/query-45d616c92ebcbe30a563e1fa7d2d0e53392e238144b039cfe042587d7fe1dea3.json deleted file mode 100644 index 052238874a..0000000000 --- a/backend/.sqlx/query-45d616c92ebcbe30a563e1fa7d2d0e53392e238144b039cfe042587d7fe1dea3.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE v2_job_status SET\n workflow_as_code_status = jsonb_set(\n jsonb_set(\n COALESCE(workflow_as_code_status, '{}'::jsonb),\n array[$1],\n COALESCE(workflow_as_code_status->$1, '{}'::jsonb)\n ),\n array[$1, 'started_at'],\n to_jsonb(now()::text)\n )\n WHERE id = $2", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Uuid" - ] - }, - "nullable": [] - }, - "hash": "45d616c92ebcbe30a563e1fa7d2d0e53392e238144b039cfe042587d7fe1dea3" -} diff --git a/backend/.sqlx/query-488dd591096b2b47787afdc3a1d73917ed13269f2ee20b86df79fca2c8efe672.json b/backend/.sqlx/query-488dd591096b2b47787afdc3a1d73917ed13269f2ee20b86df79fca2c8efe672.json index e6d4991053..da5eb1ceea 100644 --- a/backend/.sqlx/query-488dd591096b2b47787afdc3a1d73917ed13269f2ee20b86df79fca2c8efe672.json +++ b/backend/.sqlx/query-488dd591096b2b47787afdc3a1d73917ed13269f2ee20b86df79fca2c8efe672.json @@ -69,7 +69,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } diff --git a/backend/.sqlx/query-4aaab98ebdaa90f1edf49ac96fba6c391c4d0054a618b861464ee37239f1f1e0.json b/backend/.sqlx/query-4aaab98ebdaa90f1edf49ac96fba6c391c4d0054a618b861464ee37239f1f1e0.json index 166d6b84a0..d8a93c797d 100644 --- a/backend/.sqlx/query-4aaab98ebdaa90f1edf49ac96fba6c391c4d0054a618b861464ee37239f1f1e0.json +++ b/backend/.sqlx/query-4aaab98ebdaa90f1edf49ac96fba6c391c4d0054a618b861464ee37239f1f1e0.json @@ -136,7 +136,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } @@ -219,7 +220,9 @@ "schedule", "app", "ui", - "postgres" + "postgres", + "sqs", + "gcp" ] } } diff --git a/backend/.sqlx/query-f8f893fb4f6f8c16bffb233a585df0b8c007c24993979fdc013aa57583905f50.json b/backend/.sqlx/query-4b8132b04e454eddfe6724c6cc3a2e60c9c24decb2a6b41125247bbf741e9c25.json similarity index 57% rename from backend/.sqlx/query-f8f893fb4f6f8c16bffb233a585df0b8c007c24993979fdc013aa57583905f50.json rename to backend/.sqlx/query-4b8132b04e454eddfe6724c6cc3a2e60c9c24decb2a6b41125247bbf741e9c25.json index 759f91c962..ab5b04afc6 100644 --- a/backend/.sqlx/query-f8f893fb4f6f8c16bffb233a585df0b8c007c24993979fdc013aa57583905f50.json +++ b/backend/.sqlx/query-4b8132b04e454eddfe6724c6cc3a2e60c9c24decb2a6b41125247bbf741e9c25.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT owner, premium, usage.usage as \"usage?\", workspace_settings.customer_id, workspace_settings.plan, workspace_settings.automatic_billing FROM workspace LEFT JOIN workspace_settings ON workspace_settings.workspace_id = $1 LEFT JOIN usage ON usage.id = $1 AND month_ = EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date) AND usage.is_workspace IS true WHERE workspace.id = $1", + "query": "SELECT owner, premium, usage.usage as \"usage?\", workspace_settings.customer_id, workspace_settings.plan FROM workspace LEFT JOIN workspace_settings ON workspace_settings.workspace_id = $1 LEFT JOIN usage ON usage.id = $1 AND month_ = EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date) AND usage.is_workspace IS true WHERE workspace.id = $1", "describe": { "columns": [ { @@ -27,11 +27,6 @@ "ordinal": 4, "name": "plan", "type_info": "Varchar" - }, - { - "ordinal": 5, - "name": "automatic_billing", - "type_info": "Bool" } ], "parameters": { @@ -44,9 +39,8 @@ false, false, true, - true, - false + true ] }, - "hash": "f8f893fb4f6f8c16bffb233a585df0b8c007c24993979fdc013aa57583905f50" + "hash": "4b8132b04e454eddfe6724c6cc3a2e60c9c24decb2a6b41125247bbf741e9c25" } diff --git a/backend/.sqlx/query-4e3469185637ad8f06673261bfae1b38c30f7d2689baf647ea4dc6b398c3a651.json b/backend/.sqlx/query-4e3469185637ad8f06673261bfae1b38c30f7d2689baf647ea4dc6b398c3a651.json new file mode 100644 index 0000000000..c6a6f72876 --- /dev/null +++ b/backend/.sqlx/query-4e3469185637ad8f06673261bfae1b38c30f7d2689baf647ea4dc6b398c3a651.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT elem\n FROM workspace_settings,\n LATERAL jsonb_array_elements(git_app_installations) AS elem\n WHERE workspace_id = $1\n AND (elem->>'installation_id')::bigint = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "elem", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [ + null + ] + }, + "hash": "4e3469185637ad8f06673261bfae1b38c30f7d2689baf647ea4dc6b398c3a651" +} diff --git a/backend/.sqlx/query-4edf05cbf35325d444de0e74ee070aafd27ef61c940daba186e7e66f668c31ed.json b/backend/.sqlx/query-4edf05cbf35325d444de0e74ee070aafd27ef61c940daba186e7e66f668c31ed.json deleted file mode 100644 index 4eae8c22fb..0000000000 --- a/backend/.sqlx/query-4edf05cbf35325d444de0e74ee070aafd27ef61c940daba186e7e66f668c31ed.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE workspace_settings SET ai_resource = $1, code_completion_model = $2, ai_models = $3 WHERE workspace_id = $4", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Jsonb", - "Varchar", - "VarcharArray", - "Text" - ] - }, - "nullable": [] - }, - "hash": "4edf05cbf35325d444de0e74ee070aafd27ef61c940daba186e7e66f668c31ed" -} diff --git a/backend/.sqlx/query-505250098ab003ff0ca30046df283e54bf44be74305070f10a5720a04c4789f3.json b/backend/.sqlx/query-505250098ab003ff0ca30046df283e54bf44be74305070f10a5720a04c4789f3.json new file mode 100644 index 0000000000..fb3fbe4f0e --- /dev/null +++ b/backend/.sqlx/query-505250098ab003ff0ca30046df283e54bf44be74305070f10a5720a04c4789f3.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE v2_job_queue\n SET canceled_by = $1\n , canceled_reason = $2\nWHERE id = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "505250098ab003ff0ca30046df283e54bf44be74305070f10a5720a04c4789f3" +} diff --git a/backend/.sqlx/query-e968e879d3c52f7dd502c3cd15fc8fbd983a4a3ab25648c562497a27c74b5c8c.json b/backend/.sqlx/query-506066203c49424e9944eb3948dc1657d3d796e6233e9f0ec925879c705d4773.json similarity index 64% rename from backend/.sqlx/query-e968e879d3c52f7dd502c3cd15fc8fbd983a4a3ab25648c562497a27c74b5c8c.json rename to backend/.sqlx/query-506066203c49424e9944eb3948dc1657d3d796e6233e9f0ec925879c705d4773.json index 3bacda16d9..50d4a9595d 100644 --- a/backend/.sqlx/query-e968e879d3c52f7dd502c3cd15fc8fbd983a4a3ab25648c562497a27c74b5c8c.json +++ b/backend/.sqlx/query-506066203c49424e9944eb3948dc1657d3d796e6233e9f0ec925879c705d4773.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE worker_ping SET ping_at = now(), current_job_id = $1, current_job_workspace_id = $2, memory_usage = $3, wm_memory_usage = $4,\n occupancy_rate = $6, occupancy_rate_15s = $7, occupancy_rate_5m = $8, occupancy_rate_30m = $9 WHERE worker = $5", + "query": "UPDATE worker_ping SET ping_at = now(), current_job_id = $1, current_job_workspace_id = $2, memory_usage = $3, wm_memory_usage = $4,\n occupancy_rate = $6, occupancy_rate_15s = $7, occupancy_rate_5m = $8, occupancy_rate_30m = $9 WHERE worker = $5", "describe": { "columns": [], "parameters": { @@ -18,5 +18,5 @@ }, "nullable": [] }, - "hash": "e968e879d3c52f7dd502c3cd15fc8fbd983a4a3ab25648c562497a27c74b5c8c" + "hash": "506066203c49424e9944eb3948dc1657d3d796e6233e9f0ec925879c705d4773" } diff --git a/backend/.sqlx/query-5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7.json b/backend/.sqlx/query-5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7.json new file mode 100644 index 0000000000..f010362e6f --- /dev/null +++ b/backend/.sqlx/query-5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7.json @@ -0,0 +1,65 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT \n gcp_resource_path, \n script_path,\n is_flow, \n workspace_id,\n path,\n edited_by,\n email,\n delivery_config AS \"delivery_config: _\"\n FROM\n gcp_trigger\n WHERE\n workspace_id = $1 AND\n path = $2 AND\n delivery_type = 'push'::DELIVERY_MODE \n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "gcp_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 3, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "delivery_config: _", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true + ] + }, + "hash": "5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7" +} diff --git a/backend/.sqlx/query-55cb03040bc2a8c53dd7fbb42bbdcc40f463cbc52d94ed9315cf9a547d4c89f2.json b/backend/.sqlx/query-55cb03040bc2a8c53dd7fbb42bbdcc40f463cbc52d94ed9315cf9a547d4c89f2.json index 14685a8bfa..009d9fe5d1 100644 --- a/backend/.sqlx/query-55cb03040bc2a8c53dd7fbb42bbdcc40f463cbc52d94ed9315cf9a547d4c89f2.json +++ b/backend/.sqlx/query-55cb03040bc2a8c53dd7fbb42bbdcc40f463cbc52d94ed9315cf9a547d4c89f2.json @@ -65,7 +65,7 @@ }, { "ordinal": 12, - "name": "ai_resource", + "name": "ai_config", "type_info": "Jsonb" }, { @@ -100,58 +100,48 @@ }, { "ordinal": 19, - "name": "automatic_billing", - "type_info": "Bool" - }, - { - "ordinal": 20, "name": "default_scripts", "type_info": "Jsonb" }, { - "ordinal": 21, + "ordinal": 20, "name": "deploy_ui", "type_info": "Jsonb" }, { - "ordinal": 22, + "ordinal": 21, "name": "mute_critical_alerts", "type_info": "Bool" }, { - "ordinal": 23, + "ordinal": 22, "name": "color", "type_info": "Varchar" }, { - "ordinal": 24, + "ordinal": 23, "name": "operator_settings", "type_info": "Jsonb" }, { - "ordinal": 25, - "name": "ai_models", - "type_info": "VarcharArray" - }, - { - "ordinal": 26, - "name": "code_completion_model", - "type_info": "Varchar" - }, - { - "ordinal": 27, + "ordinal": 24, "name": "teams_command_script", "type_info": "Text" }, { - "ordinal": 28, + "ordinal": 25, "name": "teams_team_id", "type_info": "Text" }, { - "ordinal": 29, + "ordinal": 26, "name": "teams_team_name", "type_info": "Text" + }, + { + "ordinal": 27, + "name": "git_app_installations", + "type_info": "Jsonb" } ], "parameters": { @@ -179,17 +169,15 @@ true, true, true, - false, true, true, true, true, true, - false, true, true, true, - true + false ] }, "hash": "55cb03040bc2a8c53dd7fbb42bbdcc40f463cbc52d94ed9315cf9a547d4c89f2" diff --git a/backend/.sqlx/query-5824982a58edd5bb2666daac49b2a6ff8553b9c196ca64ea2752df8cfe30c30c.json b/backend/.sqlx/query-56c2522a12f91515e38290e4680a55a4727195125cd49a2f92f89bcdf74dc364.json similarity index 66% rename from backend/.sqlx/query-5824982a58edd5bb2666daac49b2a6ff8553b9c196ca64ea2752df8cfe30c30c.json rename to backend/.sqlx/query-56c2522a12f91515e38290e4680a55a4727195125cd49a2f92f89bcdf74dc364.json index c54aa8f20d..d547567d28 100644 --- a/backend/.sqlx/query-5824982a58edd5bb2666daac49b2a6ff8553b9c196ca64ea2752df8cfe30c30c.json +++ b/backend/.sqlx/query-56c2522a12f91515e38290e4680a55a4727195125cd49a2f92f89bcdf74dc364.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT \n workspace_id, \n workspaced_route,\n path, \n route_path, \n route_path_key, \n script_path, \n is_flow, \n edited_by, \n edited_at, \n email, \n extra_perms, \n is_async, \n requires_auth, \n http_method AS \"http_method: _\", \n static_asset_config AS \"static_asset_config: _\", \n is_static_website,\n wrap_body,\n raw_string\n FROM http_trigger\n WHERE workspace_id = $1\n ", + "query": "\n SELECT \n workspace_id, \n workspaced_route,\n path, \n route_path, \n route_path_key, \n authentication_resource_path,\n script_path, \n is_flow, \n edited_by, \n edited_at, \n email, \n extra_perms, \n is_async, \n authentication_method AS \"authentication_method: _\", \n http_method AS \"http_method: _\", \n static_asset_config AS \"static_asset_config: _\", \n is_static_website,\n wrap_body,\n raw_string\n FROM http_trigger\n WHERE workspace_id = $1\n ", "describe": { "columns": [ { @@ -30,46 +30,65 @@ }, { "ordinal": 5, - "name": "script_path", + "name": "authentication_resource_path", "type_info": "Varchar" }, { "ordinal": 6, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 7, "name": "is_flow", "type_info": "Bool" }, { - "ordinal": 7, + "ordinal": 8, "name": "edited_by", "type_info": "Varchar" }, { - "ordinal": 8, + "ordinal": 9, "name": "edited_at", "type_info": "Timestamptz" }, { - "ordinal": 9, + "ordinal": 10, "name": "email", "type_info": "Varchar" }, { - "ordinal": 10, + "ordinal": 11, "name": "extra_perms", "type_info": "Jsonb" }, { - "ordinal": 11, + "ordinal": 12, "name": "is_async", "type_info": "Bool" }, { - "ordinal": 12, - "name": "requires_auth", - "type_info": "Bool" + "ordinal": 13, + "name": "authentication_method: _", + "type_info": { + "Custom": { + "name": "authentication_method", + "kind": { + "Enum": [ + "none", + "windmill", + "api_key", + "basic_http", + "custom_script", + "signature" + ] + } + } + } }, { - "ordinal": 13, + "ordinal": 14, "name": "http_method: _", "type_info": { "Custom": { @@ -87,22 +106,22 @@ } }, { - "ordinal": 14, + "ordinal": 15, "name": "static_asset_config: _", "type_info": "Jsonb" }, { - "ordinal": 15, + "ordinal": 16, "name": "is_static_website", "type_info": "Bool" }, { - "ordinal": 16, + "ordinal": 17, "name": "wrap_body", "type_info": "Bool" }, { - "ordinal": 17, + "ordinal": 18, "name": "raw_string", "type_info": "Bool" } @@ -118,6 +137,7 @@ false, false, false, + true, false, false, false, @@ -133,5 +153,5 @@ false ] }, - "hash": "5824982a58edd5bb2666daac49b2a6ff8553b9c196ca64ea2752df8cfe30c30c" + "hash": "56c2522a12f91515e38290e4680a55a4727195125cd49a2f92f89bcdf74dc364" } diff --git a/backend/.sqlx/query-5d3401f608b27937285e418f7bd64bd112977c995bf266680c54f58ad57fd4b6.json b/backend/.sqlx/query-5d3401f608b27937285e418f7bd64bd112977c995bf266680c54f58ad57fd4b6.json deleted file mode 100644 index b962770bd9..0000000000 --- a/backend/.sqlx/query-5d3401f608b27937285e418f7bd64bd112977c995bf266680c54f58ad57fd4b6.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE \n http_trigger \n SET \n script_path = $1, \n path = $2, \n is_flow = $3, \n http_method = $4,\n static_asset_config = $5, \n edited_by = $6, \n email = $7, \n is_async = $8, \n requires_auth = $9, \n edited_at = now(), \n is_static_website = $10\n WHERE \n workspace_id = $11 AND \n path = $12\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Varchar", - "Bool", - { - "Custom": { - "name": "http_method", - "kind": { - "Enum": [ - "get", - "post", - "put", - "delete", - "patch" - ] - } - } - }, - "Jsonb", - "Varchar", - "Varchar", - "Bool", - "Bool", - "Bool", - "Text", - "Text" - ] - }, - "nullable": [] - }, - "hash": "5d3401f608b27937285e418f7bd64bd112977c995bf266680c54f58ad57fd4b6" -} diff --git a/backend/.sqlx/query-5ea1d8c87a17690942ca9e70e0b953e3b32a9a7a73784219d48f8e8932cdb0c8.json b/backend/.sqlx/query-5ea1d8c87a17690942ca9e70e0b953e3b32a9a7a73784219d48f8e8932cdb0c8.json new file mode 100644 index 0000000000..304814543b --- /dev/null +++ b/backend/.sqlx/query-5ea1d8c87a17690942ca9e70e0b953e3b32a9a7a73784219d48f8e8932cdb0c8.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT jsonb_build_object(\n 'kind', jb.kind,\n 'script_path', jb.runnable_path,\n 'latest_schema', COALESCE(\n (SELECT DISTINCT ON (s.path) s.schema FROM script s WHERE s.path = jb.runnable_path AND jb.kind = 'script' ORDER BY s.path, s.created_at DESC),\n (SELECT flow_version.schema FROM flow LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] WHERE flow.path = jb.runnable_path AND jb.kind = 'flow')\n ),\n 'schemas', ARRAY(\n SELECT jsonb_build_object(\n 'script_hash', LPAD(TO_HEX(COALESCE(s.hash, f.id)), 16, '0'),\n 'job_ids', ARRAY_AGG(DISTINCT j.id),\n 'schema', ANY_VALUE(COALESCE(s.schema, f.schema))\n ) FROM v2_job j\n LEFT JOIN script s ON s.hash = j.runnable_id AND j.kind = 'script'\n LEFT JOIN flow_version f ON f.id = j.runnable_id AND j.kind = 'flow'\n WHERE j.id = ANY(ARRAY_AGG(jb.id))\n GROUP BY COALESCE(s.hash, f.id)\n )\n ) FROM v2_job jb\n WHERE (jb.kind = 'flow' OR jb.kind = 'script')\n AND jb.workspace_id = $1 AND jb.id = ANY($2)\n GROUP BY jb.kind, jb.runnable_path", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "jsonb_build_object", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Text", + "UuidArray" + ] + }, + "nullable": [ + null + ] + }, + "hash": "5ea1d8c87a17690942ca9e70e0b953e3b32a9a7a73784219d48f8e8932cdb0c8" +} diff --git a/backend/.sqlx/query-0a9dd1addaf48eeb46eed59abb6daf9819d07b08cf7ca442ea7ec78a9b2b63b2.json b/backend/.sqlx/query-5faba1042763a308c64e36cc2a331d90bc0aa384262e473c7006340dcb6e959c.json similarity index 59% rename from backend/.sqlx/query-0a9dd1addaf48eeb46eed59abb6daf9819d07b08cf7ca442ea7ec78a9b2b63b2.json rename to backend/.sqlx/query-5faba1042763a308c64e36cc2a331d90bc0aa384262e473c7006340dcb6e959c.json index a0f52168b9..9b7f1962a4 100644 --- a/backend/.sqlx/query-0a9dd1addaf48eeb46eed59abb6daf9819d07b08cf7ca442ea7ec78a9b2b63b2.json +++ b/backend/.sqlx/query-5faba1042763a308c64e36cc2a331d90bc0aa384262e473c7006340dcb6e959c.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT value\n FROM resource\n WHERE path = $1 AND workspace_id = $2", + "query": "SELECT value FROM resource WHERE workspace_id = $1 AND path = $2", "describe": { "columns": [ { @@ -19,5 +19,5 @@ true ] }, - "hash": "0a9dd1addaf48eeb46eed59abb6daf9819d07b08cf7ca442ea7ec78a9b2b63b2" + "hash": "5faba1042763a308c64e36cc2a331d90bc0aa384262e473c7006340dcb6e959c" } diff --git a/backend/.sqlx/query-6199e8be5cb13db71108e555ea20f0b76dc38476670f9fc0667b057d2766d42e.json b/backend/.sqlx/query-6199e8be5cb13db71108e555ea20f0b76dc38476670f9fc0667b057d2766d42e.json deleted file mode 100644 index 2313dd087c..0000000000 --- a/backend/.sqlx/query-6199e8be5cb13db71108e555ea20f0b76dc38476670f9fc0667b057d2766d42e.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT set_config('session.groups', $1, true)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "set_config", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "6199e8be5cb13db71108e555ea20f0b76dc38476670f9fc0667b057d2766d42e" -} diff --git a/backend/.sqlx/query-61c29d684e8e683e839a6d7210b3b9b96854e5bfd752e45922c358c42ebea0c4.json b/backend/.sqlx/query-61c29d684e8e683e839a6d7210b3b9b96854e5bfd752e45922c358c42ebea0c4.json index 1bc34cfbc0..be472306a0 100644 --- a/backend/.sqlx/query-61c29d684e8e683e839a6d7210b3b9b96854e5bfd752e45922c358c42ebea0c4.json +++ b/backend/.sqlx/query-61c29d684e8e683e839a6d7210b3b9b96854e5bfd752e45922c358c42ebea0c4.json @@ -60,7 +60,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } diff --git a/backend/.sqlx/query-64adf72c19023b03a47d48444b1cf970559b3ef735274ef0fef6f47b4c68da7e.json b/backend/.sqlx/query-64adf72c19023b03a47d48444b1cf970559b3ef735274ef0fef6f47b4c68da7e.json index d90022a58d..d6fbd2ff35 100644 --- a/backend/.sqlx/query-64adf72c19023b03a47d48444b1cf970559b3ef735274ef0fef6f47b4c68da7e.json +++ b/backend/.sqlx/query-64adf72c19023b03a47d48444b1cf970559b3ef735274ef0fef6f47b4c68da7e.json @@ -13,7 +13,7 @@ "Left": [ "Bool", "Varchar", - "Json", + "Jsonb", "Int4", "Bool", "Text" diff --git a/backend/.sqlx/query-673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333.json b/backend/.sqlx/query-673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333.json new file mode 100644 index 0000000000..8b9a46c4d0 --- /dev/null +++ b/backend/.sqlx/query-673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE \n capture_config \n SET \n last_server_ping = NULL \n WHERE \n workspace_id = $1 AND \n path = $2 AND \n is_flow = $3 AND \n trigger_kind = 'gcp' AND \n server_id IS NULL\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333" +} diff --git a/backend/.sqlx/query-e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7.json b/backend/.sqlx/query-6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414.json similarity index 70% rename from backend/.sqlx/query-e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7.json rename to backend/.sqlx/query-6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414.json index 60332810b2..2e4638f1f7 100644 --- a/backend/.sqlx/query-e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7.json +++ b/backend/.sqlx/query-6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, created_at, trigger_kind as \"trigger_kind: _\", payload as \"payload!: _\", trigger_extra as \"trigger_extra: _\" FROM capture WHERE id = $1 AND workspace_id = $2", + "query": "\n SELECT \n id, \n created_at, \n trigger_kind AS \"trigger_kind: _\", \n payload AS \"payload!: _\", \n trigger_extra AS \"trigger_extra: _\"\n FROM \n capture\n WHERE \n id = $1 \n AND workspace_id = $2\n ", "describe": { "columns": [ { @@ -29,7 +29,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -60,5 +61,5 @@ true ] }, - "hash": "e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7" + "hash": "6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414" } diff --git a/backend/.sqlx/query-69518153298f8ca6f112bed156b520758656ce6bcd1e694a62e140e0af8c59fa.json b/backend/.sqlx/query-69518153298f8ca6f112bed156b520758656ce6bcd1e694a62e140e0af8c59fa.json new file mode 100644 index 0000000000..f96e0e349a --- /dev/null +++ b/backend/.sqlx/query-69518153298f8ca6f112bed156b520758656ce6bcd1e694a62e140e0af8c59fa.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE workspace_settings\n SET git_app_installations = COALESCE(\n (\n SELECT jsonb_agg(elem)\n FROM (\n SELECT elem\n FROM jsonb_array_elements(git_app_installations) AS elem\n WHERE (elem->>'installation_id')::bigint != ($1::jsonb->>'installation_id')::bigint\n UNION ALL\n SELECT $1::jsonb\n ) sub\n ),\n jsonb_build_array($1::jsonb)\n )\n WHERE workspace_id = $2;\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb", + "Text" + ] + }, + "nullable": [] + }, + "hash": "69518153298f8ca6f112bed156b520758656ce6bcd1e694a62e140e0af8c59fa" +} diff --git a/backend/.sqlx/query-6c90d5ea2a09b47b81fdab465062c25f8768b220e53bf469550a3a3697ab756a.json b/backend/.sqlx/query-6c90d5ea2a09b47b81fdab465062c25f8768b220e53bf469550a3a3697ab756a.json deleted file mode 100644 index fb5e174ced..0000000000 --- a/backend/.sqlx/query-6c90d5ea2a09b47b81fdab465062c25f8768b220e53bf469550a3a3697ab756a.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT set_config('session.user', $1, true)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "set_config", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "6c90d5ea2a09b47b81fdab465062c25f8768b220e53bf469550a3a3697ab756a" -} diff --git a/backend/.sqlx/query-4e9c2e0690eaca280ccb5e5160438f207d930d29e3000b9845eef89e87a35ad1.json b/backend/.sqlx/query-71a040866adbd192080da165eb120abf7531b2542a2da225152e19144400f950.json similarity index 81% rename from backend/.sqlx/query-4e9c2e0690eaca280ccb5e5160438f207d930d29e3000b9845eef89e87a35ad1.json rename to backend/.sqlx/query-71a040866adbd192080da165eb120abf7531b2542a2da225152e19144400f950.json index 3dd496788f..d17cf3c524 100644 --- a/backend/.sqlx/query-4e9c2e0690eaca280ccb5e5160438f207d930d29e3000b9845eef89e87a35ad1.json +++ b/backend/.sqlx/query-71a040866adbd192080da165eb120abf7531b2542a2da225152e19144400f950.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT workspace_id, slack_team_id, teams_team_id, teams_team_name, slack_name, slack_command_script, teams_command_script, slack_email, auto_invite_domain, auto_invite_operator, auto_add, customer_id, plan, webhook, deploy_to, ai_resource, ai_models, code_completion_model, error_handler, error_handler_extra_args, error_handler_muted_on_cancel, large_file_storage, git_sync, deploy_ui, default_app, automatic_billing, default_scripts, mute_critical_alerts, color, operator_settings FROM workspace_settings WHERE workspace_id = $1", + "query": "SELECT workspace_id, slack_team_id, teams_team_id, teams_team_name, slack_name, slack_command_script, teams_command_script, slack_email, auto_invite_domain, auto_invite_operator, auto_add, customer_id, plan, webhook, deploy_to, ai_config, error_handler, error_handler_extra_args, error_handler_muted_on_cancel, large_file_storage, git_sync, deploy_ui, default_app, default_scripts, mute_critical_alerts, color, operator_settings, git_app_installations FROM workspace_settings WHERE workspace_id = $1", "describe": { "columns": [ { @@ -80,78 +80,68 @@ }, { "ordinal": 15, - "name": "ai_resource", + "name": "ai_config", "type_info": "Jsonb" }, { "ordinal": 16, - "name": "ai_models", - "type_info": "VarcharArray" - }, - { - "ordinal": 17, - "name": "code_completion_model", - "type_info": "Varchar" - }, - { - "ordinal": 18, "name": "error_handler", "type_info": "Varchar" }, { - "ordinal": 19, + "ordinal": 17, "name": "error_handler_extra_args", "type_info": "Json" }, { - "ordinal": 20, + "ordinal": 18, "name": "error_handler_muted_on_cancel", "type_info": "Bool" }, { - "ordinal": 21, + "ordinal": 19, "name": "large_file_storage", "type_info": "Jsonb" }, { - "ordinal": 22, + "ordinal": 20, "name": "git_sync", "type_info": "Jsonb" }, { - "ordinal": 23, + "ordinal": 21, "name": "deploy_ui", "type_info": "Jsonb" }, { - "ordinal": 24, + "ordinal": 22, "name": "default_app", "type_info": "Varchar" }, { - "ordinal": 25, - "name": "automatic_billing", - "type_info": "Bool" - }, - { - "ordinal": 26, + "ordinal": 23, "name": "default_scripts", "type_info": "Jsonb" }, { - "ordinal": 27, + "ordinal": 24, "name": "mute_critical_alerts", "type_info": "Bool" }, { - "ordinal": 28, + "ordinal": 25, "name": "color", "type_info": "Varchar" }, { - "ordinal": 29, + "ordinal": 26, "name": "operator_settings", "type_info": "Jsonb" + }, + { + "ordinal": 27, + "name": "git_app_installations", + "type_info": "Jsonb" } ], "parameters": { @@ -176,21 +166,19 @@ true, true, true, - false, - true, - true, - true, - false, - true, - true, true, true, false, true, true, true, - true + true, + true, + true, + true, + true, + false ] }, - "hash": "4e9c2e0690eaca280ccb5e5160438f207d930d29e3000b9845eef89e87a35ad1" + "hash": "71a040866adbd192080da165eb120abf7531b2542a2da225152e19144400f950" } diff --git a/backend/.sqlx/query-75451b6d48e4c26812ae64981d0d968b8fb0bf4374a2fccc167fa879bad7078f.json b/backend/.sqlx/query-75451b6d48e4c26812ae64981d0d968b8fb0bf4374a2fccc167fa879bad7078f.json index 98de576f13..cf2b476448 100644 --- a/backend/.sqlx/query-75451b6d48e4c26812ae64981d0d968b8fb0bf4374a2fccc167fa879bad7078f.json +++ b/backend/.sqlx/query-75451b6d48e4c26812ae64981d0d968b8fb0bf4374a2fccc167fa879bad7078f.json @@ -60,7 +60,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } diff --git a/backend/.sqlx/query-77701b16ee1f6dd827372835db59bbffc7254af47a8d48b7ba3cf969c2f8398c.json b/backend/.sqlx/query-77701b16ee1f6dd827372835db59bbffc7254af47a8d48b7ba3cf969c2f8398c.json new file mode 100644 index 0000000000..e6e754579f --- /dev/null +++ b/backend/.sqlx/query-77701b16ee1f6dd827372835db59bbffc7254af47a8d48b7ba3cf969c2f8398c.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE v2_job_queue SET tag = $1, running = false WHERE id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "77701b16ee1f6dd827372835db59bbffc7254af47a8d48b7ba3cf969c2f8398c" +} diff --git a/backend/.sqlx/query-5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd.json b/backend/.sqlx/query-7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3.json similarity index 64% rename from backend/.sqlx/query-5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd.json rename to backend/.sqlx/query-7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3.json index 61c4d20b04..a313dd6076 100644 --- a/backend/.sqlx/query-5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd.json +++ b/backend/.sqlx/query-7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, created_at, trigger_kind as \"trigger_kind: _\", CASE WHEN pg_column_size(payload) < 40000 THEN payload ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as \"payload!: _\", trigger_extra as \"trigger_extra: _\"\n FROM capture\n WHERE workspace_id = $1\n AND path = $2 AND is_flow = $3\n AND ($4::trigger_kind IS NULL OR trigger_kind = $4)\n ORDER BY created_at DESC\n OFFSET $5\n LIMIT $6", + "query": "\n SELECT \n id, \n created_at, \n trigger_kind AS \"trigger_kind: _\",\n CASE \n WHEN pg_column_size(payload) < 40000 THEN payload \n ELSE '\"WINDMILL_TOO_BIG\"'::jsonb \n END AS \"payload!: _\",\n trigger_extra AS \"trigger_extra: _\"\n FROM \n capture\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3 \n AND ($4::trigger_kind IS NULL OR trigger_kind = $4)\n ORDER BY \n created_at DESC\n OFFSET $5\n LIMIT $6\n ", "describe": { "columns": [ { @@ -29,7 +29,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -64,7 +65,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -81,5 +83,5 @@ true ] }, - "hash": "5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd" + "hash": "7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3" } diff --git a/backend/.sqlx/query-7cd070aaca3b4f95bb6e669ac07f288bd1cc8a85625255d86e45f63e8267d34c.json b/backend/.sqlx/query-7cd070aaca3b4f95bb6e669ac07f288bd1cc8a85625255d86e45f63e8267d34c.json new file mode 100644 index 0000000000..99095e3fcc --- /dev/null +++ b/backend/.sqlx/query-7cd070aaca3b4f95bb6e669ac07f288bd1cc8a85625255d86e45f63e8267d34c.json @@ -0,0 +1,199 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE schedule SET\n enabled = $1,\n email = $2\n WHERE path = $3 AND workspace_id = $4\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "schedule", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "timezone", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "enabled", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 10, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 11, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 12, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 13, + "name": "on_failure", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "on_failure_times", + "type_info": "Int4" + }, + { + "ordinal": 15, + "name": "on_failure_exact", + "type_info": "Bool" + }, + { + "ordinal": 16, + "name": "on_failure_extra_args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 17, + "name": "on_recovery", + "type_info": "Varchar" + }, + { + "ordinal": 18, + "name": "on_recovery_times", + "type_info": "Int4" + }, + { + "ordinal": 19, + "name": "on_recovery_extra_args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 20, + "name": "on_success", + "type_info": "Varchar" + }, + { + "ordinal": 21, + "name": "on_success_extra_args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 22, + "name": "ws_error_handler_muted", + "type_info": "Bool" + }, + { + "ordinal": 23, + "name": "retry", + "type_info": "Jsonb" + }, + { + "ordinal": 24, + "name": "no_flow_overlap", + "type_info": "Bool" + }, + { + "ordinal": 25, + "name": "summary", + "type_info": "Varchar" + }, + { + "ordinal": 26, + "name": "description", + "type_info": "Text" + }, + { + "ordinal": 27, + "name": "tag", + "type_info": "Varchar" + }, + { + "ordinal": 28, + "name": "paused_until", + "type_info": "Timestamptz" + }, + { + "ordinal": 29, + "name": "cron_version", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Bool", + "Varchar", + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true + ] + }, + "hash": "7cd070aaca3b4f95bb6e669ac07f288bd1cc8a85625255d86e45f63e8267d34c" +} diff --git a/backend/.sqlx/query-7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795.json b/backend/.sqlx/query-7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795.json new file mode 100644 index 0000000000..e1ab284262 --- /dev/null +++ b/backend/.sqlx/query-7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM \n capture\n WHERE \n id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795" +} diff --git a/backend/.sqlx/query-7e64ba7e2362cc19d2aed9f34c9879983922e96a9baab7c1a2b09ed2b1c261e2.json b/backend/.sqlx/query-7e64ba7e2362cc19d2aed9f34c9879983922e96a9baab7c1a2b09ed2b1c261e2.json new file mode 100644 index 0000000000..9984af6e6e --- /dev/null +++ b/backend/.sqlx/query-7e64ba7e2362cc19d2aed9f34c9879983922e96a9baab7c1a2b09ed2b1c261e2.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT \n active_pid \n FROM \n pg_replication_slots \n WHERE \n slot_name = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "active_pid", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Name" + ] + }, + "nullable": [ + true + ] + }, + "hash": "7e64ba7e2362cc19d2aed9f34c9879983922e96a9baab7c1a2b09ed2b1c261e2" +} diff --git a/backend/.sqlx/query-7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566.json b/backend/.sqlx/query-7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566.json deleted file mode 100644 index 4e6d8e9ba2..0000000000 --- a/backend/.sqlx/query-7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE capture_config SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Text", - "Text", - "Bool" - ] - }, - "nullable": [] - }, - "hash": "7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566" -} diff --git a/backend/.sqlx/query-7ecb01893c46823a207bf59aa57d6f4c6e63f7b7b6d4cf0b4ae1237da0e17b4b.json b/backend/.sqlx/query-7ecb01893c46823a207bf59aa57d6f4c6e63f7b7b6d4cf0b4ae1237da0e17b4b.json new file mode 100644 index 0000000000..628794aae4 --- /dev/null +++ b/backend/.sqlx/query-7ecb01893c46823a207bf59aa57d6f4c6e63f7b7b6d4cf0b4ae1237da0e17b4b.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n jsonb_array_elements(git_sync->'repositories')->>'script_path' AS script_path,\n jsonb_array_elements(git_sync->'repositories')->>'git_repo_resource_path' AS git_repo_resource_path\n FROM workspace_settings\n WHERE workspace_id = $1;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "script_path", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "git_repo_resource_path", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "7ecb01893c46823a207bf59aa57d6f4c6e63f7b7b6d4cf0b4ae1237da0e17b4b" +} diff --git a/backend/.sqlx/query-7f772ceace10008d7d40afd331a585bfa19b70315840585c81b8e7a3911ab5e7.json b/backend/.sqlx/query-7f772ceace10008d7d40afd331a585bfa19b70315840585c81b8e7a3911ab5e7.json new file mode 100644 index 0000000000..1d7b5ddba5 --- /dev/null +++ b/backend/.sqlx/query-7f772ceace10008d7d40afd331a585bfa19b70315840585c81b8e7a3911ab5e7.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE workspace_settings\n SET git_app_installations = COALESCE(\n (\n SELECT jsonb_agg(elem)\n FROM jsonb_array_elements(git_app_installations) AS elem\n WHERE (elem->>'installation_id')::bigint != $1\n ),\n '[]'::jsonb\n )\n WHERE workspace_id = $2;\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text" + ] + }, + "nullable": [] + }, + "hash": "7f772ceace10008d7d40afd331a585bfa19b70315840585c81b8e7a3911ab5e7" +} diff --git a/backend/.sqlx/query-c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8.json b/backend/.sqlx/query-7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa.json similarity index 68% rename from backend/.sqlx/query-c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8.json rename to backend/.sqlx/query-7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa.json index 45ce8d3f95..ca02b5c648 100644 --- a/backend/.sqlx/query-c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8.json +++ b/backend/.sqlx/query-7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT trigger_config as \"trigger_config: _\", trigger_kind as \"trigger_kind: _\", error, last_server_ping\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3", + "query": "\n SELECT \n trigger_config AS \"trigger_config: _\", \n trigger_kind AS \"trigger_kind: _\", \n error, \n last_server_ping\n FROM \n capture_config\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3\n ", "describe": { "columns": [ { @@ -24,7 +24,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -55,5 +56,5 @@ true ] }, - "hash": "c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8" + "hash": "7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa" } diff --git a/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json b/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json index 967f53c987..89745202b0 100644 --- a/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json +++ b/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json @@ -33,7 +33,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } diff --git a/backend/.sqlx/query-71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447.json b/backend/.sqlx/query-87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29.json similarity index 63% rename from backend/.sqlx/query-71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447.json rename to backend/.sqlx/query-87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29.json index 643e0854bb..e2acac048f 100644 --- a/backend/.sqlx/query-71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447.json +++ b/backend/.sqlx/query-87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT owner, email\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'", + "query": "\n SELECT \n owner, \n email\n FROM \n capture_config\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3 \n AND trigger_kind = $4 \n AND last_client_ping > NOW() - INTERVAL '10 seconds'\n ", "describe": { "columns": [ { @@ -32,7 +32,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -44,5 +45,5 @@ false ] }, - "hash": "71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447" + "hash": "87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29" } diff --git a/backend/.sqlx/query-884039108b98daa6279975e65348e460f99a0d2155fe2ff7b1d2840c5d9b76d0.json b/backend/.sqlx/query-884039108b98daa6279975e65348e460f99a0d2155fe2ff7b1d2840c5d9b76d0.json new file mode 100644 index 0000000000..64048e92f8 --- /dev/null +++ b/backend/.sqlx/query-884039108b98daa6279975e65348e460f99a0d2155fe2ff7b1d2840c5d9b76d0.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT elem\n FROM workspace_settings,\n LATERAL jsonb_array_elements(git_app_installations) AS elem\n WHERE workspace_id = $1\n AND (elem->>'installation_id')::bigint = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "elem", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [ + null + ] + }, + "hash": "884039108b98daa6279975e65348e460f99a0d2155fe2ff7b1d2840c5d9b76d0" +} diff --git a/backend/.sqlx/query-89de3ff8ab32e545efcbcda05f994cb1a32c4991cbd25046282d34272587d2de.json b/backend/.sqlx/query-89de3ff8ab32e545efcbcda05f994cb1a32c4991cbd25046282d34272587d2de.json index e7f486d2a4..99c2dc90a2 100644 --- a/backend/.sqlx/query-89de3ff8ab32e545efcbcda05f994cb1a32c4991cbd25046282d34272587d2de.json +++ b/backend/.sqlx/query-89de3ff8ab32e545efcbcda05f994cb1a32c4991cbd25046282d34272587d2de.json @@ -60,7 +60,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } diff --git a/backend/.sqlx/query-8c30e91c2486f7511563621e7e805d0588a9ec8bbea9db10e95783e27e35bc12.json b/backend/.sqlx/query-8c30e91c2486f7511563621e7e805d0588a9ec8bbea9db10e95783e27e35bc12.json new file mode 100644 index 0000000000..961a55d8b1 --- /dev/null +++ b/backend/.sqlx/query-8c30e91c2486f7511563621e7e805d0588a9ec8bbea9db10e95783e27e35bc12.json @@ -0,0 +1,57 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO http_trigger (\n workspace_id, \n path, \n route_path, \n route_path_key,\n workspaced_route,\n authentication_resource_path,\n wrap_body,\n raw_string,\n script_path, \n is_flow, \n is_async, \n authentication_method, \n http_method, \n static_asset_config, \n edited_by, \n email, \n edited_at, \n is_static_website\n ) \n VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, now(), $17\n )\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Varchar", + "Bool", + "Bool", + "Varchar", + "Bool", + "Bool", + { + "Custom": { + "name": "authentication_method", + "kind": { + "Enum": [ + "none", + "windmill", + "api_key", + "basic_http", + "custom_script", + "signature" + ] + } + } + }, + { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + }, + "Jsonb", + "Varchar", + "Varchar", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "8c30e91c2486f7511563621e7e805d0588a9ec8bbea9db10e95783e27e35bc12" +} diff --git a/backend/.sqlx/query-8efd06387ded837d7849adafe5bc93acb882ef90fc58b023650c875e0fd17047.json b/backend/.sqlx/query-8efd06387ded837d7849adafe5bc93acb882ef90fc58b023650c875e0fd17047.json deleted file mode 100644 index 005e8fedc9..0000000000 --- a/backend/.sqlx/query-8efd06387ded837d7849adafe5bc93acb882ef90fc58b023650c875e0fd17047.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) \n values ($1, $2, $3, $4, $5, $6, $7, $8) \n ON CONFLICT (job_id) DO UPDATE SET email = $2, username = $3, is_admin = $4, is_operator = $5, folders = $6, groups = $7, workspace_id = $8", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid", - "Varchar", - "Varchar", - "Bool", - "Bool", - "JsonbArray", - "TextArray", - "Varchar" - ] - }, - "nullable": [] - }, - "hash": "8efd06387ded837d7849adafe5bc93acb882ef90fc58b023650c875e0fd17047" -} diff --git a/backend/.sqlx/query-6860deb7064e57b9e7646438145dc57cc51c7ea256058daf170a1ec8573ed102.json b/backend/.sqlx/query-927149213e0f8ae983652ef80464f646d6be80e702193f1acdd40dd6033652e4.json similarity index 64% rename from backend/.sqlx/query-6860deb7064e57b9e7646438145dc57cc51c7ea256058daf170a1ec8573ed102.json rename to backend/.sqlx/query-927149213e0f8ae983652ef80464f646d6be80e702193f1acdd40dd6033652e4.json index be5ab7a673..e4682cfedf 100644 --- a/backend/.sqlx/query-6860deb7064e57b9e7646438145dc57cc51c7ea256058daf170a1ec8573ed102.json +++ b/backend/.sqlx/query-927149213e0f8ae983652ef80464f646d6be80e702193f1acdd40dd6033652e4.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT \n path, \n script_path, \n is_flow, \n route_path, \n workspace_id, \n is_async, \n requires_auth, \n edited_by, \n email,\n static_asset_config AS \"static_asset_config: _\",\n wrap_body,\n raw_string,\n workspaced_route,\n is_static_website \n FROM \n http_trigger \n WHERE \n workspace_id = $1 AND \n http_method = $2\n ", + "query": "\n SELECT \n path, \n script_path, \n is_flow, \n route_path, \n workspace_id, \n is_async, \n authentication_method AS \"authentication_method: _\", \n edited_by, \n email,\n static_asset_config AS \"static_asset_config: _\",\n wrap_body,\n raw_string,\n workspaced_route,\n is_static_website,\n authentication_resource_path\n FROM \n http_trigger \n WHERE \n workspace_id = $1 AND \n http_method = $2\n ", "describe": { "columns": [ { @@ -35,8 +35,22 @@ }, { "ordinal": 6, - "name": "requires_auth", - "type_info": "Bool" + "name": "authentication_method: _", + "type_info": { + "Custom": { + "name": "authentication_method", + "kind": { + "Enum": [ + "none", + "windmill", + "api_key", + "basic_http", + "custom_script", + "signature" + ] + } + } + } }, { "ordinal": 7, @@ -72,6 +86,11 @@ "ordinal": 13, "name": "is_static_website", "type_info": "Bool" + }, + { + "ordinal": 14, + "name": "authentication_resource_path", + "type_info": "Varchar" } ], "parameters": { @@ -107,8 +126,9 @@ false, false, false, - false + false, + true ] }, - "hash": "6860deb7064e57b9e7646438145dc57cc51c7ea256058daf170a1ec8573ed102" + "hash": "927149213e0f8ae983652ef80464f646d6be80e702193f1acdd40dd6033652e4" } diff --git a/backend/.sqlx/query-92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633.json b/backend/.sqlx/query-92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633.json new file mode 100644 index 0000000000..14d37809d5 --- /dev/null +++ b/backend/.sqlx/query-92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET \n server_id = $1, \n last_server_ping = now(),\n error = 'Connecting...'\n WHERE \n enabled IS TRUE \n AND workspace_id = $2 \n AND path = $3 \n AND (last_server_ping IS NULL \n OR last_server_ping < now() - INTERVAL '15 seconds'\n ) \n RETURNING true\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633" +} diff --git a/backend/.sqlx/query-97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77.json b/backend/.sqlx/query-97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77.json deleted file mode 100644 index 2014d9e6e4..0000000000 --- a/backend/.sqlx/query-97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "DELETE FROM capture\n WHERE workspace_id = $1\n AND created_at <=\n (\n SELECT created_at\n FROM capture\n WHERE workspace_id = $1\n ORDER BY created_at DESC\n OFFSET $2\n LIMIT 1\n )", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77" -} diff --git a/backend/.sqlx/query-9897705b7c265333559df757a725711a40924ec551a7589a64ee96f8aa7f6a21.json b/backend/.sqlx/query-9897705b7c265333559df757a725711a40924ec551a7589a64ee96f8aa7f6a21.json deleted file mode 100644 index abad579224..0000000000 --- a/backend/.sqlx/query-9897705b7c265333559df757a725711a40924ec551a7589a64ee96f8aa7f6a21.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT set_config('session.folders_write', $1, true)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "set_config", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "9897705b7c265333559df757a725711a40924ec551a7589a64ee96f8aa7f6a21" -} diff --git a/backend/.sqlx/query-999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904.json b/backend/.sqlx/query-999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904.json new file mode 100644 index 0000000000..8748572af7 --- /dev/null +++ b/backend/.sqlx/query-999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET\n last_server_ping = NULL \n WHERE \n workspace_id = $1 \n AND path = $2 \n AND server_id IS NULL", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904" +} diff --git a/backend/.sqlx/query-9dfc48c84c52b8b027594b1c6638080f1174e06c8621245fd82ea1515e2d9a96.json b/backend/.sqlx/query-9dfc48c84c52b8b027594b1c6638080f1174e06c8621245fd82ea1515e2d9a96.json index 737090f5b8..b35ca6aa5b 100644 --- a/backend/.sqlx/query-9dfc48c84c52b8b027594b1c6638080f1174e06c8621245fd82ea1515e2d9a96.json +++ b/backend/.sqlx/query-9dfc48c84c52b8b027594b1c6638080f1174e06c8621245fd82ea1515e2d9a96.json @@ -12,7 +12,7 @@ "parameters": { "Left": [ "Varchar", - "Json", + "Jsonb", "Int4", "Text" ] diff --git a/backend/.sqlx/query-a0c20436e0506bf9e0e50bd3dcabdd35131cc374edac0a08c5492954f08c9d98.json b/backend/.sqlx/query-a0c20436e0506bf9e0e50bd3dcabdd35131cc374edac0a08c5492954f08c9d98.json new file mode 100644 index 0000000000..1724d969cf --- /dev/null +++ b/backend/.sqlx/query-a0c20436e0506bf9e0e50bd3dcabdd35131cc374edac0a08c5492954f08c9d98.json @@ -0,0 +1,222 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO schedule (\n workspace_id, path, schedule, timezone, edited_by, script_path,\n is_flow, args, enabled, email,\n on_failure, on_failure_times, on_failure_exact, on_failure_extra_args,\n on_recovery, on_recovery_times, on_recovery_extra_args,\n on_success, on_success_extra_args,\n ws_error_handler_muted, retry, summary, no_flow_overlap,\n tag, paused_until, cron_version, description\n ) VALUES (\n $1, $2, $3, $4, $5, $6,\n $7, $8, $9, $10,\n $11, $12, $13, $14,\n $15, $16, $17,\n $18, $19,\n $20, $21, $22, $23,\n $24, $25, $26, $27\n )\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "schedule", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "timezone", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "enabled", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 10, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 11, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 12, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 13, + "name": "on_failure", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "on_failure_times", + "type_info": "Int4" + }, + { + "ordinal": 15, + "name": "on_failure_exact", + "type_info": "Bool" + }, + { + "ordinal": 16, + "name": "on_failure_extra_args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 17, + "name": "on_recovery", + "type_info": "Varchar" + }, + { + "ordinal": 18, + "name": "on_recovery_times", + "type_info": "Int4" + }, + { + "ordinal": 19, + "name": "on_recovery_extra_args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 20, + "name": "on_success", + "type_info": "Varchar" + }, + { + "ordinal": 21, + "name": "on_success_extra_args: _", + "type_info": "Jsonb" + }, + { + "ordinal": 22, + "name": "ws_error_handler_muted", + "type_info": "Bool" + }, + { + "ordinal": 23, + "name": "retry", + "type_info": "Jsonb" + }, + { + "ordinal": 24, + "name": "no_flow_overlap", + "type_info": "Bool" + }, + { + "ordinal": 25, + "name": "summary", + "type_info": "Varchar" + }, + { + "ordinal": 26, + "name": "description", + "type_info": "Text" + }, + { + "ordinal": 27, + "name": "tag", + "type_info": "Varchar" + }, + { + "ordinal": 28, + "name": "paused_until", + "type_info": "Timestamptz" + }, + { + "ordinal": 29, + "name": "cron_version", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Jsonb", + "Bool", + "Varchar", + "Varchar", + "Int4", + "Bool", + "Jsonb", + "Varchar", + "Int4", + "Jsonb", + "Varchar", + "Jsonb", + "Bool", + "Jsonb", + "Varchar", + "Bool", + "Varchar", + "Timestamptz", + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true + ] + }, + "hash": "a0c20436e0506bf9e0e50bd3dcabdd35131cc374edac0a08c5492954f08c9d98" +} diff --git a/backend/.sqlx/query-0cc3618495d5d024b2a173c58a3a8bb2a9d69b7b6e7ed6b0d0064fa2ce9c2e31.json b/backend/.sqlx/query-a21a16064b51580a8f5c2505cb0c701281dbfa94e40994fdd1cadc86a26c294e.json similarity index 54% rename from backend/.sqlx/query-0cc3618495d5d024b2a173c58a3a8bb2a9d69b7b6e7ed6b0d0064fa2ce9c2e31.json rename to backend/.sqlx/query-a21a16064b51580a8f5c2505cb0c701281dbfa94e40994fdd1cadc86a26c294e.json index 79e36950f6..dc20d9d86b 100644 --- a/backend/.sqlx/query-0cc3618495d5d024b2a173c58a3a8bb2a9d69b7b6e7ed6b0d0064fa2ce9c2e31.json +++ b/backend/.sqlx/query-a21a16064b51580a8f5c2505cb0c701281dbfa94e40994fdd1cadc86a26c294e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT value\n FROM global_settings\n WHERE name = 'openai_azure_base_path'", + "query": "SELECT value\n FROM global_settings\n WHERE name = 'openai_azure_base_path'", "describe": { "columns": [ { @@ -16,5 +16,5 @@ false ] }, - "hash": "0cc3618495d5d024b2a173c58a3a8bb2a9d69b7b6e7ed6b0d0064fa2ce9c2e31" + "hash": "a21a16064b51580a8f5c2505cb0c701281dbfa94e40994fdd1cadc86a26c294e" } diff --git a/backend/.sqlx/query-a2e86f169ffbf8acee5f7c7b71db5859ac94ffbad267c9cd6c652e8ce8fc5d3c.json b/backend/.sqlx/query-a2e86f169ffbf8acee5f7c7b71db5859ac94ffbad267c9cd6c652e8ce8fc5d3c.json new file mode 100644 index 0000000000..4e0d53b0f3 --- /dev/null +++ b/backend/.sqlx/query-a2e86f169ffbf8acee5f7c7b71db5859ac94ffbad267c9cd6c652e8ce8fc5d3c.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO job_logs (logs, job_id, workspace_id) VALUES ($1, $2, $3) ON CONFLICT (job_id) DO UPDATE SET logs = concat(job_logs.logs, $1::text) RETURNING length(logs)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "length", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Uuid", + "Varchar" + ] + }, + "nullable": [ + null + ] + }, + "hash": "a2e86f169ffbf8acee5f7c7b71db5859ac94ffbad267c9cd6c652e8ce8fc5d3c" +} diff --git a/backend/.sqlx/query-a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652.json b/backend/.sqlx/query-a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652.json new file mode 100644 index 0000000000..03b05af6fb --- /dev/null +++ b/backend/.sqlx/query-a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture_config \n SET \n last_server_ping = now(), \n error = $1 \n WHERE \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'gcp' AND \n server_id = $5 AND \n last_client_ping > NOW() - INTERVAL '10 seconds' \n RETURNING 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652" +} diff --git a/backend/.sqlx/query-03ae5b1c912b13a8a7aadf50cb4984a2ea952e782fd52eb3088454690bd13dd1.json b/backend/.sqlx/query-a9db7b2f435bb82acb8c5eeb7f800b28f3256491fdaa168591adc7b4b9f3327a.json similarity index 81% rename from backend/.sqlx/query-03ae5b1c912b13a8a7aadf50cb4984a2ea952e782fd52eb3088454690bd13dd1.json rename to backend/.sqlx/query-a9db7b2f435bb82acb8c5eeb7f800b28f3256491fdaa168591adc7b4b9f3327a.json index c26b190f79..8cc09349ec 100644 --- a/backend/.sqlx/query-03ae5b1c912b13a8a7aadf50cb4984a2ea952e782fd52eb3088454690bd13dd1.json +++ b/backend/.sqlx/query-a9db7b2f435bb82acb8c5eeb7f800b28f3256491fdaa168591adc7b4b9f3327a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT content AS \"content!: String\",\n lock AS \"lock: String\", language AS \"language: Option\", envs AS \"envs: Vec\", schema AS \"schema: String\", schema_validation AS \"schema_validation: bool\", codebase LIKE '%.tar' as use_tar FROM script WHERE hash = $1 LIMIT 1", + "query": "SELECT content AS \"content!: String\",\n lock AS \"lock: String\", language AS \"language: Option\", envs AS \"envs: Vec\", schema AS \"schema: String\", schema_validation AS \"schema_validation: bool\", codebase LIKE '%.tar' as use_tar FROM script WHERE hash = $1 LIMIT 1", "describe": { "columns": [ { @@ -40,7 +40,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } @@ -82,5 +83,5 @@ null ] }, - "hash": "03ae5b1c912b13a8a7aadf50cb4984a2ea952e782fd52eb3088454690bd13dd1" + "hash": "a9db7b2f435bb82acb8c5eeb7f800b28f3256491fdaa168591adc7b4b9f3327a" } diff --git a/backend/.sqlx/query-aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f.json b/backend/.sqlx/query-aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f.json new file mode 100644 index 0000000000..9526b72f55 --- /dev/null +++ b/backend/.sqlx/query-aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f.json @@ -0,0 +1,64 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\",\n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\",\n EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS \"mqtt_used!\",\n EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS \"sqs_used!\",\n EXISTS(SELECT 1 FROM gcp_trigger WHERE workspace_id = $1) AS \"gcp_used!\"\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "websocket_used!", + "type_info": "Bool" + }, + { + "ordinal": 1, + "name": "http_routes_used!", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "kafka_used!", + "type_info": "Bool" + }, + { + "ordinal": 3, + "name": "nats_used!", + "type_info": "Bool" + }, + { + "ordinal": 4, + "name": "postgres_used!", + "type_info": "Bool" + }, + { + "ordinal": 5, + "name": "mqtt_used!", + "type_info": "Bool" + }, + { + "ordinal": 6, + "name": "sqs_used!", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "gcp_used!", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null, + null, + null, + null, + null, + null, + null, + null + ] + }, + "hash": "aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f" +} diff --git a/backend/.sqlx/query-a439552f74ed0ba305e3d9cb99ae9e5d24834082ebf2fe9fd3964fdd80b69ccb.json b/backend/.sqlx/query-aa523c363186575b4bd2537b8e2430e6938e7cc35f8c9e2d1c5459a85443cbdd.json similarity index 52% rename from backend/.sqlx/query-a439552f74ed0ba305e3d9cb99ae9e5d24834082ebf2fe9fd3964fdd80b69ccb.json rename to backend/.sqlx/query-aa523c363186575b4bd2537b8e2430e6938e7cc35f8c9e2d1c5459a85443cbdd.json index 691a6d5e31..520fb2c559 100644 --- a/backend/.sqlx/query-a439552f74ed0ba305e3d9cb99ae9e5d24834082ebf2fe9fd3964fdd80b69ccb.json +++ b/backend/.sqlx/query-aa523c363186575b4bd2537b8e2430e6938e7cc35f8c9e2d1c5459a85443cbdd.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2,\n occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, vcpus = COALESCE($7, vcpus),\n memory = COALESCE($8, memory), occupancy_rate_15s = $9, occupancy_rate_5m = $10, occupancy_rate_30m = $11 WHERE worker = $6", + "query": "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2,\n occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, vcpus = COALESCE($7, vcpus),\n memory = COALESCE($8, memory), occupancy_rate_15s = $9, occupancy_rate_5m = $10, occupancy_rate_30m = $11 WHERE worker = $6", "describe": { "columns": [], "parameters": { @@ -20,5 +20,5 @@ }, "nullable": [] }, - "hash": "a439552f74ed0ba305e3d9cb99ae9e5d24834082ebf2fe9fd3964fdd80b69ccb" + "hash": "aa523c363186575b4bd2537b8e2430e6938e7cc35f8c9e2d1c5459a85443cbdd" } diff --git a/backend/.sqlx/query-ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338.json b/backend/.sqlx/query-ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338.json index aefb084bba..47e4f47005 100644 --- a/backend/.sqlx/query-ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338.json +++ b/backend/.sqlx/query-ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338.json @@ -64,7 +64,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } diff --git a/backend/.sqlx/query-ac01e45d3335015f53f3d63fe159e631efb65c3d326b6b6ae8361a2116bff145.json b/backend/.sqlx/query-ac01e45d3335015f53f3d63fe159e631efb65c3d326b6b6ae8361a2116bff145.json deleted file mode 100644 index 929157b5d7..0000000000 --- a/backend/.sqlx/query-ac01e45d3335015f53f3d63fe159e631efb65c3d326b6b6ae8361a2116bff145.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT content FROM script WHERE path = $1 AND workspace_id = $2\n AND created_at = (SELECT max(created_at) FROM script WHERE path = $1 AND\n workspace_id = $2)\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "content", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [ - false - ] - }, - "hash": "ac01e45d3335015f53f3d63fe159e631efb65c3d326b6b6ae8361a2116bff145" -} diff --git a/backend/.sqlx/query-ad88831c9021b79c9037a925c2b53be3a93dbe2a67bdc4d4342c84f439b5eaf9.json b/backend/.sqlx/query-ad88831c9021b79c9037a925c2b53be3a93dbe2a67bdc4d4342c84f439b5eaf9.json new file mode 100644 index 0000000000..8d51b798e9 --- /dev/null +++ b/backend/.sqlx/query-ad88831c9021b79c9037a925c2b53be3a93dbe2a67bdc4d4342c84f439b5eaf9.json @@ -0,0 +1,85 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT \n j.id,\n j.kind AS \"kind: _\",\n COALESCE(s.path, f.path) AS \"script_path!\",\n COALESCE(s.hash, f.id) AS \"script_hash!: _\",\n COALESCE(jc.started_at, jq.scheduled_for, make_date(1970, 1, 1)) AS \"scheduled_for!: _\",\n args AS input,\n COALESCE(s.schema, f.schema) AS \"schema: _\"\n FROM v2_job j\n LEFT JOIN script s ON j.runnable_id = s.hash AND j.kind = 'script'\n LEFT JOIN flow_version f ON j.runnable_id = f.id AND j.runnable_path = f.path AND j.kind = 'flow'\n LEFT JOIN v2_job_completed jc ON jc.id = j.id\n LEFT JOIN v2_job_queue jq ON jq.id = j.id\n WHERE j.id = ANY($1)\n AND j.workspace_id = $2\n AND COALESCE(s.hash, f.id) IS NOT NULL\n AND COALESCE(s.path, f.path) IS NOT NULL", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "kind: _", + "type_info": { + "Custom": { + "name": "job_kind", + "kind": { + "Enum": [ + "script", + "preview", + "flow", + "dependencies", + "flowpreview", + "script_hub", + "identity", + "flowdependencies", + "http", + "graphql", + "postgresql", + "noop", + "appdependencies", + "deploymentcallback", + "singlescriptflow", + "flowscript", + "flownode", + "appscript" + ] + } + } + } + }, + { + "ordinal": 2, + "name": "script_path!", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "script_hash!: _", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "scheduled_for!: _", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "input", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "schema: _", + "type_info": "Json" + } + ], + "parameters": { + "Left": [ + "UuidArray", + "Text" + ] + }, + "nullable": [ + false, + false, + null, + null, + null, + true, + null + ] + }, + "hash": "ad88831c9021b79c9037a925c2b53be3a93dbe2a67bdc4d4342c84f439b5eaf9" +} diff --git a/backend/.sqlx/query-b186efe51e7bb1924efbd7e9b36085502a1e77e30e59c7310c78976f77a810a3.json b/backend/.sqlx/query-b186efe51e7bb1924efbd7e9b36085502a1e77e30e59c7310c78976f77a810a3.json deleted file mode 100644 index d856ab0109..0000000000 --- a/backend/.sqlx/query-b186efe51e7bb1924efbd7e9b36085502a1e77e30e59c7310c78976f77a810a3.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT ai_resource, code_completion_model, ai_models FROM workspace_settings WHERE workspace_id = $1", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "ai_resource", - "type_info": "Jsonb" - }, - { - "ordinal": 1, - "name": "code_completion_model", - "type_info": "Varchar" - }, - { - "ordinal": 2, - "name": "ai_models", - "type_info": "VarcharArray" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - true, - true, - false - ] - }, - "hash": "b186efe51e7bb1924efbd7e9b36085502a1e77e30e59c7310c78976f77a810a3" -} diff --git a/backend/.sqlx/query-62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a.json b/backend/.sqlx/query-b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d.json similarity index 51% rename from backend/.sqlx/query-62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a.json rename to backend/.sqlx/query-b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d.json index d2eab003f2..a20f4e47ad 100644 --- a/backend/.sqlx/query-62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a.json +++ b/backend/.sqlx/query-b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO capture_config\n (workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path, is_flow, trigger_kind)\n DO UPDATE SET trigger_config = $5, owner = $6, email = $7, server_id = NULL, error = NULL", + "query": "\n INSERT INTO capture_config (\n workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7\n )\n ON CONFLICT (workspace_id, path, is_flow, trigger_kind)\n DO UPDATE \n SET \n trigger_config = $5, \n owner = $6, \n email = $7, \n server_id = NULL, \n error = NULL\n ", "describe": { "columns": [], "parameters": { @@ -21,7 +21,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -33,5 +34,5 @@ }, "nullable": [] }, - "hash": "62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a" + "hash": "b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d" } diff --git a/backend/.sqlx/query-b4d48c820bf41619bffa8f62367e98369e1d93514e1618723a34bf96080d4ebc.json b/backend/.sqlx/query-b4d48c820bf41619bffa8f62367e98369e1d93514e1618723a34bf96080d4ebc.json new file mode 100644 index 0000000000..0efca7e867 --- /dev/null +++ b/backend/.sqlx/query-b4d48c820bf41619bffa8f62367e98369e1d93514e1618723a34bf96080d4ebc.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE workspace_settings\n SET git_app_installations = (\n SELECT jsonb_agg(\n CASE\n WHEN (elem->>'installation_id')::bigint = $2 THEN $1::jsonb\n ELSE elem\n END\n )\n FROM jsonb_array_elements(git_app_installations) AS elem\n )\n WHERE workspace_id = $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb", + "Int8", + "Text" + ] + }, + "nullable": [] + }, + "hash": "b4d48c820bf41619bffa8f62367e98369e1d93514e1618723a34bf96080d4ebc" +} diff --git a/backend/.sqlx/query-b61a00e6a8ca0a1d24e64fdc9223b077c957da8455ea747b0680923d8282425b.json b/backend/.sqlx/query-b61a00e6a8ca0a1d24e64fdc9223b077c957da8455ea747b0680923d8282425b.json new file mode 100644 index 0000000000..80f0549739 --- /dev/null +++ b/backend/.sqlx/query-b61a00e6a8ca0a1d24e64fdc9223b077c957da8455ea747b0680923d8282425b.json @@ -0,0 +1,73 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n j.kind AS \"kind!: JobKind\",\n j.runnable_id AS \"script_hash: _\",\n j.runnable_path AS script_path,\n COUNT(*) AS \"count!\",\n ANY_VALUE(COALESCE(f.schema, s.schema)) AS schema\n FROM v2_job j\n LEFT JOIN script s ON s.hash = j.runnable_id AND j.kind = 'script'\n LEFT JOIN flow_version f ON f.id = j.runnable_id AND f.path = j.runnable_path AND j.kind = 'flow'\n WHERE COALESCE(s.hash, f.id) IS NOT NULL\n AND COALESCE(s.path, f.path) IS NOT NULL\n AND j.workspace_id = $1 AND j.id = ANY($2)\n GROUP BY j.runnable_id, j.runnable_path, j.kind", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "kind!: JobKind", + "type_info": { + "Custom": { + "name": "job_kind", + "kind": { + "Enum": [ + "script", + "preview", + "flow", + "dependencies", + "flowpreview", + "script_hub", + "identity", + "flowdependencies", + "http", + "graphql", + "postgresql", + "noop", + "appdependencies", + "deploymentcallback", + "singlescriptflow", + "flowscript", + "flownode", + "appscript" + ] + } + } + } + }, + { + "ordinal": 1, + "name": "script_hash: _", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "count!", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "schema", + "type_info": "Json" + } + ], + "parameters": { + "Left": [ + "Text", + "UuidArray" + ] + }, + "nullable": [ + false, + true, + true, + null, + null + ] + }, + "hash": "b61a00e6a8ca0a1d24e64fdc9223b077c957da8455ea747b0680923d8282425b" +} diff --git a/backend/.sqlx/query-ba117e89b5da7ef46a9e702a2f80c624cd1b00bcab9855edb9284d8afec46ff0.json b/backend/.sqlx/query-ba117e89b5da7ef46a9e702a2f80c624cd1b00bcab9855edb9284d8afec46ff0.json new file mode 100644 index 0000000000..773dc5d24d --- /dev/null +++ b/backend/.sqlx/query-ba117e89b5da7ef46a9e702a2f80c624cd1b00bcab9855edb9284d8afec46ff0.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE workspace_settings SET ai_config = $1 WHERE workspace_id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb", + "Text" + ] + }, + "nullable": [] + }, + "hash": "ba117e89b5da7ef46a9e702a2f80c624cd1b00bcab9855edb9284d8afec46ff0" +} diff --git a/backend/.sqlx/query-c00bae0d8c9bee37cbad4de4cb02c80d00f52a3fc32bf32271ebc90f7837abda.json b/backend/.sqlx/query-c00bae0d8c9bee37cbad4de4cb02c80d00f52a3fc32bf32271ebc90f7837abda.json deleted file mode 100644 index 74aa6c4ffb..0000000000 --- a/backend/.sqlx/query-c00bae0d8c9bee37cbad4de4cb02c80d00f52a3fc32bf32271ebc90f7837abda.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE v2_job_queue\n SET canceled_by = 'timeout'\n , canceled_reason = $1\n WHERE id = $2", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Uuid" - ] - }, - "nullable": [] - }, - "hash": "c00bae0d8c9bee37cbad4de4cb02c80d00f52a3fc32bf32271ebc90f7837abda" -} diff --git a/backend/.sqlx/query-c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c.json b/backend/.sqlx/query-c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c.json new file mode 100644 index 0000000000..e65e3cb60e --- /dev/null +++ b/backend/.sqlx/query-c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c.json @@ -0,0 +1,50 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n path,\n is_flow,\n workspace_id,\n owner,\n email,\n trigger_config as \"trigger_config!: _\"\n FROM\n capture_config\n WHERE\n trigger_kind = 'gcp' AND\n last_client_ping > NOW() - INTERVAL '10 seconds' AND\n trigger_config IS NOT NULL AND\n trigger_config->>'delivery_type' IS DISTINCT FROM 'push' AND\n (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds')\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "owner", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "trigger_config!: _", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + true + ] + }, + "hash": "c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c" +} diff --git a/backend/.sqlx/query-dc165e2d3e6cfc52d92b48500b5ca7dd94b46263c58163071c0ded1c54535727.json b/backend/.sqlx/query-c12a0b0d423577afbb2772f971bffe2635785b53d31d0ceb3d72226a0c316e8a.json similarity index 56% rename from backend/.sqlx/query-dc165e2d3e6cfc52d92b48500b5ca7dd94b46263c58163071c0ded1c54535727.json rename to backend/.sqlx/query-c12a0b0d423577afbb2772f971bffe2635785b53d31d0ceb3d72226a0c316e8a.json index 3a607fbf31..ca8fd862d2 100644 --- a/backend/.sqlx/query-dc165e2d3e6cfc52d92b48500b5ca7dd94b46263c58163071c0ded1c54535727.json +++ b/backend/.sqlx/query-c12a0b0d423577afbb2772f971bffe2635785b53d31d0ceb3d72226a0c316e8a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n -- slack_team_id, \n -- slack_name, \n -- slack_command_script, \n -- CASE WHEN slack_email = 'missing@email.xyz' THEN NULL ELSE slack_email END AS slack_email,\n auto_invite_domain IS NOT NULL AS \"auto_invite_enabled!\",\n CASE WHEN auto_invite_operator IS TRUE THEN 'operator' ELSE 'developer' END AS \"auto_invite_as!\", \n CASE WHEN auto_add IS TRUE THEN 'add' ELSE 'invite' END AS \"auto_invite_mode!\", \n webhook, \n deploy_to, \n error_handler, \n ai_resource, \n ai_models,\n code_completion_model,\n error_handler_extra_args, \n error_handler_muted_on_cancel, \n large_file_storage, \n git_sync,\n default_app,\n default_scripts,\n workspace.name,\n mute_critical_alerts,\n color,\n operator_settings\n FROM workspace_settings\n LEFT JOIN workspace ON workspace.id = workspace_settings.workspace_id\n WHERE workspace_id = $1", + "query": "SELECT\n -- slack_team_id,\n -- slack_name,\n -- slack_command_script,\n -- CASE WHEN slack_email = 'missing@email.xyz' THEN NULL ELSE slack_email END AS slack_email,\n auto_invite_domain IS NOT NULL AS \"auto_invite_enabled!\",\n CASE WHEN auto_invite_operator IS TRUE THEN 'operator' ELSE 'developer' END AS \"auto_invite_as!\",\n CASE WHEN auto_add IS TRUE THEN 'add' ELSE 'invite' END AS \"auto_invite_mode!\",\n webhook,\n deploy_to,\n error_handler,\n ai_config,\n error_handler_extra_args,\n error_handler_muted_on_cancel,\n large_file_storage,\n git_sync,\n default_app,\n default_scripts,\n workspace.name,\n mute_critical_alerts,\n color,\n operator_settings\n FROM workspace_settings\n LEFT JOIN workspace ON workspace.id = workspace_settings.workspace_id\n WHERE workspace_id = $1", "describe": { "columns": [ { @@ -35,66 +35,56 @@ }, { "ordinal": 6, - "name": "ai_resource", + "name": "ai_config", "type_info": "Jsonb" }, { "ordinal": 7, - "name": "ai_models", - "type_info": "VarcharArray" - }, - { - "ordinal": 8, - "name": "code_completion_model", - "type_info": "Varchar" - }, - { - "ordinal": 9, "name": "error_handler_extra_args", "type_info": "Json" }, { - "ordinal": 10, + "ordinal": 8, "name": "error_handler_muted_on_cancel", "type_info": "Bool" }, { - "ordinal": 11, + "ordinal": 9, "name": "large_file_storage", "type_info": "Jsonb" }, { - "ordinal": 12, + "ordinal": 10, "name": "git_sync", "type_info": "Jsonb" }, { - "ordinal": 13, + "ordinal": 11, "name": "default_app", "type_info": "Varchar" }, { - "ordinal": 14, + "ordinal": 12, "name": "default_scripts", "type_info": "Jsonb" }, { - "ordinal": 15, + "ordinal": 13, "name": "name", "type_info": "Varchar" }, { - "ordinal": 16, + "ordinal": 14, "name": "mute_critical_alerts", "type_info": "Bool" }, { - "ordinal": 17, + "ordinal": 15, "name": "color", "type_info": "Varchar" }, { - "ordinal": 18, + "ordinal": 16, "name": "operator_settings", "type_info": "Jsonb" } @@ -112,8 +102,6 @@ true, true, true, - false, - true, true, false, true, @@ -126,5 +114,5 @@ true ] }, - "hash": "dc165e2d3e6cfc52d92b48500b5ca7dd94b46263c58163071c0ded1c54535727" + "hash": "c12a0b0d423577afbb2772f971bffe2635785b53d31d0ceb3d72226a0c316e8a" } diff --git a/backend/.sqlx/query-c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50.json b/backend/.sqlx/query-c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50.json new file mode 100644 index 0000000000..65cc991931 --- /dev/null +++ b/backend/.sqlx/query-c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE \n FROM \n gcp_trigger \n WHERE \n workspace_id = $1 AND \n path = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50" +} diff --git a/backend/.sqlx/query-c3025cdb6e421e1225d420e8b1efd18d1dd3bb2fac53c1f2df648b61fb7488aa.json b/backend/.sqlx/query-c3025cdb6e421e1225d420e8b1efd18d1dd3bb2fac53c1f2df648b61fb7488aa.json new file mode 100644 index 0000000000..638417aabb --- /dev/null +++ b/backend/.sqlx/query-c3025cdb6e421e1225d420e8b1efd18d1dd3bb2fac53c1f2df648b61fb7488aa.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE worker_ping SET \nping_at = now(), \njobs_executed = 1, \ncurrent_job_id = $1, \ncurrent_job_workspace_id = 'admins' \nWHERE worker = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Text" + ] + }, + "nullable": [] + }, + "hash": "c3025cdb6e421e1225d420e8b1efd18d1dd3bb2fac53c1f2df648b61fb7488aa" +} diff --git a/backend/.sqlx/query-c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a.json b/backend/.sqlx/query-c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a.json new file mode 100644 index 0000000000..5a67ebda84 --- /dev/null +++ b/backend/.sqlx/query-c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture_config\n SET \n path = $1\n WHERE \n path = $2 \n AND workspace_id = $3 \n AND is_flow = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a" +} diff --git a/backend/.sqlx/query-c4f382045e5c47986e02f1e57667e6b3cb1d60f15fed9a24e3f05b1bd60c0fc8.json b/backend/.sqlx/query-c4f382045e5c47986e02f1e57667e6b3cb1d60f15fed9a24e3f05b1bd60c0fc8.json new file mode 100644 index 0000000000..e976cd0dd9 --- /dev/null +++ b/backend/.sqlx/query-c4f382045e5c47986e02f1e57667e6b3cb1d60f15fed9a24e3f05b1bd60c0fc8.json @@ -0,0 +1,73 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT DISTINCT ON (j.runnable_path, j.kind) \n j.kind AS \"kind!: JobKind\",\n j.runnable_path AS script_path,\n NULL as \"script_hash: _\",\n -1::bigint as \"count!: _\",\n COALESCE(f.schema, s.schema) AS schema\n FROM v2_job j\n LEFT JOIN script s ON s.path = j.runnable_path AND j.kind = 'script'\n LEFT JOIN flow_version f ON f.path = j.runnable_path AND j.kind = 'flow'\n WHERE COALESCE(s.hash, f.id) IS NOT NULL\n AND j.workspace_id = $1 AND j.id = ANY($2)\n ORDER BY j.runnable_path, j.kind, COALESCE(f.created_at, s.created_at) DESC", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "kind!: JobKind", + "type_info": { + "Custom": { + "name": "job_kind", + "kind": { + "Enum": [ + "script", + "preview", + "flow", + "dependencies", + "flowpreview", + "script_hub", + "identity", + "flowdependencies", + "http", + "graphql", + "postgresql", + "noop", + "appdependencies", + "deploymentcallback", + "singlescriptflow", + "flowscript", + "flownode", + "appscript" + ] + } + } + } + }, + { + "ordinal": 1, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "script_hash: _", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "count!: _", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "schema", + "type_info": "Json" + } + ], + "parameters": { + "Left": [ + "Text", + "UuidArray" + ] + }, + "nullable": [ + false, + true, + null, + null, + null + ] + }, + "hash": "c4f382045e5c47986e02f1e57667e6b3cb1d60f15fed9a24e3f05b1bd60c0fc8" +} diff --git a/backend/.sqlx/query-f367a1c8f80dd414dcbcd949374eeb5770796f00b5b3d547163bcfdaed65d8ae.json b/backend/.sqlx/query-c53e1c7133c8ae187656eef5999509fae17fb0ba43e084327accbb5b24c3dfbd.json similarity index 53% rename from backend/.sqlx/query-f367a1c8f80dd414dcbcd949374eeb5770796f00b5b3d547163bcfdaed65d8ae.json rename to backend/.sqlx/query-c53e1c7133c8ae187656eef5999509fae17fb0ba43e084327accbb5b24c3dfbd.json index 776443782e..e343b8b863 100644 --- a/backend/.sqlx/query-f367a1c8f80dd414dcbcd949374eeb5770796f00b5b3d547163bcfdaed65d8ae.json +++ b/backend/.sqlx/query-c53e1c7133c8ae187656eef5999509fae17fb0ba43e084327accbb5b24c3dfbd.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO outstanding_wait_time(job_id, self_wait_time_ms) VALUES ($1, $2)\n ON CONFLICT (job_id) DO UPDATE SET self_wait_time_ms = EXCLUDED.self_wait_time_ms", + "query": "INSERT INTO outstanding_wait_time(job_id, self_wait_time_ms) VALUES ($1, $2)\n ON CONFLICT (job_id) DO UPDATE SET self_wait_time_ms = EXCLUDED.self_wait_time_ms", "describe": { "columns": [], "parameters": { @@ -11,5 +11,5 @@ }, "nullable": [] }, - "hash": "f367a1c8f80dd414dcbcd949374eeb5770796f00b5b3d547163bcfdaed65d8ae" + "hash": "c53e1c7133c8ae187656eef5999509fae17fb0ba43e084327accbb5b24c3dfbd" } diff --git a/backend/.sqlx/query-ca8bf3dda133556ee7051d5436a5d76ae2223d59e9f321a8b6d0c27adc09f741.json b/backend/.sqlx/query-ca8bf3dda133556ee7051d5436a5d76ae2223d59e9f321a8b6d0c27adc09f741.json deleted file mode 100644 index b7a302213a..0000000000 --- a/backend/.sqlx/query-ca8bf3dda133556ee7051d5436a5d76ae2223d59e9f321a8b6d0c27adc09f741.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid" - ] - }, - "nullable": [] - }, - "hash": "ca8bf3dda133556ee7051d5436a5d76ae2223d59e9f321a8b6d0c27adc09f741" -} diff --git a/backend/.sqlx/query-29624682d687790dd199c4af759132d79fdb2982de111cb5fd43e3d9ecd0f15e.json b/backend/.sqlx/query-cccdcb7fe7968eadfc04d8957a8e98b2f2d92a6d7f687a9dd5a70edb3d5a63e6.json similarity index 50% rename from backend/.sqlx/query-29624682d687790dd199c4af759132d79fdb2982de111cb5fd43e3d9ecd0f15e.json rename to backend/.sqlx/query-cccdcb7fe7968eadfc04d8957a8e98b2f2d92a6d7f687a9dd5a70edb3d5a63e6.json index 0967139406..412b64c480 100644 --- a/backend/.sqlx/query-29624682d687790dd199c4af759132d79fdb2982de111cb5fd43e3d9ecd0f15e.json +++ b/backend/.sqlx/query-cccdcb7fe7968eadfc04d8957a8e98b2f2d92a6d7f687a9dd5a70edb3d5a63e6.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO v2_job (id, workspace_id, raw_code, raw_lock, raw_flow, tag, parent_job,\n created_by, permissioned_as, runnable_id, runnable_path, args, kind, trigger,\n script_lang, same_worker, pre_run_error, permissioned_as_email, visible_to_owner,\n flow_innermost_root_job, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id,\n cache_ttl, priority, trigger_kind, script_entrypoint_override, preprocessed)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $21, $22, $23, $24, $25, $26,\n CASE WHEN $14::VARCHAR IS NOT NULL THEN 'schedule'::job_trigger_kind END,\n ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27)", + "query": "WITH inserted_job AS (\n INSERT INTO v2_job (id, workspace_id, raw_code, raw_lock, raw_flow, tag, parent_job,\n created_by, permissioned_as, runnable_id, runnable_path, args, kind, trigger,\n script_lang, same_worker, pre_run_error, permissioned_as_email, visible_to_owner,\n flow_innermost_root_job, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id,\n cache_ttl, priority, trigger_kind, script_entrypoint_override, preprocessed)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $21, $22, $23, $24, $25, $26,\n CASE WHEN $14::VARCHAR IS NOT NULL THEN 'schedule'::job_trigger_kind END,\n ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27)\n ),\n inserted_runtime AS (\n INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)\n ),\n inserted_job_perms AS (\n INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) \n values ($1, $32, $33, $34, $35, $36, $37, $2) \n ON CONFLICT (job_id) DO UPDATE SET email = $32, username = $33, is_admin = $34, is_operator = $35, folders = $36, groups = $37, workspace_id = $2\n )\n INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 THEN now() END, $30, $31)", "describe": { "columns": [], "parameters": { @@ -69,7 +69,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } @@ -85,10 +86,20 @@ "Varchar", "Int4", "Int2", - "Bool" + "Bool", + "Bool", + "Timestamptz", + "Varchar", + "Int2", + "Varchar", + "Varchar", + "Bool", + "Bool", + "JsonbArray", + "TextArray" ] }, "nullable": [] }, - "hash": "29624682d687790dd199c4af759132d79fdb2982de111cb5fd43e3d9ecd0f15e" + "hash": "cccdcb7fe7968eadfc04d8957a8e98b2f2d92a6d7f687a9dd5a70edb3d5a63e6" } diff --git a/backend/.sqlx/query-ccd4c7fe5fbdf1ab4bbbbd7d2a9b1ec3fc844ed286ff563f0c9a5c4778cfb718.json b/backend/.sqlx/query-ccd4c7fe5fbdf1ab4bbbbd7d2a9b1ec3fc844ed286ff563f0c9a5c4778cfb718.json new file mode 100644 index 0000000000..a457b8b2bf --- /dev/null +++ b/backend/.sqlx/query-ccd4c7fe5fbdf1ab4bbbbd7d2a9b1ec3fc844ed286ff563f0c9a5c4778cfb718.json @@ -0,0 +1,67 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT j.kind AS \"kind: _\", COALESCE(s.path, f.path) AS \"script_path!\", COALESCE(s.hash, f.id) AS \"script_hash!: _\", args\n FROM v2_job j\n LEFT JOIN script s ON j.runnable_id = s.hash AND j.kind = 'script'\n LEFT JOIN flow_version f ON j.runnable_id = f.id AND j.runnable_path = f.path AND j.kind = 'flow'\n WHERE j.id = ANY($1)\n AND j.workspace_id = $2\n AND COALESCE(s.hash, f.id) IS NOT NULL\n AND COALESCE(s.path, f.path) IS NOT NULL", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "kind: _", + "type_info": { + "Custom": { + "name": "job_kind", + "kind": { + "Enum": [ + "script", + "preview", + "flow", + "dependencies", + "flowpreview", + "script_hub", + "identity", + "flowdependencies", + "http", + "graphql", + "postgresql", + "noop", + "appdependencies", + "deploymentcallback", + "singlescriptflow", + "flowscript", + "flownode", + "appscript" + ] + } + } + } + }, + { + "ordinal": 1, + "name": "script_path!", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "script_hash!: _", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "args", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "UuidArray", + "Text" + ] + }, + "nullable": [ + false, + null, + null, + true + ] + }, + "hash": "ccd4c7fe5fbdf1ab4bbbbd7d2a9b1ec3fc844ed286ff563f0c9a5c4778cfb718" +} diff --git a/backend/.sqlx/query-d0bd4f43cb1feabe7ee9e017a0d6af22d25369a33247cec6e9f2d1a5eb851412.json b/backend/.sqlx/query-d0bd4f43cb1feabe7ee9e017a0d6af22d25369a33247cec6e9f2d1a5eb851412.json new file mode 100644 index 0000000000..4e3ee705a3 --- /dev/null +++ b/backend/.sqlx/query-d0bd4f43cb1feabe7ee9e017a0d6af22d25369a33247cec6e9f2d1a5eb851412.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE workspace_settings\n SET git_app_installations = (\n SELECT jsonb_agg(updated)\n FROM (\n -- For each element, if the account_id matches, replace it\n SELECT\n CASE\n WHEN elem->>'account_id' = ($1::jsonb)->>'account_id' THEN $1::jsonb\n ELSE elem\n END AS updated\n FROM jsonb_array_elements(git_app_installations) AS elem\n UNION ALL\n -- Append new installation if no element with the same account_id exists\n SELECT $1::jsonb\n WHERE NOT EXISTS (\n SELECT 1\n FROM jsonb_array_elements(git_app_installations) AS elem\n WHERE elem->>'account_id' = ($1::jsonb)->>'account_id'\n )\n ) sub\n )\n WHERE workspace_id = $2;\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb", + "Text" + ] + }, + "nullable": [] + }, + "hash": "d0bd4f43cb1feabe7ee9e017a0d6af22d25369a33247cec6e9f2d1a5eb851412" +} diff --git a/backend/.sqlx/query-d15f02f090b8d1a7e816fe11b2e0867540ab6bb02ac6bf82decc220dce0ab048.json b/backend/.sqlx/query-d15f02f090b8d1a7e816fe11b2e0867540ab6bb02ac6bf82decc220dce0ab048.json index 7a54e8ea3f..0a2b8c3a0c 100644 --- a/backend/.sqlx/query-d15f02f090b8d1a7e816fe11b2e0867540ab6bb02ac6bf82decc220dce0ab048.json +++ b/backend/.sqlx/query-d15f02f090b8d1a7e816fe11b2e0867540ab6bb02ac6bf82decc220dce0ab048.json @@ -41,7 +41,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } diff --git a/backend/.sqlx/query-d1dcc7fc8a1e1bc4dad263ec5163a94fca9dd95cc3b26b33611eab9d2a261141.json b/backend/.sqlx/query-d1dcc7fc8a1e1bc4dad263ec5163a94fca9dd95cc3b26b33611eab9d2a261141.json new file mode 100644 index 0000000000..4a0592701c --- /dev/null +++ b/backend/.sqlx/query-d1dcc7fc8a1e1bc4dad263ec5163a94fca9dd95cc3b26b33611eab9d2a261141.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT args as \"args: sqlx::types::Json>\"\n FROM v2_job\n WHERE id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "args: sqlx::types::Json>", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + true + ] + }, + "hash": "d1dcc7fc8a1e1bc4dad263ec5163a94fca9dd95cc3b26b33611eab9d2a261141" +} diff --git a/backend/.sqlx/query-d1fdfabd4f3bbe93cf9667e8e76bd8f537e68fabceb094fe535693fbd146eff2.json b/backend/.sqlx/query-d1fdfabd4f3bbe93cf9667e8e76bd8f537e68fabceb094fe535693fbd146eff2.json new file mode 100644 index 0000000000..5ebf571855 --- /dev/null +++ b/backend/.sqlx/query-d1fdfabd4f3bbe93cf9667e8e76bd8f537e68fabceb094fe535693fbd146eff2.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COALESCE(\n (SELECT DISTINCT ON (s.path) s.schema FROM script s WHERE s.path = jb.runnable_path AND jb.kind = 'script' ORDER BY s.path, s.created_at DESC),\n (SELECT flow_version.schema FROM flow LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] WHERE flow.path = jb.runnable_path AND jb.kind = 'flow')\n ) FROM v2_job jb\n WHERE jb.id = $1 AND jb.workspace_id = $2\n GROUP BY jb.kind, jb.runnable_path", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "coalesce", + "type_info": "Json" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "d1fdfabd4f3bbe93cf9667e8e76bd8f537e68fabceb094fe535693fbd146eff2" +} diff --git a/backend/.sqlx/query-dd06bdc09968add6a7c09f124f1f9b717990371d98e0784e96eb31cfdd17885a.json b/backend/.sqlx/query-dd06bdc09968add6a7c09f124f1f9b717990371d98e0784e96eb31cfdd17885a.json new file mode 100644 index 0000000000..0d2df00658 --- /dev/null +++ b/backend/.sqlx/query-dd06bdc09968add6a7c09f124f1f9b717990371d98e0784e96eb31cfdd17885a.json @@ -0,0 +1,56 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n http_trigger \n SET \n workspaced_route = $1,\n wrap_body = $2,\n raw_string = $3,\n authentication_resource_path = $4,\n script_path = $5, \n path = $6, \n is_flow = $7, \n http_method = $8, \n static_asset_config = $9, \n edited_by = $10, \n email = $11, \n is_async = $12, \n authentication_method = $13, \n edited_at = now(), \n is_static_website = $14\n WHERE \n workspace_id = $15 AND \n path = $16\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bool", + "Bool", + "Bool", + "Varchar", + "Varchar", + "Varchar", + "Bool", + { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + }, + "Jsonb", + "Varchar", + "Varchar", + "Bool", + { + "Custom": { + "name": "authentication_method", + "kind": { + "Enum": [ + "none", + "windmill", + "api_key", + "basic_http", + "custom_script", + "signature" + ] + } + } + }, + "Bool", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "dd06bdc09968add6a7c09f124f1f9b717990371d98e0784e96eb31cfdd17885a" +} diff --git a/backend/.sqlx/query-dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9.json b/backend/.sqlx/query-dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9.json deleted file mode 100644 index bb8d339e55..0000000000 --- a/backend/.sqlx/query-dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT EXISTS(SELECT 1 FROM log_file WHERE hostname = $1 AND log_ts = $2)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "exists", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Text", - "Timestamp" - ] - }, - "nullable": [ - null - ] - }, - "hash": "dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9" -} diff --git a/backend/.sqlx/query-df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58.json b/backend/.sqlx/query-df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58.json new file mode 100644 index 0000000000..f98dd01404 --- /dev/null +++ b/backend/.sqlx/query-df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger\n SET \n last_server_ping = now(),\n error = $1\n WHERE\n workspace_id = $2\n AND path = $3\n AND server_id = $4 \n AND enabled IS TRUE\n RETURNING 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58" +} diff --git a/backend/.sqlx/query-e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981.json b/backend/.sqlx/query-e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981.json new file mode 100644 index 0000000000..926e5c2474 --- /dev/null +++ b/backend/.sqlx/query-e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM \n capture\n WHERE \n workspace_id = $1\n AND created_at <= (\n SELECT \n created_at\n FROM \n capture\n WHERE \n workspace_id = $1\n ORDER BY \n created_at DESC\n OFFSET $2\n LIMIT 1\n )\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981" +} diff --git a/backend/.sqlx/query-cc6e21bf16d7b92764aa2b261cee94f6daf6a1eedd8a68742a2f510f0452cc32.json b/backend/.sqlx/query-e3c8219420bb859de3f1c322978c5859c924cffa61074562ac6d33106d02d7d6.json similarity index 66% rename from backend/.sqlx/query-cc6e21bf16d7b92764aa2b261cee94f6daf6a1eedd8a68742a2f510f0452cc32.json rename to backend/.sqlx/query-e3c8219420bb859de3f1c322978c5859c924cffa61074562ac6d33106d02d7d6.json index 54ae52423d..8ee4e7890e 100644 --- a/backend/.sqlx/query-cc6e21bf16d7b92764aa2b261cee94f6daf6a1eedd8a68742a2f510f0452cc32.json +++ b/backend/.sqlx/query-e3c8219420bb859de3f1c322978c5859c924cffa61074562ac6d33106d02d7d6.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT g_.workspace_id, name, summary, extra_perms, array_agg(u2g.usr) filter (where u2g.usr is not null) as members \n FROM usr u\n JOIN usr_to_group u2g ON u2g.usr = u.username AND u2g.workspace_id = u.workspace_id\n RIGHT JOIN group_ g_ ON g_.workspace_id = u.workspace_id AND g_.name = u2g.group_\n WHERE g_.workspace_id = $1 AND g_.name != 'all'\n GROUP BY g_.workspace_id, name, summary, extra_perms", + "query": "SELECT g_.workspace_id, name, summary, extra_perms, array_agg(u2g.usr) filter (where u2g.usr is not null) as members\n FROM usr u\n JOIN usr_to_group u2g ON u2g.usr = u.username AND u2g.workspace_id = u.workspace_id\n RIGHT JOIN group_ g_ ON g_.workspace_id = u.workspace_id AND g_.name = u2g.group_\n WHERE g_.workspace_id = $1 AND g_.name != 'all'\n GROUP BY g_.workspace_id, name, summary, extra_perms", "describe": { "columns": [ { @@ -42,5 +42,5 @@ null ] }, - "hash": "cc6e21bf16d7b92764aa2b261cee94f6daf6a1eedd8a68742a2f510f0452cc32" + "hash": "e3c8219420bb859de3f1c322978c5859c924cffa61074562ac6d33106d02d7d6" } diff --git a/backend/.sqlx/query-82b16e771b6e21c4587b5ebf059e312f43b3e5a48f7599133831dbd65886f5d8.json b/backend/.sqlx/query-e5f1e1e74daeabf410991e2484c1fb565f04539fc7eb141ebfaa957456016841.json similarity index 50% rename from backend/.sqlx/query-82b16e771b6e21c4587b5ebf059e312f43b3e5a48f7599133831dbd65886f5d8.json rename to backend/.sqlx/query-e5f1e1e74daeabf410991e2484c1fb565f04539fc7eb141ebfaa957456016841.json index 880e79a957..ddd216acc1 100644 --- a/backend/.sqlx/query-82b16e771b6e21c4587b5ebf059e312f43b3e5a48f7599133831dbd65886f5d8.json +++ b/backend/.sqlx/query-e5f1e1e74daeabf410991e2484c1fb565f04539fc7eb141ebfaa957456016841.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT usage.usage FROM usage \n WHERE is_workspace = true \n AND month_ = EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date)\n AND id = $1", + "query": "\n SELECT usage.usage FROM usage\n WHERE is_workspace = true\n AND month_ = EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date)\n AND id = $1", "describe": { "columns": [ { @@ -18,5 +18,5 @@ false ] }, - "hash": "82b16e771b6e21c4587b5ebf059e312f43b3e5a48f7599133831dbd65886f5d8" + "hash": "e5f1e1e74daeabf410991e2484c1fb565f04539fc7eb141ebfaa957456016841" } diff --git a/backend/.sqlx/query-e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114.json b/backend/.sqlx/query-e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114.json deleted file mode 100644 index 461721c4c2..0000000000 --- a/backend/.sqlx/query-e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE capture SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Text", - "Text", - "Bool" - ] - }, - "nullable": [] - }, - "hash": "e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114" -} diff --git a/backend/.sqlx/query-ec7836df5f9056ec70015800b7f4feaeb1b671120f5f8c98fca8c89c6587fc35.json b/backend/.sqlx/query-ec7836df5f9056ec70015800b7f4feaeb1b671120f5f8c98fca8c89c6587fc35.json index a99ef5bd04..73ac1919c1 100644 --- a/backend/.sqlx/query-ec7836df5f9056ec70015800b7f4feaeb1b671120f5f8c98fca8c89c6587fc35.json +++ b/backend/.sqlx/query-ec7836df5f9056ec70015800b7f4feaeb1b671120f5f8c98fca8c89c6587fc35.json @@ -55,7 +55,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } diff --git a/backend/.sqlx/query-ec9980f80a8bfa4b09225035e8a1f78d7d61fbf83dda9b39bb22e0f9584d221b.json b/backend/.sqlx/query-ec9980f80a8bfa4b09225035e8a1f78d7d61fbf83dda9b39bb22e0f9584d221b.json new file mode 100644 index 0000000000..d87e680abe --- /dev/null +++ b/backend/.sqlx/query-ec9980f80a8bfa4b09225035e8a1f78d7d61fbf83dda9b39bb22e0f9584d221b.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS (\n SELECT 1 FROM v2_as_completed_job\n WHERE workspace_id = $2\n AND (job_kind = 'appscript' OR job_kind = 'preview')\n AND created_by = 'anonymous'\n AND started_at > now() - interval '3 hours'\n AND script_path LIKE $3 || '/%'\n AND result @> ('{\"s3\":\"' || $1 || '\"}')::jsonb\n )", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "ec9980f80a8bfa4b09225035e8a1f78d7d61fbf83dda9b39bb22e0f9584d221b" +} diff --git a/backend/.sqlx/query-f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357.json b/backend/.sqlx/query-f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357.json new file mode 100644 index 0000000000..b20ae56e30 --- /dev/null +++ b/backend/.sqlx/query-f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357.json @@ -0,0 +1,129 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n gcp_resource_path,\n subscription_id,\n topic_id,\n workspace_id,\n delivery_type AS \"delivery_type: _\",\n delivery_config AS \"delivery_config: _\",\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM \n gcp_trigger\n WHERE \n workspace_id = $1 AND \n path = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "gcp_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "subscription_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "topic_id", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "delivery_type: _", + "type_info": { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + } + }, + { + "ordinal": 5, + "name": "delivery_config: _", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 11, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 12, + "name": "server_id", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "last_server_ping", + "type_info": "Timestamptz" + }, + { + "ordinal": 14, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 15, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 16, + "name": "enabled", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false + ] + }, + "hash": "f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357" +} diff --git a/backend/.sqlx/query-f632ca2e17a3952fc45bd40a055a9442c35453dff95140d2f252c4fe6a14c6a4.json b/backend/.sqlx/query-f632ca2e17a3952fc45bd40a055a9442c35453dff95140d2f252c4fe6a14c6a4.json deleted file mode 100644 index 5145efa595..0000000000 --- a/backend/.sqlx/query-f632ca2e17a3952fc45bd40a055a9442c35453dff95140d2f252c4fe6a14c6a4.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT EXISTS (SELECT 1 \n FROM workspace_settings \n WHERE workspace_id <> $1 \n AND slack_command_script IS NOT NULL\n AND slack_team_id IS NOT NULL \n AND slack_team_id = (SELECT slack_team_id FROM workspace_settings WHERE workspace_id = $1))\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "exists", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "f632ca2e17a3952fc45bd40a055a9442c35453dff95140d2f252c4fe6a14c6a4" -} diff --git a/backend/.sqlx/query-f955a01779f5441efc6aa9364b24c79b3cbc6413046c3b6099d19f675d8a395b.json b/backend/.sqlx/query-f955a01779f5441efc6aa9364b24c79b3cbc6413046c3b6099d19f675d8a395b.json new file mode 100644 index 0000000000..925d8c39f1 --- /dev/null +++ b/backend/.sqlx/query-f955a01779f5441efc6aa9364b24c79b3cbc6413046c3b6099d19f675d8a395b.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT EXISTS (SELECT 1\n FROM workspace_settings\n WHERE workspace_id <> $1\n AND slack_command_script IS NOT NULL\n AND slack_team_id = $2\n AND (SELECT slack_command_script IS NOT NULL FROM workspace_settings WHERE workspace_id = $1))\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "f955a01779f5441efc6aa9364b24c79b3cbc6413046c3b6099d19f675d8a395b" +} diff --git a/backend/.sqlx/query-07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5.json b/backend/.sqlx/query-f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946.json similarity index 64% rename from backend/.sqlx/query-07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5.json rename to backend/.sqlx/query-f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946.json index b905255754..a97a131baa 100644 --- a/backend/.sqlx/query-07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5.json +++ b/backend/.sqlx/query-f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO capture (workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by)\n VALUES ($1, $2, $3, $4, $5, $6, $7)", + "query": "\n INSERT INTO \n capture (\n workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7\n )\n ", "describe": { "columns": [], "parameters": { @@ -21,7 +21,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -33,5 +34,5 @@ }, "nullable": [] }, - "hash": "07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5" + "hash": "f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946" } diff --git a/backend/.sqlx/query-fa59674af1d1a4ceb696fc883005ef114772f7d2ee0f60cb1358cdb7f0b5cd0c.json b/backend/.sqlx/query-fa59674af1d1a4ceb696fc883005ef114772f7d2ee0f60cb1358cdb7f0b5cd0c.json deleted file mode 100644 index 917a0910cc..0000000000 --- a/backend/.sqlx/query-fa59674af1d1a4ceb696fc883005ef114772f7d2ee0f60cb1358cdb7f0b5cd0c.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT EXISTS (SELECT 1 \n FROM workspace_settings \n WHERE workspace_id <> $1 \n AND slack_command_script IS NOT NULL\n AND slack_team_id = $2\n AND (SELECT slack_command_script IS NOT NULL FROM workspace_settings WHERE workspace_id = $1))\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "exists", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "fa59674af1d1a4ceb696fc883005ef114772f7d2ee0f60cb1358cdb7f0b5cd0c" -} diff --git a/backend/.sqlx/query-faf2c77242e0ab39b33886edf3b742531bf1351d0be1c3631bde0adfe375497a.json b/backend/.sqlx/query-faf2c77242e0ab39b33886edf3b742531bf1351d0be1c3631bde0adfe375497a.json new file mode 100644 index 0000000000..ea798bab76 --- /dev/null +++ b/backend/.sqlx/query-faf2c77242e0ab39b33886edf3b742531bf1351d0be1c3631bde0adfe375497a.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT tag FROM v2_job WHERE id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "tag", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + false + ] + }, + "hash": "faf2c77242e0ab39b33886edf3b742531bf1351d0be1c3631bde0adfe375497a" +} diff --git a/backend/.sqlx/query-fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5.json b/backend/.sqlx/query-fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5.json new file mode 100644 index 0000000000..d47bb3fd68 --- /dev/null +++ b/backend/.sqlx/query-fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET \n enabled = FALSE, \n error = $1, \n server_id = NULL, \n last_server_ping = NULL \n WHERE \n workspace_id = $2 AND \n path = $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5" +} diff --git a/backend/.sqlx/query-fd724083c4ef6ec0f1cede5813c89b3abe9d04b86ad50c0f62903a1a79479a60.json b/backend/.sqlx/query-fd724083c4ef6ec0f1cede5813c89b3abe9d04b86ad50c0f62903a1a79479a60.json deleted file mode 100644 index a24ed36971..0000000000 --- a/backend/.sqlx/query-fd724083c4ef6ec0f1cede5813c89b3abe9d04b86ad50c0f62903a1a79479a60.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE \n http_trigger \n SET \n route_path = $1, \n route_path_key = $2, \n workspaced_route = $3, \n wrap_body = $4,\n raw_string = $5,\n script_path = $6, \n path = $7, \n is_flow = $8, \n http_method = $9, \n static_asset_config = $10, \n edited_by = $11, \n email = $12, \n is_async = $13, \n requires_auth = $14, \n edited_at = now(), \n is_static_website = $15\n WHERE \n workspace_id = $16 AND \n path = $17\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Varchar", - "Bool", - "Bool", - "Bool", - "Varchar", - "Varchar", - "Bool", - { - "Custom": { - "name": "http_method", - "kind": { - "Enum": [ - "get", - "post", - "put", - "delete", - "patch" - ] - } - } - }, - "Jsonb", - "Varchar", - "Varchar", - "Bool", - "Bool", - "Bool", - "Text", - "Text" - ] - }, - "nullable": [] - }, - "hash": "fd724083c4ef6ec0f1cede5813c89b3abe9d04b86ad50c0f62903a1a79479a60" -} diff --git a/backend/.sqlx/query-fe7221651a982861dede4116bc71fe2dce615ff76a53f72cb5386dc17e4e07aa.json b/backend/.sqlx/query-fe7221651a982861dede4116bc71fe2dce615ff76a53f72cb5386dc17e4e07aa.json new file mode 100644 index 0000000000..1ca60067d0 --- /dev/null +++ b/backend/.sqlx/query-fe7221651a982861dede4116bc71fe2dce615ff76a53f72cb5386dc17e4e07aa.json @@ -0,0 +1,21 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) \n SELECT unnest($1::uuid[]), $2, $3, $4, $5, $6, $7, $8", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "UuidArray", + "Varchar", + "Varchar", + "Bool", + "Bool", + "JsonbArray", + "TextArray", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "fe7221651a982861dede4116bc71fe2dce615ff76a53f72cb5386dc17e4e07aa" +} diff --git a/backend/.sqlx/query-ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238.json b/backend/.sqlx/query-ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238.json index 95fca28ce0..c7644fa79a 100644 --- a/backend/.sqlx/query-ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238.json +++ b/backend/.sqlx/query-ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238.json @@ -64,7 +64,8 @@ "ansible", "csharp", "oracledb", - "nu" + "nu", + "java" ] } } diff --git a/backend/.vscode/settings.json b/backend/.vscode/settings.json index 6ebd36cf07..ab8340f5c8 100644 --- a/backend/.vscode/settings.json +++ b/backend/.vscode/settings.json @@ -11,5 +11,5 @@ "remote.autoForwardPorts": true, "conventionalCommits.scopes": [ "restructring triggers, decoding trigger message on work" - ] + ], } diff --git a/backend/Cargo.lock b/backend/Cargo.lock index cfff91f203..0f9558966f 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -678,31 +678,6 @@ dependencies = [ "syn 2.0.100", ] -[[package]] -name = "async-stripe" -version = "0.39.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58d670cf4d47a1b8ffef54286a5625382e360a34ee76902fd93ad8c7032a0c30" -dependencies = [ - "chrono", - "futures-util", - "hex", - "hmac", - "http-types", - "hyper 0.14.32", - "hyper-tls 0.5.0", - "serde", - "serde_json", - "serde_path_to_error", - "serde_qs 0.10.1", - "sha2 0.10.8", - "smart-default", - "smol_str", - "thiserror 1.0.69", - "tokio", - "uuid 0.8.2", -] - [[package]] name = "async-trait" version = "0.1.88" @@ -723,7 +698,7 @@ dependencies = [ "async-compression", "chrono", "crc32fast", - "futures-lite 2.6.0", + "futures-lite", "pin-project", "thiserror 1.0.69", "tokio", @@ -766,9 +741,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a84fe2c5e9965fba0fbc2001db252f1d57527d82a905cca85127df227bca748" +checksum = "8c39646d1a6b51240a1a23bb57ea4eebede7e16fbc237fdc876980233dcecb4f" dependencies = [ "aws-credential-types", "aws-runtime", @@ -783,7 +758,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.3.0", + "fastrand", "hex", "http 1.3.1", "ring 0.17.14", @@ -808,9 +783,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.12.6" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dabb68eb3a7aa08b46fddfd59a3d55c978243557a90ab804769f7e20e67d2b01" +checksum = "19b756939cb2f8dc900aa6dcd505e6e2428e9cae7ff7b028c49e3946efa70878" dependencies = [ "aws-lc-sys", "zeroize", @@ -818,9 +793,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77926887776171ced7d662120a75998e444d3750c951abfe07f90da130514b1f" +checksum = "b9f7720b74ed28ca77f90769a71fd8c637a0137f6fae4ae947e1050229cff57f" dependencies = [ "bindgen 0.69.5", "cc", @@ -844,21 +819,21 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.3.0", + "fastrand", "http 0.2.12", "http-body 0.4.6", "once_cell", "percent-encoding", "pin-project-lite", "tracing", - "uuid 1.16.0", + "uuid", ] [[package]] name = "aws-sdk-sqs" -version = "1.62.0" +version = "1.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194d4234d8042159069b905760af670eefaa80848db097399b50110ab4746d04" +checksum = "514d007ac4d5b156b408d8dd623a57b37ae77425810e0fedcffab57b0dabaded" dependencies = [ "aws-credential-types", "aws-runtime", @@ -870,6 +845,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", + "fastrand", "http 0.2.12", "once_cell", "regex-lite", @@ -878,9 +854,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.62.0" +version = "1.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d5330ad4e8a1ff49e9f26b738611caa72b105c41d41733801d1a36e8f9de936" +checksum = "02d4bdb0e5f80f0689e61c77ab678b2b9304af329616af38aef5b6b967b8e736" dependencies = [ "aws-credential-types", "aws-runtime", @@ -892,6 +868,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", + "fastrand", "http 0.2.12", "once_cell", "regex-lite", @@ -900,9 +877,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.63.0" +version = "1.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7956b1a85d49082347a7d17daa2e32df191f3e23c03d47294b99f95413026a78" +checksum = "acbbb3ce8da257aedbccdcb1aadafbbb6a5fe9adf445db0e1ea897bdc7e22d08" dependencies = [ "aws-credential-types", "aws-runtime", @@ -914,6 +891,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", + "fastrand", "http 0.2.12", "once_cell", "regex-lite", @@ -922,9 +900,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.63.0" +version = "1.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065c533fbe6f84962af33fcf02b0350b7c1f79285baab5924615d2be3b232855" +checksum = "96a78a8f50a1630db757b60f679c8226a8a70ee2ab5f5e6e51dc67f6c61c7cfd" dependencies = [ "aws-credential-types", "aws-runtime", @@ -937,6 +915,7 @@ dependencies = [ "aws-smithy-types", "aws-smithy-xml", "aws-types", + "fastrand", "http 0.2.12", "once_cell", "regex-lite", @@ -1000,9 +979,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0497ef5d53065b7cd6a35e9c1654bd1fefeae5c52900d91d1b188b0af0f29324" +checksum = "8aff1159006441d02e57204bf57a1b890ba68bedb6904ffd2873c1c4c11c546b" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -1035,6 +1014,16 @@ dependencies = [ "aws-smithy-types", ] +[[package]] +name = "aws-smithy-observability" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445d065e76bc1ef54963db400319f1dd3ebb3e0a74af20f7f7630625b0cc7cc0" +dependencies = [ + "aws-smithy-runtime-api", + "once_cell", +] + [[package]] name = "aws-smithy-query" version = "0.60.7" @@ -1047,17 +1036,18 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6328865e36c6fd970094ead6b05efd047d3a80ec5fc3be5e743910da9f2ebf8" +checksum = "0152749e17ce4d1b47c7747bdfec09dac1ccafdcbc741ebf9daa2a373356730f" dependencies = [ "aws-smithy-async", "aws-smithy-http", "aws-smithy-http-client", + "aws-smithy-observability", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", - "fastrand 2.3.0", + "fastrand", "http 0.2.12", "http 1.3.1", "http-body 0.4.6", @@ -1203,7 +1193,7 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "970d91570c01a8a5959b36ad7dd1c30642df24b6b3068710066f6809f7033bb7" dependencies = [ - "fastrand 2.3.0", + "fastrand", "gloo-timers", "tokio", ] @@ -1289,9 +1279,9 @@ dependencies = [ [[package]] name = "bigdecimal" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f31f3af01c5c65a07985c804d3366560e6fa7883d640a122819b14ec327482c" +checksum = "1a22f228ab7a1b23027ccc6c350b72868017af7ea8356fbdf19f8d991c690013" dependencies = [ "autocfg", "libm", @@ -1429,9 +1419,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17679a8d69b6d7fd9cd9801a536cec9fa5e5970b69f9d4747f70b39b031f5e7" +checksum = "34a796731680be7931955498a16a10b2270c7762963d5d570fdbfe02dcbf314f" dependencies = [ "arrayref", "arrayvec", @@ -1536,9 +1526,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.6" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b74d67a0fc0af8e9823b79fd1c43a0900e5a8f0e0f4cc9210796bf3a820126" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" dependencies = [ "borsh-derive", "cfg_aliases 0.2.1", @@ -1546,9 +1536,9 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.6" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d37ed1b2c9b78421218a0b4f6d8349132d6ec2cfeba1cfb0118b0a8e268df9e" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" dependencies = [ "once_cell", "proc-macro-crate", @@ -1671,9 +1661,9 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ff22c2722516255d1823ce3cc4bc0b154dbc9364be5c905d6baa6eccbbc8774" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", @@ -1707,9 +1697,9 @@ dependencies = [ [[package]] name = "bytesize" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2c12f985c78475a6b8d629afd0c360260ef34cfef52efccdcfd31972f81c2e" +checksum = "2e93abca9e28e0a1b9877922aacb20576e05d4679ffa78c3d6dc22a26a216659" [[package]] name = "bzip2" @@ -1843,9 +1833,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.16" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "jobserver", "libc", @@ -1923,12 +1913,12 @@ dependencies = [ [[package]] name = "chrono-tz" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6ac4f2c0bf0f44e9161aec9675e1050aa4a530663c4a9e37e108fa948bca9f" +checksum = "efdce149c370f133a071ca8ef6ea340b7b88748ab0810097a9e2976eaa34b4f3" dependencies = [ "chrono", - "chrono-tz-build 0.4.0", + "chrono-tz-build 0.4.1", "phf", ] @@ -1945,9 +1935,9 @@ dependencies = [ [[package]] name = "chrono-tz-build" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" +checksum = "8f10f8c9340e31fc120ff885fcdb54a0b48e474bbd77cab557f0c30a3e569402" dependencies = [ "parse-zoneinfo", "phf_codegen", @@ -1985,9 +1975,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.32" +version = "4.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83" +checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" dependencies = [ "clap_builder", "clap_derive", @@ -1995,9 +1985,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.32" +version = "4.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8" +checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" dependencies = [ "anstream", "anstyle", @@ -2500,12 +2490,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] @@ -2538,9 +2528,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", @@ -2574,11 +2564,11 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core 0.20.10", + "darling_core 0.20.11", "quote", "syn 2.0.100", ] @@ -2593,7 +2583,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", ] [[package]] @@ -2647,7 +2637,7 @@ dependencies = [ "log", "num_cpus", "object_store", - "parking_lot", + "parking_lot 0.12.3", "parquet", "paste", "pin-project-lite", @@ -2657,7 +2647,7 @@ dependencies = [ "tokio", "tokio-util", "url", - "uuid 1.16.0", + "uuid", "xz2", "zstd", ] @@ -2708,7 +2698,7 @@ dependencies = [ "hashbrown 0.14.5", "log", "object_store", - "parking_lot", + "parking_lot 0.12.3", "rand 0.8.5", "tempfile", "url", @@ -2757,7 +2747,7 @@ dependencies = [ "regex", "sha2 0.10.8", "unicode-segmentation", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -2888,7 +2878,7 @@ dependencies = [ "itertools 0.12.1", "log", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "rand 0.8.5", "tokio", @@ -2924,7 +2914,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" dependencies = [ "serde", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -2980,7 +2970,7 @@ dependencies = [ "deno_error", "thiserror 2.0.12", "tokio", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -3019,7 +3009,7 @@ dependencies = [ "indexmap 2.8.0", "log", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "serde", "serde_json", "sha2 0.10.8", @@ -3101,7 +3091,7 @@ dependencies = [ "indexmap 2.8.0", "libc", "memoffset", - "parking_lot", + "parking_lot 0.12.3", "percent-encoding", "pin-project", "serde", @@ -3175,7 +3165,7 @@ dependencies = [ "spki", "thiserror 2.0.12", "tokio", - "uuid 1.16.0", + "uuid", "x25519-dalek", ] @@ -3346,11 +3336,11 @@ dependencies = [ "log", "once_cell", "os_pipe", - "parking_lot", + "parking_lot 0.12.3", "pin-project", "rand 0.8.5", "tokio", - "uuid 1.16.0", + "uuid", "winapi", "windows-sys 0.59.0", ] @@ -3726,7 +3716,7 @@ dependencies = [ "log", "node_resolver", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "sys_traits", "thiserror 2.0.12", "url", @@ -3797,7 +3787,7 @@ dependencies = [ "tokio", "tokio-metrics", "twox-hash 1.6.3", - "uuid 1.16.0", + "uuid", "which 6.0.3", "winapi", "windows-sys 0.59.0", @@ -3883,7 +3873,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d774fd83f26b24f0805a6ab8b26834a0d06ceac0db517b769b1e4633c96a2057" dependencies = [ "futures", - "parking_lot", + "parking_lot 0.12.3", "tokio", ] @@ -3917,7 +3907,7 @@ dependencies = [ "serde", "thiserror 2.0.12", "tokio", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -4006,7 +3996,7 @@ dependencies = [ "num-bigint", "prost", "serde", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -4032,7 +4022,7 @@ dependencies = [ "tokio", "tokio-util", "url", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -4056,7 +4046,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tokio-stream", - "uuid 1.16.0", + "uuid", "v8_valueserializer", ] @@ -4099,9 +4089,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" dependencies = [ "powerfmt", "serde", @@ -4684,15 +4674,6 @@ dependencies = [ "serde", ] -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.3.0" @@ -4726,7 +4707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix 1.0.3", + "rustix 1.0.5", "windows-sys 0.59.0", ] @@ -4797,9 +4778,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "libz-sys", @@ -4823,6 +4804,7 @@ checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", + "nanorand", "spin 0.9.8", ] @@ -5008,7 +4990,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -5017,28 +4999,13 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - [[package]] name = "futures-lite" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" dependencies = [ - "fastrand 2.3.0", + "fastrand", "futures-core", "futures-io", "parking", @@ -5272,17 +5239,6 @@ dependencies = [ "unicode-width 0.1.14", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -5409,6 +5365,94 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "google-cloud-auth" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57a13fbacc5e9c41ded3ad8d0373175a6b7a6ad430d99e89d314ac121b7ab06" +dependencies = [ + "async-trait", + "base64 0.21.7", + "google-cloud-metadata", + "google-cloud-token", + "home", + "jsonwebtoken 9.3.1", + "reqwest 0.12.15", + "serde", + "serde_json", + "thiserror 1.0.69", + "time", + "tokio", + "tracing", + "urlencoding", +] + +[[package]] +name = "google-cloud-gax" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de13e62d7e0ffc3eb40a0113ddf753cf6ec741be739164442b08893db4f9bfca" +dependencies = [ + "google-cloud-token", + "http 1.3.1", + "thiserror 1.0.69", + "tokio", + "tokio-retry2", + "tonic", + "tower 0.4.13", + "tracing", +] + +[[package]] +name = "google-cloud-googleapis" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "886aa8ec755382a1fdf4651f6e6ec01f2f3bf49f2cb0f068b9a74cafd574a715" +dependencies = [ + "prost", + "prost-types", + "tonic", +] + +[[package]] +name = "google-cloud-metadata" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d901aeb453fd80e51d64df4ee005014f6cf39f2d736dd64f7239c132d9d39a6a" +dependencies = [ + "reqwest 0.12.15", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "google-cloud-pubsub" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebc6e7327e49a66ffb40508c673b7643191bd6b509530193bda97f09272cdcf" +dependencies = [ + "async-channel", + "async-stream", + "google-cloud-auth", + "google-cloud-gax", + "google-cloud-googleapis", + "google-cloud-token", + "prost-types", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "google-cloud-token" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c12ba8b21d128a2ce8585955246977fbce4415f680ebf9199b6f9d6d725f" +dependencies = [ + "async-trait", +] + [[package]] name = "gosyn" version = "0.2.9" @@ -5700,7 +5744,7 @@ dependencies = [ "ipconfig", "moka", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "rand 0.9.0", "resolv-conf", "serde", @@ -5835,27 +5879,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-types" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" -dependencies = [ - "anyhow", - "async-channel", - "base64 0.13.1", - "futures-lite 1.13.0", - "http 0.2.12", - "infer", - "pin-project-lite", - "rand 0.7.3", - "serde", - "serde_json", - "serde_qs 0.8.5", - "serde_urlencoded", - "url", -] - [[package]] name = "httparse" version = "1.10.1" @@ -6013,9 +6036,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" dependencies = [ "bytes", "futures-channel", @@ -6023,6 +6046,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "hyper 1.6.0", + "libc", "pin-project-lite", "socket2", "tokio", @@ -6047,16 +6071,17 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core 0.61.0", ] [[package]] @@ -6109,9 +6134,9 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" @@ -6133,9 +6158,9 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" @@ -6154,9 +6179,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" @@ -6300,12 +6325,6 @@ dependencies = [ "web-time", ] -[[package]] -name = "infer" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" - [[package]] name = "inotify" version = "0.9.6" @@ -6473,10 +6492,11 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.2", "libc", ] @@ -6513,6 +6533,21 @@ dependencies = [ "simple_asn1", ] +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64 0.22.1", + "js-sys", + "pem 3.0.5", + "ring 0.17.14", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "junction" version = "1.2.0" @@ -6870,9 +6905,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "loki-api" @@ -7316,13 +7351,13 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "loom", - "parking_lot", + "parking_lot 0.12.3", "portable-atomic", "rustc_version 0.4.1", "smallvec", "tagptr", "thiserror 1.0.69", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -7387,7 +7422,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb6d9ff4094f6d58d3f892fc558e60048476213dd17dcf904b62202e9029da6" dependencies = [ - "darling 0.20.10", + "darling 0.20.11", "heck 0.5.0", "num-bigint", "proc-macro-crate", @@ -7459,7 +7494,7 @@ dependencies = [ "sha2 0.10.8", "subprocess", "thiserror 1.0.69", - "uuid 1.16.0", + "uuid", "zstd", ] @@ -7485,6 +7520,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom 0.2.15", +] + [[package]] name = "napi_sym" version = "0.120.0" @@ -8019,7 +8063,7 @@ dependencies = [ "hyper 1.6.0", "itertools 0.13.0", "md-5 0.10.6", - "parking_lot", + "parking_lot 0.12.3", "percent-encoding", "quick-xml 0.36.2", "rand 0.8.5", @@ -8060,9 +8104,9 @@ checksum = "80adb31078122c880307e9cdfd4e3361e6545c319f9b9dcafcb03acd3b51a575" [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oneshot" @@ -8435,6 +8479,17 @@ 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.3" @@ -8442,7 +8497,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[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", ] [[package]] @@ -8858,7 +8927,7 @@ dependencies = [ "postgres-protocol 0.6.8", "serde", "serde_json", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -8873,7 +8942,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.23", + "zerocopy 0.8.24", ] [[package]] @@ -9035,16 +9104,16 @@ dependencies = [ [[package]] name = "prometheus" -version = "0.13.4" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" +checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" dependencies = [ "cfg-if", "fnv", "lazy_static", "memchr", - "parking_lot", - "thiserror 1.0.69", + "parking_lot 0.12.3", + "thiserror 2.0.12", ] [[package]] @@ -9197,7 +9266,7 @@ dependencies = [ "ahash 0.8.11", "equivalent", "hashbrown 0.15.2", - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -9242,9 +9311,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" +checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" dependencies = [ "cfg_aliases 0.2.1", "libc", @@ -9285,19 +9354,6 @@ dependencies = [ "nibble_vec", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -9317,17 +9373,7 @@ checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy 0.8.23", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "zerocopy 0.8.24", ] [[package]] @@ -9350,15 +9396,6 @@ dependencies = [ "rand_core 0.9.3", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.4" @@ -9387,15 +9424,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "range-alloc" version = "0.1.4" @@ -9486,6 +9514,15 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" +[[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", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -9695,6 +9732,43 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "reqwest-middleware" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e8975513bd9a7a43aad01030e79b3498e05db14e9d945df6483e8cf9b8c4c4" +dependencies = [ + "anyhow", + "async-trait", + "http 1.3.1", + "reqwest 0.12.15", + "serde", + "thiserror 1.0.69", + "tower-service", +] + +[[package]] +name = "reqwest-retry" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c73e4195a6bfbcb174b790d9b3407ab90646976c55de58a6515da25d851178" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "getrandom 0.2.15", + "http 1.3.1", + "hyper 1.6.0", + "parking_lot 0.11.2", + "reqwest 0.12.15", + "reqwest-middleware", + "retry-policies", + "thiserror 1.0.69", + "tokio", + "tracing", + "wasm-timer", +] + [[package]] name = "resolv-conf" version = "0.7.1" @@ -9704,6 +9778,15 @@ dependencies = [ "hostname", ] +[[package]] +name = "retry-policies" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5875471e6cab2871bc150ecb8c727db5113c9338cc3354dc5ee3425b6aa40a1c" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -9773,7 +9856,7 @@ dependencies = [ "rkyv_derive", "seahash", "tinyvec", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -9900,9 +9983,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.37.0" +version = "1.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c24af6e7ac43c88a8a458d1139d0246fdce2f6cd2f1ac6cb51eb88b29c978af" +checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" dependencies = [ "arrayvec", "borsh", @@ -9975,9 +10058,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags 2.9.0", "errno", @@ -10023,7 +10106,7 @@ dependencies = [ "once_cell", "ring 0.17.14", "rustls-pki-types", - "rustls-webpki 0.103.0", + "rustls-webpki 0.103.1", "subtle", "zeroize", ] @@ -10127,9 +10210,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.0" +version = "0.103.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa4eeac2588ffff23e9d7a7e9b3f971c5fb5b7ebc9452745e0c232c64f83b2f" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" dependencies = [ "aws-lc-rs", "ring 0.17.14", @@ -10287,7 +10370,7 @@ dependencies = [ "serde", "thiserror 1.0.69", "url", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -10570,28 +10653,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_qs" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" -dependencies = [ - "percent-encoding", - "serde", - "thiserror 1.0.69", -] - -[[package]] -name = "serde_qs" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cac3f1e2ca2fe333923a1ae72caca910b98ed0630bb35ef6f8c8517d6e81afa" -dependencies = [ - "percent-encoding", - "serde", - "thiserror 1.0.69", -] - [[package]] name = "serde_repr" version = "0.1.20" @@ -10662,7 +10723,7 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ - "darling 0.20.10", + "darling 0.20.11", "proc-macro2", "quote", "syn 2.0.100", @@ -10893,17 +10954,6 @@ dependencies = [ "serde", ] -[[package]] -name = "smart-default" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "smartstring" version = "1.0.1" @@ -10915,15 +10965,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "smol_str" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9" -dependencies = [ - "serde", -] - [[package]] name = "smtp-proto" version = "0.1.6" @@ -10960,9 +11001,9 @@ checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", @@ -11137,7 +11178,7 @@ dependencies = [ "tokio-stream", "tracing", "url", - "uuid 1.16.0", + "uuid", "webpki-roots", ] @@ -11221,7 +11262,7 @@ dependencies = [ "stringprep", "thiserror 2.0.12", "tracing", - "uuid 1.16.0", + "uuid", "whoami", ] @@ -11262,7 +11303,7 @@ dependencies = [ "stringprep", "thiserror 2.0.12", "tracing", - "uuid 1.16.0", + "uuid", "whoami", ] @@ -11288,7 +11329,7 @@ dependencies = [ "sqlx-core", "tracing", "url", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -12016,7 +12057,7 @@ dependencies = [ "tempfile", "thiserror 1.0.69", "time", - "uuid 1.16.0", + "uuid", "winapi", ] @@ -12133,10 +12174,10 @@ version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "fastrand 2.3.0", + "fastrand", "getrandom 0.3.2", "once_cell", - "rustix 1.0.3", + "rustix 1.0.5", "windows-sys 0.59.0", ] @@ -12155,7 +12196,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" dependencies = [ - "rustix 1.0.3", + "rustix 1.0.5", "windows-sys 0.59.0", ] @@ -12265,7 +12306,7 @@ dependencies = [ "tokio-rustls 0.24.1", "tokio-util", "tracing", - "uuid 1.16.0", + "uuid", ] [[package]] @@ -12312,9 +12353,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.40" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -12333,9 +12374,9 @@ checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.21" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -12433,7 +12474,7 @@ dependencies = [ "bytes", "libc", "mio 1.0.3", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", @@ -12497,7 +12538,7 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot", + "parking_lot 0.12.3", "percent-encoding", "phf", "pin-project-lite", @@ -12523,7 +12564,7 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot", + "parking_lot 0.12.3", "percent-encoding", "phf", "pin-project-lite", @@ -12536,6 +12577,16 @@ dependencies = [ "whoami", ] +[[package]] +name = "tokio-retry2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1264d076dd34560544a2799e40e457bd07c43d30f4a845686b031bcd8455c84f" +dependencies = [ + "pin-project", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -12713,6 +12764,7 @@ dependencies = [ "axum", "base64 0.22.1", "bytes", + "flate2", "h2 0.4.8", "http 1.3.1", "http-body 1.0.1", @@ -12733,6 +12785,7 @@ dependencies = [ "tower-layer", "tower-service", "tracing", + "webpki-roots", ] [[package]] @@ -12782,7 +12835,7 @@ dependencies = [ "cookie 0.18.1", "futures-util", "http 1.3.1", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "tower-layer", "tower-service", @@ -12979,6 +13032,16 @@ dependencies = [ "tree-sitter-language", ] +[[package]] +name = "tree-sitter-java" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa6cbcdc8c679b214e616fd3300da67da0e492e066df01bcf5a5921a71e90d6" +dependencies = [ + "cc", + "tree-sitter-language", +] + [[package]] name = "tree-sitter-language" version = "0.1.5" @@ -13097,7 +13160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe" dependencies = [ "rand 0.9.0", - "uuid 1.16.0", + "uuid", "web-time", ] @@ -13384,15 +13447,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.15", -] - [[package]] name = "uuid" version = "1.16.0" @@ -13480,12 +13534,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "walkdir" version = "2.5.0" @@ -13505,12 +13553,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -13640,6 +13682,21 @@ 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" @@ -13713,7 +13770,7 @@ dependencies = [ "log", "naga", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "profiling", "raw-window-handle", "ron", @@ -13755,7 +13812,7 @@ dependencies = [ "ndk-sys", "objc", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "profiling", "range-alloc", "raw-window-handle", @@ -13806,9 +13863,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" dependencies = [ "redox_syscall 0.5.10", "wasite", @@ -13854,12 +13911,13 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "axum", "base64 0.22.1", "chrono", + "constant_time_eq", "deno_core", "dotenv", "futures", @@ -13876,15 +13934,17 @@ dependencies = [ "rustls 0.23.25", "serde", "serde_json", + "sha1", "sha2 0.10.8", "sqlx", "tikv-jemalloc-ctl", "tikv-jemalloc-sys", "tikv-jemallocator", "tokio", + "tokio-stream", "tracing", "url", - "uuid 1.16.0", + "uuid", "v8", "windmill-api", "windmill-api-client", @@ -13898,7 +13958,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "argon2", @@ -13906,7 +13966,6 @@ dependencies = [ "async-oauth2", "async-recursion", "async-stream", - "async-stripe", "async_zip", "aws-config", "aws-sdk-sqs", @@ -13919,13 +13978,18 @@ dependencies = [ "candle-nn", "candle-transformers", "chrono", - "chrono-tz 0.10.1", + "chrono-tz 0.10.3", "const_format", + "constant_time_eq", "cookie 0.17.0", "cron", "datafusion", + "deno_core", + "deno_error", "futures", "git-version", + "google-cloud-googleapis", + "google-cloud-pubsub", "half", "hex", "hf-hub", @@ -13933,7 +13997,7 @@ dependencies = [ "http 1.3.1", "hyper 1.6.0", "itertools 0.14.0", - "jsonwebtoken", + "jsonwebtoken 8.3.0", "lazy_static", "magic-crypt", "mail-parser", @@ -13961,6 +14025,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sha1", "sha2 0.10.8", "sql-builder", "sqlx", @@ -13972,9 +14037,11 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-postgres 0.7.11", + "tokio-stream", "tokio-tar", "tokio-tungstenite", "tokio-util", + "tonic", "tower 0.5.2", "tower-cookies", "tower-http", @@ -13983,20 +14050,22 @@ dependencies = [ "ulid", "url", "urlencoding", - "uuid 1.16.0", + "uuid", "windmill-audit", "windmill-common", "windmill-git-sync", "windmill-indexer", "windmill-parser", "windmill-parser-py", + "windmill-parser-py-imports", "windmill-parser-ts", "windmill-queue", + "windmill-worker", ] [[package]] name = "windmill-api-client" -version = "1.478.1" +version = "1.481.0" dependencies = [ "base64 0.22.1", "chrono", @@ -14006,12 +14075,12 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "uuid 1.16.0", + "uuid", ] [[package]] name = "windmill-audit" -version = "1.478.1" +version = "1.481.0" dependencies = [ "chrono", "serde", @@ -14024,21 +14093,21 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "serde", "serde_json", "sqlx", "tracing", - "uuid 1.16.0", + "uuid", "windmill-common", "windmill-queue", ] [[package]] name = "windmill-common" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "async-stream", @@ -14048,7 +14117,7 @@ dependencies = [ "backon", "bytes", "chrono", - "chrono-tz 0.10.1", + "chrono-tz 0.10.3", "const_format", "crc", "cron", @@ -14062,7 +14131,7 @@ dependencies = [ "hyper 1.6.0", "indexmap 2.8.0", "itertools 0.14.0", - "jsonwebtoken", + "jsonwebtoken 8.3.0", "lazy_static", "magic-crypt", "mail-send", @@ -14078,11 +14147,14 @@ dependencies = [ "rand 0.9.0", "regex", "reqwest 0.12.15", + "reqwest-middleware", + "reqwest-retry", "semver 1.0.26", "serde", "serde_json", "sha2 0.10.8", "sqlx", + "tar", "tempfile", "thiserror 2.0.12", "tikv-jemalloc-ctl", @@ -14093,27 +14165,27 @@ dependencies = [ "tracing-loki", "tracing-opentelemetry", "tracing-subscriber", - "uuid 1.16.0", + "uuid", "windmill-macros", ] [[package]] name = "windmill-git-sync" -version = "1.478.1" +version = "1.481.0" dependencies = [ "regex", "serde", "serde_json", "sqlx", "tracing", - "uuid 1.16.0", + "uuid", "windmill-common", "windmill-queue", ] [[package]] name = "windmill-indexer" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "bytes", @@ -14130,13 +14202,13 @@ dependencies = [ "tokio", "tokio-tar", "tracing", - "uuid 1.16.0", + "uuid", "windmill-common", ] [[package]] name = "windmill-macros" -version = "1.478.1" +version = "1.481.0" dependencies = [ "itertools 0.14.0", "lazy_static", @@ -14148,7 +14220,7 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.478.1" +version = "1.481.0" dependencies = [ "convert_case 0.6.0", "serde", @@ -14157,7 +14229,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "lazy_static", @@ -14169,7 +14241,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "serde_json", @@ -14181,7 +14253,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "gosyn", @@ -14193,7 +14265,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "lazy_static", @@ -14203,9 +14275,21 @@ dependencies = [ "windmill-parser", ] +[[package]] +name = "windmill-parser-java" +version = "1.481.0" +dependencies = [ + "anyhow", + "serde_json", + "tree-sitter", + "tree-sitter-java", + "wasm-bindgen", + "windmill-parser", +] + [[package]] name = "windmill-parser-nu" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "nu-parser", @@ -14216,7 +14300,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -14227,7 +14311,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -14238,7 +14322,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "async-recursion", @@ -14258,7 +14342,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -14275,7 +14359,7 @@ dependencies = [ [[package]] name = "windmill-parser-sql" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "lazy_static", @@ -14287,7 +14371,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "lazy_static", @@ -14305,7 +14389,7 @@ dependencies = [ [[package]] name = "windmill-parser-wasm" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "getrandom 0.2.15", @@ -14317,6 +14401,7 @@ dependencies = [ "windmill-parser-csharp", "windmill-parser-go", "windmill-parser-graphql", + "windmill-parser-java", "windmill-parser-nu", "windmill-parser-php", "windmill-parser-py", @@ -14328,7 +14413,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "serde_json", @@ -14338,14 +14423,14 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "async-recursion", "axum", "backon", "chrono", - "chrono-tz 0.10.1", + "chrono-tz 0.10.3", "cron", "futures", "futures-core", @@ -14364,14 +14449,14 @@ dependencies = [ "tokio", "tracing", "ulid", - "uuid 1.16.0", + "uuid", "windmill-audit", "windmill-common", ] [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.478.1" +version = "1.481.0" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -14381,7 +14466,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.478.1" +version = "1.481.0" dependencies = [ "anyhow", "async-recursion", @@ -14409,12 +14494,13 @@ dependencies = [ "deno_webidl", "dotenv", "dyn-iter", + "flume", "futures", "gcp_auth", "git-version", "hex", "itertools 0.14.0", - "jsonwebtoken", + "jsonwebtoken 8.3.0", "lazy_static", "mappable-rc", "mysql_async", @@ -14430,6 +14516,7 @@ dependencies = [ "rand 0.9.0", "regex", "reqwest 0.12.15", + "reqwest-middleware", "rust_decimal", "serde", "serde_json", @@ -14441,17 +14528,20 @@ dependencies = [ "tokio-postgres 0.7.13", "tokio-util", "tracing", + "url", "urlencoding", - "uuid 1.16.0", + "uuid", "winapi", "windmill-audit", "windmill-common", "windmill-git-sync", + "windmill-macros", "windmill-parser", "windmill-parser-bash", "windmill-parser-csharp", "windmill-parser-go", "windmill-parser-graphql", + "windmill-parser-java", "windmill-parser-nu", "windmill-parser-php", "windmill-parser-py", @@ -14550,6 +14640,19 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.2", + "windows-strings 0.4.0", +] + [[package]] name = "windows-implement" version = "0.56.0" @@ -14583,6 +14686,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "windows-interface" version = "0.56.0" @@ -14616,6 +14730,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "windows-link" version = "0.1.1" @@ -14679,6 +14804,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -15006,7 +15140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", - "rustix 1.0.3", + "rustix 1.0.5", ] [[package]] @@ -15080,11 +15214,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.23" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" dependencies = [ - "zerocopy-derive 0.8.23", + "zerocopy-derive 0.8.24", ] [[package]] @@ -15100,9 +15234,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.23" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index c001db30c2..ed4155f495 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.478.1" +version = "1.481.0" authors.workspace = true edition.workspace = true @@ -23,6 +23,7 @@ members = [ "./parsers/windmill-parser-rust", "./parsers/windmill-parser-csharp", "./parsers/windmill-parser-nu", + "./parsers/windmill-parser-java", "./parsers/windmill-parser-bash", "./parsers/windmill-parser-py", "./parsers/windmill-parser-py-imports", @@ -31,7 +32,7 @@ members = [ ] [workspace.package] -version = "1.478.1" +version = "1.481.0" authors = ["Ruben Fiszel "] edition = "2021" @@ -48,9 +49,10 @@ lto = "thin" [features] default = [] +agent_worker_server = ["windmill-api/agent_worker_server"] enterprise = ["windmill-worker/enterprise", "windmill-queue/enterprise", "windmill-api/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise", "windmill-git-sync/enterprise", "windmill-common/prometheus", "windmill-common/enterprise"] enterprise_saml = ["windmill-api/enterprise_saml", "oauth2"] -stripe = ["windmill-api/stripe", "enterprise"] +stripe = ["windmill-api/stripe"] benchmark = ["windmill-api/benchmark", "windmill-worker/benchmark", "windmill-queue/benchmark", "windmill-common/benchmark"] loki = ["windmill-common/loki"] embedding = ["windmill-api/embedding"] @@ -62,36 +64,41 @@ cloud = ["windmill-queue/cloud", "windmill-worker/cloud", "windmill-common/cloud jemalloc = ["windmill-common/jemalloc", "dep:tikv-jemallocator", "dep:tikv-jemalloc-sys", "dep:tikv-jemalloc-ctl"] tantivy = ["dep:windmill-indexer", "windmill-api/tantivy", "windmill-indexer/enterprise", "windmill-indexer/parquet", "windmill-common/tantivy", "enterprise", "parquet"] sqlx = ["windmill-worker/sqlx"] -deno_core = ["windmill-worker/deno_core", "dep:deno_core", "dep:v8"] +deno_core = ["windmill-worker/deno_core", "windmill-api/deno_core", "dep:deno_core", "dep:v8"] kafka = ["windmill-api/kafka"] nats = ["windmill-api/nats"] otel = ["windmill-common/otel", "windmill-worker/otel"] dind = ["windmill-worker/dind"] -php = ["windmill-worker/php"] +websocket = ["windmill-api/websocket"] +http_trigger = ["windmill-api/http_trigger"] +postgres_trigger = ["windmill-api/postgres_trigger"] +mqtt_trigger = ["windmill-api/mqtt_trigger"] +sqs_trigger = ["windmill-api/sqs_trigger"] +gcp_trigger = ["windmill-api/gcp_trigger"] +smtp = ["windmill-api/smtp", "windmill-common/smtp"] +license = ["windmill-api/license"] +oauth2 = ["windmill-api/oauth2"] +zip = ["windmill-api/zip"] +static_frontend = ["windmill-api/static_frontend"] +scoped_cache = ["windmill-common/scoped_cache"] +# Languages +python = ["windmill-worker/python"] rust = ["windmill-worker/rust"] mysql = ["windmill-worker/mysql"] oracledb = ["windmill-worker/oracledb"] mssql = ["windmill-worker/mssql"] bigquery = ["windmill-worker/bigquery"] -websocket = ["windmill-api/websocket"] -postgres_trigger = ["windmill-api/postgres_trigger"] -mqtt_trigger = ["windmill-api/mqtt_trigger"] -sqs_trigger = ["windmill-api/sqs_trigger"] -python = ["windmill-worker/python"] -smtp = ["windmill-api/smtp", "windmill-common/smtp"] +php = ["windmill-worker/php"] csharp = ["windmill-worker/csharp"] nu = ["windmill-worker/nu"] -license = ["windmill-api/license"] -oauth2 = ["windmill-api/oauth2"] -http_trigger = ["windmill-api/http_trigger"] -zip = ["windmill-api/zip"] -static_frontend = ["windmill-api/static_frontend"] -scoped_cache = ["windmill-common/scoped_cache"] +java = ["windmill-worker/java"] +all_languages = [ "python", "deno_core", "rust", "mysql", "oracledb", "mssql", "bigquery", "csharp", "nu", "php", "java"] [dependencies] anyhow.workspace = true tokio.workspace = true +tokio-stream.workspace = true dotenv.workspace = true windmill-queue.workspace = true windmill-common = { workspace = true, default-features = false } @@ -118,6 +125,8 @@ serde_json.workspace = true serde.workspace = true deno_core = { workspace = true, optional = true } object_store = { workspace = true, optional = true } +sha1 = { workspace = true, optional = true } +constant_time_eq = { workspace = true, optional = true } quote.workspace = true memchr.workspace = true v8 = { workspace = true, optional = true } @@ -156,6 +165,7 @@ windmill-parser-go = { path = "./parsers/windmill-parser-go" } windmill-parser-rust = { path = "./parsers/windmill-parser-rust" } windmill-parser-yaml = { path = "./parsers/windmill-parser-yaml" } windmill-parser-csharp = { path = "./parsers/windmill-parser-csharp" } +windmill-parser-java = { path = "./parsers/windmill-parser-java" } windmill-parser-nu = { path = "./parsers/windmill-parser-nu" } windmill-parser-bash = { path = "./parsers/windmill-parser-bash" } windmill-parser-sql = { path = "./parsers/windmill-parser-sql" } @@ -163,12 +173,16 @@ windmill-parser-graphql = { path = "./parsers/windmill-parser-graphql" } windmill-parser-php = { path = "./parsers/windmill-parser-php" } windmill-api-client = { path = "./windmill-api-client" } +reqwest-retry = "^0" +reqwest-middleware = { version = "^0", features = ["json"] } + rustls = "0.23.0" memchr = "2.7.4" axum = { version = "^0.7", features = ["multipart"] } headers = "^0" hyper = { version = "^1", features = ["full"] } tokio = { version = "^1.42.0", features = ["full", "tracing", "time"] } +tokio-stream = { version = "0.1.17" } tower = "^0" tower-http = { version = "^0.6", features = ["trace", "cors"] } tower-cookies = "^0.10" @@ -231,6 +245,8 @@ deno_runtime = { version = "0.198.0", features = ["transpile"] } deno_telemetry = "0.12.0" deno_error = "=0.5.5" +google-cloud-pubsub = "0.30.0" +google-cloud-googleapis = {version = "0.16.1", features = ["pubsub"]} # TODO: remove once deno fixes the issue on their end # https://github.com/denoland/deno/issues/28557 winapi = { version = "0.3.9", features = ["sysinfoapi"] } @@ -242,12 +258,11 @@ swc_ecma_visit = "=0.104.8" async-recursion = "^1" -# remove when async-strip is removed, needed to pin rand -half = "=2.4.1" base64 = "^0" base32 = "^0" hmac = "0.12.1" sha2 = "0.10.6" +sha1 = "0.10.6" sqlx = { version = "0.8.0", features = [ "macros", "migrate", @@ -266,13 +281,9 @@ futures-core = "^0" lazy_static = "1.4.0" serde_derive = "1.0.147" const_format = { version = "0.2", features = ["rust_1_64", "rust_1_51"] } +constant_time_eq = "0.3.1" dyn-iter = "0.2.0" rsa = "^0" -async-stripe = { version = "0.39.1", features = [ - "runtime-tokio-hyper", - "checkout", - "billing", -] } async_zip = { version = "0.0.17", features = ["tokio", "tokio-fs", "deflate", "chrono"] } once_cell = "1.17.1" gosyn = "0.2.6" @@ -339,9 +350,12 @@ opentelemetry-semantic-conventions = { version = "0.27.0", features = ["semconv_ bollard = "0.18.1" -tonic = { version = "^0", features = ["tls-native-roots"] } +tonic = { version = "=0.12.3", features = ["tls-native-roots"] } byteorder = "1.5.0" +# todo remove +half = "=2.4.1" + tikv-jemallocator = { version = "0.5" } tikv-jemalloc-sys = { version = "^0.5" } tikv-jemalloc-ctl = { version = "^0.5" } @@ -353,6 +367,8 @@ tantivy = "0.22.0" backon = "1.3.0" +flume = { version = "0.11.1", features = ["async"] } + # Macro-related proc-macro2 = "1.0" pulldown-cmark = "0.9" @@ -364,5 +380,6 @@ yaml-rust = "0.4.5" tokio-tungstenite = { version = "0.24.0", features = ["native-tls"] } tree-sitter = { version = "0.23.0", features = [] } tree-sitter-c-sharp = "0.23.0" +tree-sitter-java = "0.23.0" oracle = { version = "0.6.3", features = ["chrono"] } rumqttc = { version = "0.24.0", features = ["use-native-tls"]} diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 41ce253b23..91f337034b 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -94ff10ff18c121f49180ddaebf5dee8cd94d06df \ No newline at end of file +1475a504133766e005ec551004c2af2283663352 \ No newline at end of file diff --git a/backend/migrations/20250304181111_add_java.down.sql b/backend/migrations/20250304181111_add_java.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250304181111_add_java.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250304181111_add_java.up.sql b/backend/migrations/20250304181111_add_java.up.sql new file mode 100644 index 0000000000..57256afe18 --- /dev/null +++ b/backend/migrations/20250304181111_add_java.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'java'; +UPDATE config set config = jsonb_set(config, '{worker_tags}', config->'worker_tags' || '["java"]'::jsonb) where name = 'worker__default' and config @> '{"worker_tags": ["deno", "python3", "go", "bash", "powershell", "dependency", "flow", "hub", "other", "bun", "php", "rust", "ansible", "csharp", "nu"]}'::jsonb AND NOT config->'worker_tags' @> '"java"'::jsonb; diff --git a/backend/migrations/20250318151955_workspace_git_app_settings.down.sql b/backend/migrations/20250318151955_workspace_git_app_settings.down.sql new file mode 100644 index 0000000000..97cc1fafb8 --- /dev/null +++ b/backend/migrations/20250318151955_workspace_git_app_settings.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE workspace_settings +DROP COLUMN IF EXISTS git_app_installations; diff --git a/backend/migrations/20250318151955_workspace_git_app_settings.up.sql b/backend/migrations/20250318151955_workspace_git_app_settings.up.sql new file mode 100644 index 0000000000..0e0fc97fb6 --- /dev/null +++ b/backend/migrations/20250318151955_workspace_git_app_settings.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE workspace_settings +ADD COLUMN IF NOT EXISTS git_app_installations JSONB NOT NULL DEFAULT '[]'; \ No newline at end of file diff --git a/backend/migrations/20250319121050_multiple_ai_providers.down.sql b/backend/migrations/20250319121050_multiple_ai_providers.down.sql new file mode 100644 index 0000000000..b6c6ff23bc --- /dev/null +++ b/backend/migrations/20250319121050_multiple_ai_providers.down.sql @@ -0,0 +1,24 @@ +ALTER TABLE workspace_settings RENAME COLUMN ai_config TO ai_resource; + +ALTER TABLE workspace_settings +ADD COLUMN ai_models VARCHAR(255)[] NOT NULL DEFAULT '{}', +ADD COLUMN code_completion_model VARCHAR(255); + +UPDATE workspace_settings +SET ai_resource = CASE + WHEN ai_resource IS NULL THEN NULL + ELSE jsonb_build_object( + 'provider', + COALESCE((SELECT jsonb_object_keys(COALESCE(ai_resource->>'providers', '{}')::jsonb) LIMIT 1), 'openai'), -- Get the first provider key + 'path', + ai_resource->'providers'->(SELECT jsonb_object_keys(COALESCE(ai_resource->>'providers', '{}')::jsonb) LIMIT 1)->>'resource_path' + ) +END, +ai_models = COALESCE(( + SELECT array_agg(model) + FROM jsonb_array_elements_text( + COALESCE(ai_resource->'providers'->(SELECT jsonb_object_keys(COALESCE(ai_resource->>'providers', '{}')::jsonb) LIMIT 1)->>'models', '[]')::jsonb + ) model + WHERE model IS NOT NULL +), '{}'), +code_completion_model = ai_resource->'code_completion_model'->>'model'; diff --git a/backend/migrations/20250319121050_multiple_ai_providers.up.sql b/backend/migrations/20250319121050_multiple_ai_providers.up.sql new file mode 100644 index 0000000000..40353f7501 --- /dev/null +++ b/backend/migrations/20250319121050_multiple_ai_providers.up.sql @@ -0,0 +1,38 @@ +UPDATE workspace_settings +SET ai_resource = CASE + WHEN ai_resource IS NULL OR ai_resource->>'path' IS NULL OR ai_resource->>'provider' IS NULL THEN NULL + ELSE jsonb_build_object( + 'providers', jsonb_build_object( + ai_resource->>'provider', + jsonb_build_object( + 'resource_path', ai_resource->>'path', + 'models', to_jsonb(ai_models) + ) + ), + 'default_model', + CASE + WHEN array_length(ai_models, 1) > 0 THEN jsonb_build_object( + 'model', ai_models[1], + 'provider', ai_resource->>'provider' + ) + ELSE NULL + END, + 'code_completion_model', + CASE + WHEN code_completion_model IS NULL THEN NULL + ELSE jsonb_build_object( + 'model', code_completion_model, + 'provider', ai_resource->>'provider' + ) + END + ) +END; + +ALTER TABLE workspace_settings +DROP COLUMN code_completion_model, +DROP COLUMN ai_models; + +ALTER TABLE workspace_settings RENAME COLUMN ai_resource TO ai_config; + + +-- { providers: { [provider]: { resource_path: resource_path, models: ai_models}, default_model: ai_models[0], code_completion_model: code_completion_model} diff --git a/backend/migrations/20250319234432_rename_require_auth_column_of_http_trigger.down.sql b/backend/migrations/20250319234432_rename_require_auth_column_of_http_trigger.down.sql new file mode 100644 index 0000000000..f34e8407b8 --- /dev/null +++ b/backend/migrations/20250319234432_rename_require_auth_column_of_http_trigger.down.sql @@ -0,0 +1,15 @@ +ALTER TABLE http_trigger + DROP COLUMN authentication_resource_path, + ALTER COLUMN authentication_method DROP DEFAULT, + ALTER COLUMN authentication_method TYPE boolean + USING CASE + WHEN authentication_method = 'windmill'::AUTHENTICATION_METHOD THEN true + ELSE false + END, + ALTER COLUMN authentication_method SET NOT NULL, + ALTER COLUMN authentication_method SET DEFAULT false; + +ALTER TABLE http_trigger + RENAME COLUMN authentication_method TO requires_auth; + +DROP TYPE AUTHENTICATION_METHOD; \ No newline at end of file diff --git a/backend/migrations/20250319234432_rename_require_auth_column_of_http_trigger.up.sql b/backend/migrations/20250319234432_rename_require_auth_column_of_http_trigger.up.sql new file mode 100644 index 0000000000..713e1b1fe3 --- /dev/null +++ b/backend/migrations/20250319234432_rename_require_auth_column_of_http_trigger.up.sql @@ -0,0 +1,22 @@ +CREATE TYPE AUTHENTICATION_METHOD AS ENUM ( + 'none', + 'windmill', + 'api_key', + 'basic_http', + 'custom_script', + 'signature' +); + +ALTER TABLE http_trigger + RENAME COLUMN requires_auth TO authentication_method; + +ALTER TABLE http_trigger + ADD COLUMN authentication_resource_path VARCHAR(255) DEFAULT NULL, + ALTER COLUMN authentication_method DROP DEFAULT, + ALTER COLUMN authentication_method TYPE AUTHENTICATION_METHOD + USING CASE + WHEN authentication_method = true THEN 'windmill'::AUTHENTICATION_METHOD + ELSE 'none'::AUTHENTICATION_METHOD + END, + ALTER COLUMN authentication_method SET NOT NULL, + ALTER COLUMN authentication_method SET DEFAULT 'none'::AUTHENTICATION_METHOD; diff --git a/backend/migrations/20250323131258_add-description-and-cast-extra-args-to-jsonb.down.sql b/backend/migrations/20250323131258_add-description-and-cast-extra-args-to-jsonb.down.sql new file mode 100644 index 0000000000..8384b48725 --- /dev/null +++ b/backend/migrations/20250323131258_add-description-and-cast-extra-args-to-jsonb.down.sql @@ -0,0 +1,6 @@ +-- Add down migration script here +ALTER TABLE schedule + DROP COLUMN description, + ALTER COLUMN on_failure_extra_args SET DATA TYPE json USING on_failure_extra_args::json, + ALTER COLUMN on_success_extra_args SET DATA TYPE json USING on_success_extra_args::json, + ALTER COLUMN on_recovery_extra_args SET DATA TYPE json USING on_recovery_extra_args::json; diff --git a/backend/migrations/20250323131258_add-description-and-cast-extra-args-to-jsonb.up.sql b/backend/migrations/20250323131258_add-description-and-cast-extra-args-to-jsonb.up.sql new file mode 100644 index 0000000000..cd50e7a2db --- /dev/null +++ b/backend/migrations/20250323131258_add-description-and-cast-extra-args-to-jsonb.up.sql @@ -0,0 +1,6 @@ +-- Add up migration script here +ALTER TABLE schedule + ADD COLUMN description TEXT NULL, + ALTER COLUMN on_failure_extra_args SET DATA TYPE jsonb USING on_failure_extra_args::jsonb, + ALTER COLUMN on_success_extra_args SET DATA TYPE jsonb USING on_success_extra_args::jsonb, + ALTER COLUMN on_recovery_extra_args SET DATA TYPE jsonb USING on_recovery_extra_args::jsonb; diff --git a/backend/migrations/20250323135044_add-gcp-trigger-table.down.sql b/backend/migrations/20250323135044_add-gcp-trigger-table.down.sql new file mode 100644 index 0000000000..94e32f5962 --- /dev/null +++ b/backend/migrations/20250323135044_add-gcp-trigger-table.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +DROP TABLE gcp_trigger; +DROP TYPE DELIVERY_MODE; \ No newline at end of file diff --git a/backend/migrations/20250323135044_add-gcp-trigger-table.up.sql b/backend/migrations/20250323135044_add-gcp-trigger-table.up.sql new file mode 100644 index 0000000000..2098d27e69 --- /dev/null +++ b/backend/migrations/20250323135044_add-gcp-trigger-table.up.sql @@ -0,0 +1,80 @@ +-- Add up migration script here + +ALTER TYPE TRIGGER_KIND ADD VALUE IF NOT EXISTS 'gcp'; +CREATE TYPE DELIVERY_MODE AS ENUM ('push', 'pull'); + +CREATE TABLE gcp_trigger ( + gcp_resource_path VARCHAR(255) NOT NULL, + topic_id VARCHAR(255) NOT NULL CHECK ( + CHAR_LENGTH(topic_id) BETWEEN 3 AND 255 + ), + subscription_id VARCHAR(255) NOT NULL CHECK ( + CHAR_LENGTH(subscription_id) BETWEEN 3 AND 255 + ), + delivery_type DELIVERY_MODE NOT NULL, + delivery_config JSONB NULL CHECK (delivery_type != 'push'::DELIVERY_MODE OR (delivery_config IS NOT NULL)), + path VARCHAR(255) NOT NULL, + script_path VARCHAR(255) NOT NULL, + is_flow BOOLEAN NOT NULL, + workspace_id VARCHAR(50) NOT NULL, + edited_by VARCHAR(50) NOT NULL, + email VARCHAR(255) NOT NULL, + edited_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + extra_perms JSONB NOT NULL DEFAULT '{}', + server_id VARCHAR(50), + last_server_ping TIMESTAMPTZ, + error TEXT, + enabled BOOLEAN NOT NULL, + PRIMARY KEY (path, workspace_id) +); + +CREATE UNIQUE INDEX unique_subscription_per_gcp_resource +ON gcp_trigger (subscription_id, gcp_resource_path, workspace_id); + +GRANT ALL ON gcp_trigger TO windmill_user; +GRANT ALL ON gcp_trigger TO windmill_admin; + +ALTER TABLE gcp_trigger ENABLE ROW LEVEL SECURITY; + +CREATE POLICY admin_policy ON gcp_trigger FOR ALL TO windmill_admin USING (true); + +CREATE POLICY see_folder_extra_perms_user_select ON gcp_trigger FOR SELECT TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_insert ON gcp_trigger FOR INSERT TO windmill_user +WITH CHECK (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_update ON gcp_trigger FOR UPDATE TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_delete ON gcp_trigger FOR DELETE TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); + +CREATE POLICY see_own ON gcp_trigger FOR ALL TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'u' AND SPLIT_PART(gcp_trigger.path, '/', 2) = current_setting('session.user')); +CREATE POLICY see_member ON gcp_trigger FOR ALL TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'g' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.groups'), ',')::text[])); + +CREATE POLICY see_extra_perms_user_select ON gcp_trigger FOR SELECT TO windmill_user +USING (extra_perms ? CONCAT('u/', current_setting('session.user'))); +CREATE POLICY see_extra_perms_user_insert ON gcp_trigger FOR INSERT TO windmill_user +WITH CHECK ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean); +CREATE POLICY see_extra_perms_user_update ON gcp_trigger FOR UPDATE TO windmill_user +USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean); +CREATE POLICY see_extra_perms_user_delete ON gcp_trigger FOR DELETE TO windmill_user +USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean); + +CREATE POLICY see_extra_perms_groups_select ON gcp_trigger FOR SELECT TO windmill_user +USING (extra_perms ?| regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]); +CREATE POLICY see_extra_perms_groups_insert ON gcp_trigger FOR INSERT TO windmill_user +WITH CHECK (exists( + SELECT key, value FROM jsonb_each_text(extra_perms) + WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]) + AND value::boolean)); +CREATE POLICY see_extra_perms_groups_update ON gcp_trigger FOR UPDATE TO windmill_user +USING (exists( + SELECT key, value FROM jsonb_each_text(extra_perms) + WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]) + AND value::boolean)); +CREATE POLICY see_extra_perms_groups_delete ON gcp_trigger FOR DELETE TO windmill_user +USING (exists( + SELECT key, value FROM jsonb_each_text(extra_perms) + WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]) + AND value::boolean)); \ No newline at end of file diff --git a/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.down.sql b/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.up.sql b/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.up.sql new file mode 100644 index 0000000000..cdf8530b35 --- /dev/null +++ b/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TYPE job_trigger_kind ADD VALUE IF NOT EXISTS 'sqs'; +ALTER TYPE job_trigger_kind ADD VALUE IF NOT EXISTS 'gcp'; diff --git a/backend/migrations/20250326105126_remove_automatic_billing_col.down.sql b/backend/migrations/20250326105126_remove_automatic_billing_col.down.sql new file mode 100644 index 0000000000..b49aa205d9 --- /dev/null +++ b/backend/migrations/20250326105126_remove_automatic_billing_col.down.sql @@ -0,0 +1 @@ +ALTER TABLE workspace_settings ADD COLUMN automatic_billing BOOLEAN NOT NULL DEFAULT TRUE; \ No newline at end of file diff --git a/backend/migrations/20250326105126_remove_automatic_billing_col.up.sql b/backend/migrations/20250326105126_remove_automatic_billing_col.up.sql new file mode 100644 index 0000000000..776f1da82f --- /dev/null +++ b/backend/migrations/20250326105126_remove_automatic_billing_col.up.sql @@ -0,0 +1 @@ +ALTER TABLE workspace_settings DROP COLUMN automatic_billing; \ No newline at end of file diff --git a/backend/migrations/20250407124204_update_hub_sync_script.down.sql b/backend/migrations/20250407124204_update_hub_sync_script.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250407124204_update_hub_sync_script.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250407124204_update_hub_sync_script.up.sql b/backend/migrations/20250407124204_update_hub_sync_script.up.sql new file mode 100644 index 0000000000..84e50b36c0 --- /dev/null +++ b/backend/migrations/20250407124204_update_hub_sync_script.up.sql @@ -0,0 +1,284 @@ +-- Add up migration script here +-- Add up migration script here +UPDATE script SET content = 'import * as wmill from "windmill-cli@1.481.0" + +export async function main() { + await wmill.hubPull({ workspace: "admins", token: process.env["WM_TOKEN"], baseUrl: globalThis.process.env["BASE_URL"] }); +} +', language = 'bun', +lock = '{ + "dependencies": { + "windmill-cli": "1.481.0" + } +} +//bun.lock +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "dependencies": { + "windmill-cli": "1.481.0", + }, + }, + }, + "packages": { + "@ayonli/jsext": ["@ayonli/jsext@1.6.0", "", { "dependencies": { "iconv-lite": "^0.6.3", "sudo-prompt": "^9.2.1", "ws": "^8.17.0", "zod": "^3.23.8" } }, "sha512-dMQuZJIVadEgQ6xp1Q5hRv2JfwANDwnElH6kZWuSjcnAjhvtCoQQ02CdOipfCd4cyrFpaI+8yBboiT9OkRaVyg=="], + + "@deno/shim-deno": ["@deno/shim-deno@0.18.2", "", { "dependencies": { "@deno/shim-deno-test": "^0.5.0", "which": "^4.0.0" } }, "sha512-oQ0CVmOio63wlhwQF75zA4ioolPvOwAoK0yuzcS5bDC1JUvH3y1GS8xPh8EOpcoDQRU4FTG8OQfxhpR+c6DrzA=="], + + "@deno/shim-deno-test": ["@deno/shim-deno-test@0.5.0", "", {}, "sha512-4nMhecpGlPi0cSzT67L+Tm+GOJqvuk8gqHBziqcUQOarnuIax1z96/gJHCSIz2Z0zhxE6Rzwb3IZXPtFh51j+w=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.2", "", { "os": "android", "cpu": "arm" }, "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.2", "", { "os": "android", "cpu": "x64" }, "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.2", "", { "os": "linux", "cpu": "arm" }, "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.2", "", { "os": "linux", "cpu": "x64" }, "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.2", "", { "os": "none", "cpu": "arm64" }, "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.2", "", { "os": "none", "cpu": "x64" }, "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.2", "", { "os": "win32", "cpu": "x64" }, "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA=="], + + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], + + "brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + + "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], + + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + + "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], + + "default-browser": ["default-browser@5.2.1", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg=="], + + "default-browser-id": ["default-browser-id@5.0.0", "", {}, "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA=="], + + "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-main": ["es-main@1.3.0", "", {}, "sha512-AzORKdz1Zt97TzbYQnIrI3ZiibWpRXUfpo/w0xOJ20GpNYd2bd3MU9m31zS/aJ1TJl6JfLTok83Y8HjNunYT0A=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "esbuild": ["esbuild@0.25.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.2", "@esbuild/android-arm": "0.25.2", "@esbuild/android-arm64": "0.25.2", "@esbuild/android-x64": "0.25.2", "@esbuild/darwin-arm64": "0.25.2", "@esbuild/darwin-x64": "0.25.2", "@esbuild/freebsd-arm64": "0.25.2", "@esbuild/freebsd-x64": "0.25.2", "@esbuild/linux-arm": "0.25.2", "@esbuild/linux-arm64": "0.25.2", "@esbuild/linux-ia32": "0.25.2", "@esbuild/linux-loong64": "0.25.2", "@esbuild/linux-mips64el": "0.25.2", "@esbuild/linux-ppc64": "0.25.2", "@esbuild/linux-riscv64": "0.25.2", "@esbuild/linux-s390x": "0.25.2", "@esbuild/linux-x64": "0.25.2", "@esbuild/netbsd-arm64": "0.25.2", "@esbuild/netbsd-x64": "0.25.2", "@esbuild/openbsd-arm64": "0.25.2", "@esbuild/openbsd-x64": "0.25.2", "@esbuild/sunos-x64": "0.25.2", "@esbuild/win32-arm64": "0.25.2", "@esbuild/win32-ia32": "0.25.2", "@esbuild/win32-x64": "0.25.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], + + "finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], + + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-port": ["get-port@7.1.0", "", {}, "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], + + "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + + "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + + "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], + + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + + "isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], + + "jszip": ["jszip@3.7.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "set-immediate-shim": "~1.0.1" } }, "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg=="], + + "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], + + "minimatch": ["minimatch@10.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "open": ["open@10.1.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "is-wsl": "^3.1.0" } }, "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw=="], + + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="], + + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="], + + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + + "run-applescript": ["run-applescript@7.0.0", "", {}, "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], + + "serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], + + "set-immediate-shim": ["set-immediate-shim@1.0.1", "", {}, "sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "sudo-prompt": ["sudo-prompt@9.2.1", "", {}, "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], + + "windmill-cli": ["windmill-cli@1.481.0", "", { "dependencies": { "@ayonli/jsext": "*", "@deno/shim-deno": "~0.18.0", "diff": "*", "es-main": "*", "esbuild": "*", "express": "*", "get-port": "7.1.0", "jszip": "3.7.1", "minimatch": "*", "open": "*", "ws": "*" }, "bin": { "wmill": "esm/main.js" } }, "sha512-nIIrt+/+TqeyHlgcDnPMTBH3CZX4TMVwxy2UFD+5lOI5OY9JOtCpWk5UPn6BOs6fw1DG0MIBJG7AhCuPelfSiQ=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="], + + "zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], + + "readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + } +}' +WHERE hash = -28028598712388162 AND workspace_id = 'admins'; \ No newline at end of file diff --git a/backend/migrations/20250409093642_add_grant.down.sql b/backend/migrations/20250409093642_add_grant.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250409093642_add_grant.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250409093642_add_grant.up.sql b/backend/migrations/20250409093642_add_grant.up.sql new file mode 100644 index 0000000000..95bae6b21c --- /dev/null +++ b/backend/migrations/20250409093642_add_grant.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +GRANT ALL on workspace_runnable_dependencies TO windmill_user; +GRANT ALL on workspace_runnable_dependencies TO windmill_admin; \ No newline at end of file diff --git a/backend/migrations/20250412144540_improve_perf_api_role.down.sql b/backend/migrations/20250412144540_improve_perf_api_role.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250412144540_improve_perf_api_role.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250412144540_improve_perf_api_role.up.sql b/backend/migrations/20250412144540_improve_perf_api_role.up.sql new file mode 100644 index 0000000000..8a521849fb --- /dev/null +++ b/backend/migrations/20250412144540_improve_perf_api_role.up.sql @@ -0,0 +1,22 @@ +-- Add up migration script here + CREATE OR REPLACE FUNCTION set_session_context( + admin BOOLEAN, + username TEXT, + groups TEXT, + pgroups TEXT, + folders_read TEXT, + folders_write TEXT +) RETURNS void AS $$ +BEGIN + IF admin THEN + SET LOCAL ROLE windmill_admin; + ELSE + SET LOCAL ROLE windmill_user; + END IF; + PERFORM set_config('session.user', username, true); + PERFORM set_config('session.groups', groups, true); + PERFORM set_config('session.pgroups', pgroups, true); + PERFORM set_config('session.folders_read', folders_read, true); + PERFORM set_config('session.folders_write', folders_write, true); +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/backend/parsers/windmill-parser-bash/src/lib.rs b/backend/parsers/windmill-parser-bash/src/lib.rs index 39f1d2667b..69d96400dc 100644 --- a/backend/parsers/windmill-parser-bash/src/lib.rs +++ b/backend/parsers/windmill-parser-bash/src/lib.rs @@ -45,7 +45,7 @@ pub fn parse_powershell_sig(code: &str) -> anyhow::Result { } lazy_static::lazy_static! { - static ref RE_BASH: Regex = Regex::new(r#"(?m)^(\w+)="\$(?:(\d+)|\{(\d+):-(.*)\})"(?:[\t ]*)?(?:#.*)?$"#).unwrap(); + static ref RE_BASH: Regex = Regex::new(r#"(?m)^(\w+)="\$(?:(\d+)|\{(\d+)\}|\{(\d+):-(.*)\})"(?:[\t ]*)?(?:#.*)?$"#).unwrap(); pub static ref RE_POWERSHELL_PARAM: Regex = Regex::new(r#"(?m)param[\t ]*\(([^)]*)\)"#).unwrap(); static ref RE_POWERSHELL_ARGS: Regex = Regex::new(r#"(?:\[(\w+)\])?\$(\w+)[\t ]*(?:=[\t ]*(?:(?:(?:"|')([^"\n\r\$]*)(?:"|'))|([\d.]+)))?"#).unwrap(); @@ -57,11 +57,12 @@ fn parse_bash_file(code: &str) -> anyhow::Result>> { hm.insert( cap.get(2) .or(cap.get(3)) + .or(cap.get(4)) .and_then(|x| x.as_str().parse::().ok()) .ok_or_else(|| anyhow!("Impossible to parse arg digit"))?, ( cap[1].to_string(), - cap.get(4).map(|x| x.as_str().to_string()), + cap.get(5).map(|x| x.as_str().to_string()), ), ); } diff --git a/backend/parsers/windmill-parser-java/Cargo.toml b/backend/parsers/windmill-parser-java/Cargo.toml new file mode 100644 index 0000000000..19809e3120 --- /dev/null +++ b/backend/parsers/windmill-parser-java/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "windmill-parser-java" +version.workspace = true +edition.workspace = true +authors.workspace = true + +[lib] +name = "windmill_parser_java" +path = "./src/lib.rs" + +[dependencies] +windmill-parser.workspace = true +tree-sitter.workspace = true +tree-sitter-java.workspace = true +anyhow.workspace = true +wasm-bindgen.workspace = true +serde_json.workspace = true +# convert_case.workspace = true +# lazy_static.workspace = true +# regex.workspace = true + diff --git a/backend/parsers/windmill-parser-java/src/lib.rs b/backend/parsers/windmill-parser-java/src/lib.rs new file mode 100644 index 0000000000..93aa348cec --- /dev/null +++ b/backend/parsers/windmill-parser-java/src/lib.rs @@ -0,0 +1,446 @@ +#![cfg_attr(target_arch = "wasm32", feature(c_variadic))] + +#[cfg(target_arch = "wasm32")] +pub mod wasm_libc; + +use anyhow::anyhow; +use anyhow::bail; +use serde_json::Value; +use tree_sitter::Node; +use windmill_parser::Arg; +use windmill_parser::MainArgSignature; +use windmill_parser::Typ; + +#[derive(Debug)] +pub struct JavaMainSigMeta { + pub is_public: bool, + pub returns_void: bool, + pub class_name: Option, + pub main_sig: MainArgSignature, +} + +pub fn parse_java_sig_meta(code: &str) -> anyhow::Result { + let mut parser = tree_sitter::Parser::new(); + let language = tree_sitter_java::LANGUAGE; + parser + .set_language(&language.into()) + .map_err(|e| anyhow!("Error setting Java as language: {e}"))?; + + // Parse code + let tree = parser + .parse(code, None) + .ok_or(anyhow!("Failed to parse code"))?; + let root_node = tree.root_node(); + + // Traverse the AST to find the Main method signature + let main_sig = find_main_signature(root_node, code); + let no_main_func = Some(main_sig.is_none()); + let mut is_public = false; + let mut returns_void = false; + let mut class_name = None; + + let mut args = vec![]; + if let Some((sig, name)) = main_sig { + class_name = name; + for sig_node in sig.children(&mut sig.walk()) { + if sig_node.kind() == "modifier" && sig_node.utf8_text(code.as_bytes())? == "public" { + is_public = true; + } + } + if let Some(return_type) = sig.child_by_field_name("type") { + let return_type = return_type.utf8_text(code.as_bytes())?; + + if return_type == "void" { + returns_void = true; + } + } + if let Some(param_list) = sig.child_by_field_name("parameters") { + for p_list_node in param_list.children(&mut param_list.walk()) { + if p_list_node.kind() == "formal_parameter" { + let (otyp, typ, name, default) = parse_java_typ(p_list_node, code)?; + args.push(Arg { + name, + otyp, + typ, + has_default: default.is_some(), + default, + oidx: None, + }); + } + } + } + } + + let main_sig = MainArgSignature { + star_args: false, + star_kwargs: false, + args, + has_preprocessor: None, + no_main_func, + }; + + Ok(JavaMainSigMeta { returns_void, class_name, main_sig, is_public }) +} + +pub fn parse_java_signature(code: &str) -> anyhow::Result { + Ok(parse_java_sig_meta(code)?.main_sig) +} + +fn find_typ<'a>(typ_node: Node<'a>, code: &str) -> anyhow::Result<(Typ, Option)> { + let null = Some(serde_json::Value::Null); + let res = match typ_node.kind() { + #[rustfmt::skip] + "type_identifier" => { + match typ_node.utf8_text(code.as_bytes()) { + Ok("String") => (Typ::Str(None), null), + Ok("Byte") => (Typ::Bytes, null), + Ok("Short") => (Typ::Int, null), + Ok("Integer") => (Typ::Int, null), + Ok("Long") => (Typ::Int, null), + Ok("Float") => (Typ::Float, null), + Ok("Double") => (Typ::Float, null), + Ok("Boolean") => (Typ::Bool, null), + Ok("Character") => (Typ::Str(None), null), + Ok("Object") => (Typ::Object(vec![]),null), // TODO: Complete the object type + Ok(s) => bail!("Unknown type `{s}`"), + Err(e) => bail!("Error getting type name: {}", e), + } + } + #[rustfmt::skip] + "integral_type" => { + match typ_node.utf8_text(code.as_bytes()) { + Ok("byte") => (Typ::Bytes, None), + Ok("short") => (Typ::Int, None), + Ok("int") => (Typ::Int, None), + Ok("long") => (Typ::Int, None), + Ok("char") => (Typ::Str(None), None), + Ok(s) => bail!("Unknown type `{s}`"), + Err(e) => bail!("Error getting type name: {}", e), + } + } + "floating_point_type" => { + match typ_node.utf8_text(code.as_bytes()) { + Ok("float") => (Typ::Float, None), + Ok("double") => (Typ::Float, None), + Ok(s) => bail!("Unknown type `{s}`"), + Err(e) => bail!("Error getting type name: {}", e), + } + } + "boolean_type" => { + match typ_node.utf8_text(code.as_bytes()) { + Ok("boolean") => (Typ::Bool, None), + Ok(s) => bail!("Unknown type `{s}`"), + Err(e) => bail!("Error getting type name: {}", e), + } + } + "array_type" => { + let new_typ_node = typ_node + .named_child(0) + .ok_or(anyhow!("Failed to find inner type of array type"))?; + (Typ::List(Box::new(find_typ(new_typ_node, code)?.0)), null) + } + wc => bail!( + "Unexpected Java type node kind: {} for '{}'. This type is not handled by Windmill, please open an issue if this seems to be an error", + wc, + typ_node.utf8_text(code.as_bytes())? + ), + + }; + Ok(res) +} + +fn parse_java_typ<'a>( + param_node: Node<'a>, + code: &str, +) -> anyhow::Result<(Option, Typ, String, Option)> { + let name = param_node + .child_by_field_name("name") + .and_then(|n| n.utf8_text(code.as_bytes()).ok()) + .unwrap_or(""); + let otyp_node = param_node.child_by_field_name("type"); + let otyp = otyp_node + .and_then(|n| n.utf8_text(code.as_bytes()).ok()) + .map(|s| s.to_string()); + + let (typ, default) = find_typ( + otyp_node.ok_or(anyhow!( + "Internal error: Failed to get child by field name 'type'" + ))?, + code, + )?; + + Ok((otyp, typ, name.to_string(), default)) +} + +// Function to find the Main method's signature +fn find_main_signature<'a>(root_node: Node<'a>, code: &str) -> Option<(Node<'a>, Option)> { + let mut cursor = root_node.walk(); + for x in root_node.children(&mut cursor) { + if x.kind() == "class_declaration" { + let class_name = x + .child_by_field_name("name") + .and_then(|n| n.utf8_text(code.as_bytes()).ok().map(|s| s.to_string())); + for c in x.children(&mut x.walk()) { + if c.kind() == "class_body" { + for w in c.children(&mut c.walk()) { + if w.kind() == "method_declaration" { + for child in w.children(&mut w.walk()) { + if child + .utf8_text(code.as_bytes()) + .map(|name| name == "main") + .unwrap_or(false) + { + return Some((w, class_name)); + } + } + } + } + } + } + } + } + return None; +} + +#[cfg(test)] +mod test { + + use serde_json::json; + + use super::*; + #[test] + fn test_parse_java_return_void() { + let code = r#" +class Main { + public static void main() {} +}"#; + let sig_meta = parse_java_sig_meta(code).unwrap(); + + assert_eq!(sig_meta.class_name, Some("Main".to_string())); + + assert!(sig_meta.returns_void); + } + #[test] + fn test_parse_java_return_object() { + let code = r#" +class Main { + public static Object main() {} +}"#; + let sig_meta = parse_java_sig_meta(code).unwrap(); + + assert_eq!(sig_meta.class_name, Some("Main".to_string())); + assert!(!sig_meta.returns_void); + } + #[test] + fn test_parse_java_primitive_types() { + let code = r#" +class Main { + public static string main(byte a, short b, int c, long d, float e, double f, boolean g, char h) {} +}"#; + let sig_meta = parse_java_sig_meta(code).unwrap(); + + assert_eq!(sig_meta.class_name, Some("Main".to_string())); + + let ret = sig_meta.main_sig; + assert_eq!( + ret.args, + vec![ + Arg { + name: "a".into(), + otyp: Some("byte".into()), + typ: Typ::Bytes, + default: None, + has_default: false, + oidx: None + }, + Arg { + name: "b".into(), + otyp: Some("short".into()), + typ: Typ::Int, + default: None, + has_default: false, + oidx: None + }, + Arg { + name: "c".into(), + otyp: Some("int".into()), + typ: Typ::Int, + default: None, + has_default: false, + oidx: None + }, + Arg { + name: "d".into(), + otyp: Some("long".into()), + typ: Typ::Int, + default: None, + has_default: false, + oidx: None + }, + Arg { + name: "e".into(), + otyp: Some("float".into()), + typ: Typ::Float, + default: None, + has_default: false, + oidx: None + }, + Arg { + name: "f".into(), + otyp: Some("double".into()), + typ: Typ::Float, + default: None, + has_default: false, + oidx: None + }, + Arg { + name: "g".into(), + otyp: Some("boolean".into()), + typ: Typ::Bool, + default: None, + has_default: false, + oidx: None + }, + Arg { + name: "h".into(), + otyp: Some("char".into()), + typ: Typ::Str(None), + default: None, + has_default: false, + oidx: None + }, + ] + ); + } + + #[test] + fn test_parse_java_objects() { + let code = r#" +class Main { + public static string main(Byte a, Short b, Integer c, Long d, Float e, Double f, Boolean g, Character h, Object i) {} +}"#; + let sig_meta = parse_java_sig_meta(code).unwrap(); + + assert_eq!(sig_meta.class_name, Some("Main".to_string())); + + let ret = sig_meta.main_sig; + assert_eq!( + ret.args, + vec![ + Arg { + name: "a".into(), + otyp: Some("Byte".into()), + typ: Typ::Bytes, + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "b".into(), + otyp: Some("Short".into()), + typ: Typ::Int, + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "c".into(), + otyp: Some("Integer".into()), + typ: Typ::Int, + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "d".into(), + otyp: Some("Long".into()), + typ: Typ::Int, + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "e".into(), + otyp: Some("Float".into()), + typ: Typ::Float, + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "f".into(), + otyp: Some("Double".into()), + typ: Typ::Float, + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "g".into(), + otyp: Some("Boolean".into()), + typ: Typ::Bool, + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "h".into(), + otyp: Some("Character".into()), + typ: Typ::Str(None), + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "i".into(), + otyp: Some("Object".into()), + typ: Typ::Object(vec![]), + default: Some(json!(null)), + has_default: true, + oidx: None + }, + ] + ); + } + #[test] + fn test_parse_java_array() { + let code = r#" +class Main { + public static string main(int[] a, Object[] b, String[] c) {} +}"#; + let sig_meta = parse_java_sig_meta(code).unwrap(); + + assert_eq!(sig_meta.class_name, Some("Main".to_string())); + + let ret = sig_meta.main_sig; + assert_eq!( + ret.args, + vec![ + Arg { + name: "a".into(), + otyp: Some("int[]".into()), + typ: Typ::List(Box::new(Typ::Int)), + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "b".into(), + otyp: Some("Object[]".into()), + typ: Typ::List(Box::new(Typ::Object(vec![]))), + default: Some(json!(null)), + has_default: true, + oidx: None + }, + Arg { + name: "c".into(), + otyp: Some("String[]".into()), + typ: Typ::List(Box::new(Typ::Str(None))), + default: Some(json!(null)), + has_default: true, + oidx: None + }, + ] + ); + } +} diff --git a/backend/parsers/windmill-parser-java/src/wasm_libc.rs b/backend/parsers/windmill-parser-java/src/wasm_libc.rs new file mode 100644 index 0000000000..7d260af2e8 --- /dev/null +++ b/backend/parsers/windmill-parser-java/src/wasm_libc.rs @@ -0,0 +1,207 @@ +use std::collections::BTreeMap; +use std::sync::{Mutex, OnceLock}; +use std::{ + alloc::{self, Layout}, + ffi::{c_char, c_int, c_void}, + mem::align_of, + ptr, +}; +use wasm_bindgen::prelude::*; + +/* -------------------------------- stdlib.h -------------------------------- */ + +#[no_mangle] +pub unsafe extern "C" fn abort() { + panic!("Aborted from C"); +} + +macro_rules! console_log { + ($($t:tt)*) => (unsafe { log(&format_args!($($t)*).to_string()) }) +} + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn log(a: &str); +} + +#[no_mangle] +pub unsafe extern "C" fn malloc(size: usize) -> *mut c_void { + if size == 0 { + return ptr::null_mut(); + } + + let (layout, offset_to_data) = layout_for_size_prepended(size); + let buf = alloc::alloc(layout); + store_layout(buf, layout, offset_to_data) +} + +#[no_mangle] +pub unsafe extern "C" fn calloc(count: usize, size: usize) -> *mut c_void { + if count == 0 || size == 0 { + return ptr::null_mut(); + } + + let (layout, offset_to_data) = layout_for_size_prepended(size * count); + let buf = alloc::alloc_zeroed(layout); + store_layout(buf, layout, offset_to_data) +} + +#[no_mangle] +pub unsafe extern "C" fn realloc(buf: *mut c_void, new_size: usize) -> *mut c_void { + if buf.is_null() { + malloc(new_size) + } else if new_size == 0 { + free(buf); + ptr::null_mut() + } else { + let (old_buf, old_layout) = retrieve_layout(buf); + let (new_layout, offset_to_data) = layout_for_size_prepended(new_size); + let new_buf = alloc::realloc(old_buf, old_layout, new_layout.size()); + store_layout(new_buf, new_layout, offset_to_data) + } +} + +#[no_mangle] +pub unsafe extern "C" fn free(buf: *mut c_void) { + if buf.is_null() { + return; + } + let (buf, layout) = retrieve_layout(buf); + alloc::dealloc(buf, layout); +} + +// In all these allocations, we store the layout before the data for later retrieval. +// This is because we need to know the layout when deallocating the memory. +// Here are some helper methods for that: + +/// Given a pointer to the data, retrieve the layout and the pointer to the layout. +unsafe fn retrieve_layout(buf: *mut c_void) -> (*mut u8, Layout) { + let (_, layout_offset) = Layout::new::() + .extend(Layout::from_size_align(0, align_of::<*const u8>() * 2).unwrap()) + .unwrap(); + + let buf = (buf as *mut u8).offset(-(layout_offset as isize)); + let layout = *(buf as *mut Layout); + + (buf, layout) +} + +/// Calculate a layout for a given size with space for storing a layout at the start. +/// Returns the layout and the offset to the data. +fn layout_for_size_prepended(size: usize) -> (Layout, usize) { + Layout::new::() + .extend(Layout::from_size_align(size, align_of::<*const u8>() * 2).unwrap()) + .unwrap() +} + +/// Store a layout in the pointer, returning a pointer to where the data should be stored. +unsafe fn store_layout(buf: *mut u8, layout: Layout, offset_to_data: usize) -> *mut c_void { + *(buf as *mut Layout) = layout; + (buf as *mut u8).offset(offset_to_data as isize) as *mut c_void +} + +/* -------------------------------- string.h -------------------------------- */ + +#[no_mangle] +pub unsafe extern "C" fn strncmp(ptr1: *const c_void, ptr2: *const c_void, n: usize) -> c_int { + let s1 = std::slice::from_raw_parts(ptr1 as *const u8, n); + let s2 = std::slice::from_raw_parts(ptr2 as *const u8, n); + + for (a, b) in s1.iter().zip(s2.iter()) { + if *a != *b || *a == 0 { + return (*a as i32) - (*b as i32); + } + } + + 0 +} + +/* -------------------------------- wctype.h -------------------------------- */ + +#[no_mangle] +pub unsafe extern "C" fn iswspace(c: c_int) -> bool { + char::from_u32(c as u32).map_or(false, |c| c.is_whitespace()) +} + +#[no_mangle] +pub unsafe extern "C" fn iswalnum(c: c_int) -> bool { + char::from_u32(c as u32).map_or(false, |c| c.is_alphanumeric()) +} + +/* --------------------------------- time.h --------------------------------- */ + +#[no_mangle] +pub unsafe extern "C" fn clock() -> u64 { + panic!("clock is not supported"); +} + +/* --------------------------------- ctype.h -------------------------------- */ + +#[no_mangle] +pub unsafe extern "C" fn isprint(c: c_int) -> bool { + c >= 32 && c <= 126 +} + +/* --------------------------------- stdio.h -------------------------------- */ + +#[no_mangle] +pub unsafe extern "C" fn fprintf(_file: *mut c_void, _format: *const c_void, _args: ...) -> c_int { + panic!("fprintf is not supported"); +} + +#[no_mangle] +pub unsafe extern "C" fn fputs(_s: *const c_void, _file: *mut c_void) -> c_int { + panic!("fputs is not supported"); +} + +#[no_mangle] +pub unsafe extern "C" fn fputc(_c: c_int, _file: *mut c_void) -> c_int { + panic!("fputc is not supported"); +} + +#[no_mangle] +pub unsafe extern "C" fn fdopen(_fd: c_int, _mode: *const c_void) -> *mut c_void { + panic!("fdopen is not supported"); +} + +#[no_mangle] +pub unsafe extern "C" fn fclose(_file: *mut c_void) -> c_int { + panic!("fclose is not supported"); +} + +#[no_mangle] +pub unsafe extern "C" fn fwrite( + _ptr: *const c_void, + _size: usize, + _nmemb: usize, + _stream: *mut c_void, +) -> usize { + panic!("fwrite is not supported"); +} + +#[no_mangle] +pub unsafe extern "C" fn vsnprintf( + _buf: *mut c_char, + _size: usize, + _format: *const c_char, + _args: ... +) -> c_int { + panic!("vsnprintf is not supported"); +} + +#[no_mangle] +pub extern "C" fn clock_gettime(ptr: usize, new_size: usize) { + panic!("clock_gettime is not supported"); +} + +// int snprintf( char* restrict buffer, size_t bufsz, const char* restrict format, ... ); +#[no_mangle] +pub extern "C" fn snprintf() { + panic!("snprintf is not supported"); +} + +#[no_mangle] +pub extern "C" fn __assert_fail(_: *const i32, _: *const i32, _: *const i32, _: *const i32) { + panic!("oh no"); +} diff --git a/backend/parsers/windmill-parser-py-imports/src/lib.rs b/backend/parsers/windmill-parser-py-imports/src/lib.rs index 77324f2384..2f18b74d6b 100644 --- a/backend/parsers/windmill-parser-py-imports/src/lib.rs +++ b/backend/parsers/windmill-parser-py-imports/src/lib.rs @@ -6,11 +6,14 @@ * LICENSE-AGPL for a copy of the license. */ +mod mapping; + use async_recursion::async_recursion; use itertools::Itertools; use lazy_static::lazy_static; -use phf::phf_map; +use std::collections::HashMap; +use mapping::{FULL_IMPORTS_MAP, SHORT_IMPORTS_MAP}; #[cfg(not(target_arch = "wasm32"))] use regex::Regex; #[cfg(target_arch = "wasm32")] @@ -18,6 +21,7 @@ use regex_lite::Regex; use rustpython_parser::{ ast::{Stmt, StmtImport, StmtImportFrom, Suite}, + text_size::TextRange, Parse, }; use sqlx::{Pool, Postgres}; @@ -25,62 +29,24 @@ use windmill_common::{error, worker::PythonAnnotations}; const DEF_MAIN: &str = "def main("; -static PYTHON_IMPORTS_REPLACEMENT: phf::Map<&'static str, &'static str> = phf_map! { - "psycopg2" => "psycopg2-binary", - "psycopg" => "psycopg[binary, pool]", - "yaml" => "pyyaml", - "git" => "GitPython", - "shopify" => "ShopifyAPI", - "seleniumwire" => "selenium-wire", - "openbb-terminal" => "openbb[all]", - "riskfolio" => "riskfolio-lib", - "smb" => "pysmb", - "PIL" => "Pillow", - "googleapiclient" => "google-api-python-client", - "googlecloudbigquery" => "google-cloud-bigquery", - "dateutil" => "python-dateutil", - "mailparser" => "mail-parser", - "mailparser-reply" => "mail-parser-reply", - "gitlab" => "python-gitlab", - "smbclient" => "smbprotocol", - "playhouse" => "peewee", - "dns" => "dnspython", - "msoffcrypto" => "msoffcrypto-tool", - "tabula" => "tabula-py", - "shapefile" => "pyshp", - "sklearn" => "scikit-learn", - "umap" => "umap-learn", - "cv2" => "opencv-python", - "atlassian" => "atlassian-python-api", - "mysql" => "mysql-connector-python", - "tenable" => "pytenable", - "ns1" => "ns1-python", - "pymsql" => "PyMySQL", - "haystack" => "haystack-ai", - "github" => "PyGithub", - "ldap" => "python-ldap", - "opensearchpy" => "opensearch-py", - "lokalise" => "python-lokalise-api", - "msgraph" => "msgraph-sdk", - "pythonjsonlogger" => "python-json-logger", - "socks" => "PySocks", - "taiga" => "python-taiga", - "docx" => "python-docx", -}; - fn replace_import(x: String) -> String { - PYTHON_IMPORTS_REPLACEMENT + SHORT_IMPORTS_MAP .get(&x) .map(|x| x.to_owned()) .unwrap_or(&x) .to_string() } -lazy_static! { - static ref RE: Regex = Regex::new(r"^\#\s?(\S+)\s*$").unwrap(); +fn replace_full_import(x: &str) -> Option { + FULL_IMPORTS_MAP.get(x).map(|x| (*x).to_owned()) } -fn process_import(module: Option, path: &str, level: usize) -> Vec { +lazy_static! { + static ref RE: Regex = Regex::new(r"^\#\s?(\S+)\s*$").unwrap(); + static ref PIN_RE: Regex = Regex::new(r"(?:\s*#\s*(pin|repin):\s*)(\S*)").unwrap(); +} + +fn process_import(module: Option, path: &str, level: usize) -> Vec { if level > 0 { let mut imports = vec![]; let splitted_path = path.split("/"); @@ -89,17 +55,18 @@ fn process_import(module: Option, path: &str, level: usize) -> Vec error::Result Some(path), + _ => None, }) .collect()); } -fn parse_code_for_imports(code: &str, path: &str) -> error::Result> { +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +enum NImport { + // Order matters! First we want to resolve all repins + + // manually repinned requirement + // e.g.: + // import pandas # repin: pandas==x.y.z + Repin { + pin: ImportPin, + key: String, + }, + // manually pinned requirements + // e.g.: + // import pandas # pin: pandas>=x.y.z + // import pandas # pin: pandas<=x.y.z + // + // NOTE: It is possible for multiple pins exist on same import + // That's why we store vector of pins + Pin { + pins: Vec, + key: String, + }, + // Automatically inferred requirement + // e.g.: + // import pandas + Auto { + // Take `x.y.z` for example + // x is going to be the `root` + // and x.y.z is `full` + // + // `full` will be None if it is equal to root + // + // We will use `root` as a requirement name and pass to `uv pip compile` if it was not replaced with any pin + pkg: String, + + // However we still need full, since all pins pin against full import names + key: Option, + }, + // Relative imports + Relative(String), +} +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +enum NImportResolved { + Repin { pin: ImportPin, key: String }, + Pin { pins: Vec, key: String }, + Auto { pkg: String, key: Option }, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +struct ImportPin { + pkg: String, + path: String, +} + +fn parse_code_for_imports(code: &str, path: &str) -> error::Result> { let mut code = code.split(DEF_MAIN).next().unwrap_or("").to_string(); // remove main function decorator from end of file if it exists @@ -141,19 +159,56 @@ fn parse_code_for_imports(code: &str, path: &str) -> error::Result> let ast = Suite::parse(&code, "main.py").map_err(|e| { error::Error::ExecutionErr(format!("Error parsing code for imports: {}", e.to_string())) })?; - let nimports: Vec = ast + + let find_pin = |range: TextRange, key: String| { + let hs = code + .chars() + .skip(range.end().to_usize()) + .take_while(|e| *e != '\n') + .collect::(); + + if hs.trim_start().is_empty(){ + return None; + } + + PIN_RE + .captures(&hs) + .and_then(|x| { + x.get(1).zip(x.get(2)).and_then(|(ty_m, pkg_m)| { + let pkg = pkg_m.as_str().to_owned(); + if ty_m.as_str() == "pin" { + Some(vec![NImport::Pin { + pins: vec![ImportPin { pkg, path: path.to_owned() }], + key, + }]) + } else if ty_m.as_str() == "repin" { + Some(vec![NImport::Repin { + pin: ImportPin { pkg, path: path.to_owned() }, + key, + }]) + } else { + None + } + }) + }) + }; + + let mut nimports: Vec = ast .into_iter() .filter_map(|x| match x { - Stmt::Import(StmtImport { names, .. }) => Some( - names - .into_iter() - .map(|x| { - let name = x.name.to_string(); - process_import(Some(name), path, 0) - }) - .flatten() - .collect::>(), - ), + Stmt::Import(StmtImport { names, range }) => names + .get(0) + .and_then(|al| find_pin(range, al.name.to_string())) + .or(Some( + names + .into_iter() + .map(|x| { + let name = x.name.to_string(); + process_import(Some(name), path, 0) + }) + .flatten() + .collect::>(), + )), Stmt::ImportFrom(StmtImportFrom { level: Some(i), module, .. }) if i.to_u32() > 0 => { Some(process_import( module.map(|x| x.to_string()), @@ -161,15 +216,25 @@ fn parse_code_for_imports(code: &str, path: &str) -> error::Result> i.to_usize(), )) } - Stmt::ImportFrom(StmtImportFrom { level: _, module, .. }) => { - Some(process_import(module.map(|x| x.to_string()), path, 0)) - } + Stmt::ImportFrom(StmtImportFrom { level: _, module, range, .. }) => find_pin( + range, + module.clone().map(|x| x.to_string()).unwrap_or_default(), + ) + .or(Some(process_import(module.map(|x| x.to_string()), path, 0))), _ => None, }) .flatten() - .filter(|x| !STDIMPORTS.contains(&x.as_str())) + .filter(|x| { + if let NImport::Auto { ref pkg, .. } = x { + !STDIMPORTS.contains(&(*pkg).as_str()) + } else { + true + } + }) .unique() .collect(); + + nimports.sort(); return Ok(nimports); } @@ -180,8 +245,9 @@ pub async fn parse_python_imports( db: &Pool, already_visited: &mut Vec, annotated_pyv_numeric: &mut Option, -) -> error::Result> { - parse_python_imports_inner( +) -> error::Result<(Vec, Option)> { + let mut compile_error_hint: Option = None; + let mut imports = parse_python_imports_inner( code, w_id, path, @@ -190,7 +256,32 @@ pub async fn parse_python_imports( annotated_pyv_numeric, &mut annotated_pyv_numeric.and_then(|_| Some(path.to_owned())), ) - .await + .await? + .into_values() + .map(|nimport| match nimport { + NImportResolved::Pin { pins, .. } => pins.into_iter().map(|p| { + if let Some(hint) = &mut compile_error_hint{ + hint.push_str(&format!("\n - pin to {} in {}", p.pkg, p.path)); + } else { + compile_error_hint = Some("\n\nMultiple pins can cause problems during lockfile resolution.\nMake sure you checked every pin for conflicts:\n".into()) + }; + Ok(p.pkg) + }).collect_vec(), + NImportResolved::Repin { pin: ImportPin { pkg, .. }, .. } => vec![Ok(pkg)], + NImportResolved::Auto { pkg, ..} => vec![Ok(pkg)], + }) + .flatten() + .collect::>>()? + .into_iter() + .unique() + .collect_vec(); + + imports.sort(); + + compile_error_hint + .as_mut() + .map(|e| e.push_str("\n\nNOTE: You can also `repin` to override all pins")); + Ok((imports, compile_error_hint)) } #[async_recursion] @@ -202,7 +293,7 @@ async fn parse_python_imports_inner( already_visited: &mut Vec, annotated_pyv_numeric: &mut Option, path_where_annotated_pyv: &mut Option, -) -> error::Result> { +) -> error::Result> { let PythonAnnotations { py310, py311, py312, py313, .. } = PythonAnnotations::parse(&code); // we pass only if there is none or only one annotation @@ -231,7 +322,6 @@ async fn parse_python_imports_inner( } else { *annotated_pyv_numeric = Some(numeric); } - *path_where_annotated_pyv = Some(path.to_owned()); } Ok(()) @@ -246,74 +336,205 @@ async fn parse_python_imports_inner( .lines() .find_position(|x| x.starts_with("#requirements:") || x.starts_with("# requirements:")); if let Some((pos, _)) = find_requirements { - let lines = code - .lines() + let mut requirements = HashMap::new(); + code.lines() .skip(pos + 1) .map_while(|x| { - RE.captures(x) - .map(|x| x.get(1).unwrap().as_str().to_string()) + RE.captures(x).and_then(|x| { + x.get(1).map(|m| { + let requirement = m.as_str().to_string(); + requirements.insert( + requirement.clone(), + NImportResolved::Repin { + pin: ImportPin { pkg: requirement, path: Default::default() }, + key: Default::default(), + }, + ); + }) + }) }) - .collect(); - Ok(lines) + .collect_vec(); + + Ok(requirements) } else { let find_extra_requirements = code.lines().find_position(|x| { x.starts_with("#extra_requirements:") || x.starts_with("# extra_requirements:") }); - let mut imports: Vec = vec![]; + let mut imports: HashMap = HashMap::new(); if let Some((pos, _)) = find_extra_requirements { - let lines: Vec = code - .lines() + code.lines() .skip(pos + 1) .map_while(|x| { - RE.captures(x) - .map(|x| x.get(1).unwrap().as_str().to_string()) + RE.captures(x).and_then(|x| { + x.get(1).map(|m| { + let requirement = m.as_str().to_string(); + imports.insert( + requirement.clone(), + NImportResolved::Auto { key: None, pkg: requirement }, + ); + }) + }) }) - .collect(); - imports.extend(lines); + .collect_vec(); } - let nimports = parse_code_for_imports(code, path)?; - for n in nimports.iter() { - let nested = if n.starts_with("relative:") { - let rpath = n.replace("relative:", ""); - let code = sqlx::query_scalar!( - r#" - SELECT content FROM script WHERE path = $1 AND workspace_id = $2 - AND created_at = (SELECT max(created_at) FROM script WHERE path = $1 AND - workspace_id = $2) - "#, - &rpath, - w_id - ) - .fetch_optional(db) - .await? - .unwrap_or_else(|| "".to_string()); + // Will get unsorted vector of imports found in current script + let mut nimports = parse_code_for_imports(code, path)?; - if already_visited.contains(&rpath) { - vec![] - } else { - already_visited.push(rpath.clone()); - parse_python_imports_inner( - &code, - w_id, + // It is important to note, that sorting is important and will always result in this pattern: + // 1. All Repins go first + // 2. All Pins go second + // 3. All Auto go third + // 4. All relative imports go the last + // + // This way we make sure all repins are resolved before (re)pins inside imported relative scripts. + nimports.sort(); + + for n in nimports.into_iter() { + let mut nested = match n { + NImport::Relative(rpath) => { + let code = sqlx::query_scalar!( + r#" + SELECT content FROM script WHERE path = $1 AND workspace_id = $2 + AND created_at = (SELECT max(created_at) FROM script WHERE path = $1 AND + workspace_id = $2) + "#, &rpath, - db, - already_visited, - annotated_pyv_numeric, - path_where_annotated_pyv, + w_id ) + .fetch_optional(db) .await? + .unwrap_or_else(|| "".to_string()); + + if already_visited.contains(&rpath) { + vec![] + } else { + already_visited.push(rpath.clone()); + // Because the algo goes depth first, this function will never return relative import + // This why we can safely assume later, that there is no relative imports + parse_python_imports_inner( + &code, + w_id, + &rpath, + db, + already_visited, + annotated_pyv_numeric, + path_where_annotated_pyv, + ) + .await? + .into_values() + .collect_vec() + } } - } else { - vec![replace_import(n.to_string())] + NImport::Repin { pin, key } => vec![NImportResolved::Repin { pin, key }], + NImport::Pin { pins, key } => vec![NImportResolved::Pin { pins, key }], + NImport::Auto { pkg, key } => vec![NImportResolved::Auto { pkg, key }], }; + + // Nested should also be sorted for the same reason + nested.sort(); + + // At this point there should be no NImport::Relative in `nested` for imp in nested { - if !imports.contains(&imp) { - imports.push(imp); + let key = match imp.clone() { + NImportResolved::Pin { key, .. } => key, + NImportResolved::Repin { key, .. } => key, + NImportResolved::Auto { key, pkg } => key.unwrap_or(pkg), + }; + // Handled cases: + // + // 1. + // Error: Imported windmill scripts have different pins + // + // auto + // ├── pin:2 + // └── pin:1 + // + // Fix 1: + // + // auto + // ├── pin:1 + // └── pin:1 + // + // Fix 2: + // + // repin:1 + // ├── pin:2 + // └── pin:1 + // + // 2. + // Error: Imported windmill scripts have different pins + // + // pin:2 + // └── pin:1 + // + // Fix 1: + // + // auto + // └── pin:1 + // + // Fix 2: + // + // repin:2 + // └── pin:1 + // + // 3. repins allowed to be repinned again + // + // repin:2 + // └── repin:1 + // + match imp.clone() { + NImportResolved::Repin { .. } => { + if let Some(existing_import) = imports.get(&key) { + match existing_import { + // replace + p if matches!( + p, + NImportResolved::Pin { .. } | NImportResolved::Auto { .. } + ) => + { + imports.insert(key, imp); + } + // do nothing (older repins have greater precedence) + NImportResolved::Repin { .. } => {} + // Should not be possible + _ => { + return Err(anyhow::anyhow!( + "Internal error: cannot resolve requirement pins", + ) + .into()); + } + } + } else { + imports.insert(key, imp.clone()); + } + } + NImportResolved::Pin { pins: new_pins, .. } => { + if let Some(existing_import) = imports.get_mut(&key) { + match existing_import { + // Check if pin is the same version, if same, do nothing, if not error + NImportResolved::Pin { pins: existing_pins, .. } => { + existing_pins.extend(new_pins) + } + // do nothing + NImportResolved::Repin { .. } => {} + // Replace with new pin + NImportResolved::Auto { .. } => { + imports.insert(key, imp); + } + } + } else { + imports.insert(key, imp.clone()); + } + } + NImportResolved::Auto { .. } => { + if !imports.contains_key(&key) { + imports.insert(key, imp); + } + } } } } - imports.sort(); Ok(imports) } } diff --git a/backend/parsers/windmill-parser-py-imports/src/mapping.rs b/backend/parsers/windmill-parser-py-imports/src/mapping.rs new file mode 100644 index 0000000000..11677ffbfd --- /dev/null +++ b/backend/parsers/windmill-parser-py-imports/src/mapping.rs @@ -0,0 +1,380 @@ +/* + * Author: Ruben Fiszel + * Copyright: Windmill Labs, Inc 2022 + * This file and its contents are licensed under the AGPLv3 License. + * Please see the included NOTICE for copyright information and + * LICENSE-AGPL for a copy of the license. + */ + +use phf::phf_map; +type PyMap = phf::Map<&'static str, &'static str>; + +/// In some cases inferring requirement from import is not possible. +/// That's why we need to map import to requirement ident. +/// These two maps allows us to do so. + +/// import x.y.z +/// ^^^^^ replaces entire x.y.z import with [?] +/// +pub static FULL_IMPORTS_MAP: PyMap = phf_map! { + // import => requirement + "google.cloud.bigquery_storage" => "google-cloud-bigquery-storage", + "google.cloud.bigquery" => "google-cloud-bigquery", + "google.cloud.parametermanager" => "google-cloud-parametermanager", + "google.cloud.oracledatabase" => "google-cloud-oracledatabase", + "google.cloud.deploy" => "google-cloud-deploy", + "google.cloud.pubsub" => "google-cloud-pubsub", + "google.cloud.workflows" => "google-cloud-workflows", + "google.cloud.managedkafka" => "google-cloud-managedkafka", + "google.cloud.iam" => "google-cloud-iam", + "google.cloud.documentai" => "google-cloud-documentai", + "google.cloud.dlp" => "google-cloud-dlp", + "google.cloud.compute" => "google-cloud-compute", + "google.cloud.alloydb" => "google-cloud-alloydb", + "google.cloud.aiplatform" => "google-cloud-aiplatform", + "google.cloud.bigtable" => "google-cloud-bigtable", + "google.cloud.workstations" => "google-cloud-workstations", + "google.cloud.websecurityscanner" => "google-cloud-websecurityscanner", + "google.cloud.webrisk" => "google-cloud-webrisk", + "google.cloud.vmwareengine" => "google-cloud-vmwareengine", + "google.cloud.visionai" => "google-cloud-visionai", + "google.cloud.vision" => "google-cloud-vision", + "google.cloud.videointelligence" => "google-cloud-videointelligence", + "google.cloud.translate" => "google-cloud-translate", + "google.cloud.trace" => "google-cloud-trace", + "google.cloud.tpu" => "google-cloud-tpu", + "google.cloud.texttospeech" => "google-cloud-texttospeech", + "google.cloud.telcoautomation" => "google-cloud-telcoautomation", + "google.cloud.tasks" => "google-cloud-tasks", + "google.cloud.talent" => "google-cloud-talent", + "google.cloud.support" => "google-cloud-support", + "google.cloud.storageinsights" => "google-cloud-storageinsights", + "google.cloud.speech" => "google-cloud-speech", + "google.cloud.shell" => "google-cloud-shell", + "google.cloud.servicehealth" => "google-cloud-servicehealth", + "google.cloud.securitycentermanagement" => "google-cloud-securitycentermanagement", + "google.cloud.securitycenter" => "google-cloud-securitycenter", + "google.cloud.securesourcemanager" => "google-cloud-securesourcemanager", + "google.cloud.scheduler" => "google-cloud-scheduler", + "google.cloud.run" => "google-cloud-run", + "google.cloud.retail" => "google-cloud-retail", + "google.cloud.recommender" => "google-cloud-recommender", + "google.cloud.rapidmigrationassessment" => "google-cloud-rapidmigrationassessment", + "google.cloud.privilegedaccessmanager" => "google-cloud-privilegedaccessmanager", + "google.cloud.policytroubleshooter_iam" => "google-cloud-policytroubleshooter-iam", + "google.cloud.policysimulator" => "google-cloud-policysimulator", + "google.cloud.parallelstore" => "google-cloud-parallelstore", + "google.cloud.optimization" => "google-cloud-optimization", + "google.cloud.notebooks" => "google-cloud-notebooks", + "google.cloud.network_services" => "google-cloud-network-services", + "google.cloud.network_security" => "google-cloud-network-security", + "google.cloud.netapp" => "google-cloud-netapp", + "google.cloud.monitoring" => "google-cloud-monitoring", + "google.cloud.modelarmor" => "google-cloud-modelarmor", + "google.cloud.migrationcenter" => "google-cloud-migrationcenter", + "google.cloud.memorystore" => "google-cloud-memorystore", + "google.cloud.memcache" => "google-cloud-memcache", + "google.cloud.language" => "google-cloud-language", + "google.cloud.kms" => "google-cloud-kms", + "google.cloud.kms_inventory" => "google-cloud-kms-inventory", + "google.cloud.ids" => "google-cloud-ids", + "google.cloud.iap" => "google-cloud-iap", + "google.cloud.gsuiteaddons" => "google-cloud-gsuiteaddons", + "google.cloud.gke_multicloud" => "google-cloud-gke-multicloud", + "google.cloud.gke_backup" => "google-cloud-gke-backup", + "google.cloud.gdchardwaremanagement" => "google-cloud-gdchardwaremanagement", + "google.cloud.functions" => "google-cloud-functions", + "google.cloud.financialservices" => "google-cloud-financialservices", + "google.cloud.filestore" => "google-cloud-filestore", + "google.cloud.eventarc" => "google-cloud-eventarc", + "google.cloud.eventarc_publishing" => "google-cloud-eventarc-publishing", + "google.cloud.essential_contacts" => "google-cloud-essential-contacts", + "google.cloud.enterpriseknowledgegraph" => "google-cloud-enterpriseknowledgegraph", + "google.cloud.edgenetwork" => "google-cloud-edgenetwork", + "google.cloud.edgecontainer" => "google-cloud-edgecontainer", + "google.cloud.domains" => "google-cloud-domains", + "google.cloud.discoveryengine" => "google-cloud-discoveryengine", + "google.cloud.dialogflow" => "google-cloud-dialogflow", + "google.cloud.developerconnect" => "google-cloud-developerconnect", + "google.cloud.datastream" => "google-cloud-datastream", + "google.cloud.dataproc" => "google-cloud-dataproc", + "google.cloud.dataplex" => "google-cloud-dataplex", + "google.cloud.datalabeling" => "google-cloud-datalabeling", + "google.cloud.dataform" => "google-cloud-dataform", + "google.cloud.datacatalog" => "google-cloud-datacatalog", + "google.cloud.datacatalog_lineage" => "google-cloud-datacatalog-lineage", + "google.cloud.data_fusion" => "google-cloud-data-fusion", + "google.cloud.contentwarehouse" => "google-cloud-contentwarehouse", + "google.cloud.container" => "google-cloud-container", + "google.cloud.config" => "google-cloud-config", + "google.cloud.confidentialcomputing" => "google-cloud-confidentialcomputing", + "google.cloud.common" => "google-cloud-common", + "google.cloud.cloudcontrolspartner" => "google-cloud-cloudcontrolspartner", + "google.cloud.channel" => "google-cloud-channel", + "google.cloud.certificate_manager" => "google-cloud-certificate-manager", + "google.cloud.billing" => "google-cloud-billing", + "google.cloud.bigquery_migration" => "google-cloud-bigquery-migration", + "google.cloud.bigquery_logging" => "google-cloud-bigquery-logging", + "google.cloud.bigquery_datatransfer" => "google-cloud-bigquery-datatransfer", + "google.cloud.bigquery_datapolicies" => "google-cloud-bigquery-datapolicies", + "google.cloud.bigquery_connection" => "google-cloud-bigquery-connection", + "google.cloud.bigquery_biglake" => "google-cloud-bigquery-biglake", + "google.cloud.bigquery_analyticshub" => "google-cloud-bigquery-analyticshub", + "google.cloud.beyondcorp_clientgateways" => "google-cloud-beyondcorp-clientgateways", + "google.cloud.beyondcorp_clientconnectorservices" => "google-cloud-beyondcorp-clientconnectorservices", + "google.cloud.beyondcorp_appgateways" => "google-cloud-beyondcorp-appgateways", + "google.cloud.beyondcorp_appconnectors" => "google-cloud-beyondcorp-appconnectors", + "google.cloud.beyondcorp_appconnections" => "google-cloud-beyondcorp-appconnections", + "google.cloud.batch" => "google-cloud-batch", + "google.cloud.bare_metal_solution" => "google-cloud-bare-metal-solution", + "google.cloud.backupdr" => "google-cloud-backupdr", + "google.cloud.automl" => "google-cloud-automl", + "google.cloud.asset" => "google-cloud-asset", + "google.cloud.apphub" => "google-cloud-apphub", + "google.cloud.apihub" => "google-cloud-apihub", + "google.cloud.advisorynotifications" => "google-cloud-advisorynotifications", + "google.cloud.spanner" => "google-cloud-spanner", + "google.cloud.storage" => "google-cloud-storage", + "google.cloud.firestore" => "google-cloud-firestore", + "google.cloud.pubsublite" => "google-cloud-pubsublite", + "google.cloud.datastore" => "google-cloud-datastore", + "google.cloud.ndb" => "google-cloud-ndb", + "google.cloud.dns" => "google-cloud-dns", + "google.cloud.runtimeconfig" => "google-cloud-runtimeconfig", + "google.cloud.iot" => "google-cloud-iot", + // Azure + "azure.mgmt.hybridkubernetes" => "azure-mgmt-hybridkubernetes", + "azure.mgmt.sql" => "azure-mgmt-sql", + "azure.mgmt.compute" => "azure-mgmt-compute", + "azure.mgmt.eventgrid" => "azure-mgmt-eventgrid", + "azure.mgmt.containerservice" => "azure-mgmt-containerservice", + "azure.mgmt.databox" => "azure-mgmt-databox", + "azure.mgmt.keyvault" => "azure-mgmt-keyvault", + "azure.mgmt.applicationinsights" => "azure-mgmt-applicationinsights", + "azure.mgmt.storage" => "azure-mgmt-storage", + "azure.mgmt.quota" => "azure-mgmt-quota", + "azure.mgmt.nginx" => "azure-mgmt-nginx", + "azure.mgmt.netapp" => "azure-mgmt-netapp", + "azure.mgmt.resource" => "azure-mgmt-resource", + "azure.mgmt.containerregistry" => "azure-mgmt-containerregistry", + "azure.mgmt.databoxedge" => "azure-mgmt-databoxedge", + "azure.mgmt.logz" => "azure-mgmt-logz", + "azure.mgmt.monitor" => "azure-mgmt-monitor", + "azure.mgmt.servicenetworking" => "azure-mgmt-servicenetworking", + "azure.mgmt.kusto" => "azure-mgmt-kusto", + "azure.mgmt.web" => "azure-mgmt-web", + "azure.mgmt.eventhub" => "azure-mgmt-eventhub", + "azure.mgmt.redis" => "azure-mgmt-redis", + "azure.mgmt.cosmosdb" => "azure-mgmt-cosmosdb", + "azure.mgmt.network" => "azure-mgmt-network", + "azure.mgmt.cognitiveservices" => "azure-mgmt-cognitiveservices", + "azure.mgmt.servicefabricmanagedclusters" => "azure-mgmt-servicefabricmanagedclusters", + "azure.mgmt.datafactory" => "azure-mgmt-datafactory", + "azure.mgmt.hybridcompute" => "azure-mgmt-hybridcompute", + "azure.mgmt.servicebus" => "azure-mgmt-servicebus", + "azure.mgmt.marketplaceordering" => "azure-mgmt-marketplaceordering", + "azure.mgmt.managedservices" => "azure-mgmt-managedservices", + "azure.mgmt.managementgroups" => "azure-mgmt-managementgroups", + "azure.mgmt.loganalytics" => "azure-mgmt-loganalytics", + "azure.mgmt.automation" => "azure-mgmt-automation", + "azure.mgmt.devtestlabs" => "azure-mgmt-devtestlabs", + "azure.mgmt.documentdb" => "azure-mgmt-documentdb", + "azure.mgmt.scheduler" => "azure-mgmt-scheduler", + "azure.mgmt.core" => "azure-mgmt-core", + "azure.mgmt.servermanager" => "azure-mgmt-servermanager", + "azure.mgmt.batchai" => "azure-mgmt-batchai", + "azure.mgmt.extendedlocation" => "azure-mgmt-extendedlocation", + "azure.mgmt.digitaltwins" => "azure-mgmt-digitaltwins", + "azure.mgmt.appconfiguration" => "azure-mgmt-appconfiguration", + "azure.mgmt.edgeorder" => "azure-mgmt-edgeorder", + "azure.mgmt.resourcehealth" => "azure-mgmt-resourcehealth", + "azure.mgmt.redhatopenshift" => "azure-mgmt-redhatopenshift", + "azure.mgmt.appplatform" => "azure-mgmt-appplatform", + "azure.mgmt.appcontainers" => "azure-mgmt-appcontainers", + "azure.mgmt.elastic" => "azure-mgmt-elastic", + "azure.mgmt.dnsresolver" => "azure-mgmt-dnsresolver", + "azure.mgmt.containerinstance" => "azure-mgmt-containerinstance", + "azure.mgmt.elasticsan" => "azure-mgmt-elasticsan", + "azure.mgmt.dns" => "azure-mgmt-dns", + "azure.mgmt.redisenterprise" => "azure-mgmt-redisenterprise", + "azure.mgmt.servicelinker" => "azure-mgmt-servicelinker", + "azure.mgmt.rdbms" => "azure-mgmt-rdbms", + "azure.mgmt.batch" => "azure-mgmt-batch", + "azure.mgmt.avs" => "azure-mgmt-avs", + "azure.mgmt.webpubsub" => "azure-mgmt-webpubsub", + "azure.mgmt.desktopvirtualization" => "azure-mgmt-desktopvirtualization", + "azure.mgmt.privatedns" => "azure-mgmt-privatedns", + "azure.mgmt.hdinsight" => "azure-mgmt-hdinsight", + "azure.mgmt.billing" => "azure-mgmt-billing", + "azure.mgmt.azurestackhci" => "azure-mgmt-azurestackhci", + "azure.mgmt.dataprotection" => "azure-mgmt-dataprotection", + "azure.mgmt.search" => "azure-mgmt-search", + "azure.mgmt.appcomplianceautomation" => "azure-mgmt-appcomplianceautomation", + "azure.mgmt.scvmm" => "azure-mgmt-scvmm", + "azure.mgmt.powerbiembedded" => "azure-mgmt-powerbiembedded", + "azure.mgmt.imagebuilder" => "azure-mgmt-imagebuilder", + "azure.mgmt.storagemover" => "azure-mgmt-storagemover", + "azure.mgmt.mobilenetwork" => "azure-mgmt-mobilenetwork", + "azure.mgmt.cdn" => "azure-mgmt-cdn", + "azure.mgmt.storagecache" => "azure-mgmt-storagecache", + "azure.mgmt.maintenance" => "azure-mgmt-maintenance", + "azure.mgmt.security" => "azure-mgmt-security", + "azure.mgmt.devcenter" => "azure-mgmt-devcenter", + "azure.mgmt.support" => "azure-mgmt-support", + "azure.mgmt.recoveryservicesbackup" => "azure-mgmt-recoveryservicesbackup", + "azure.mgmt.recoveryservices" => "azure-mgmt-recoveryservices", + "azure.mgmt.confidentialledger" => "azure-mgmt-confidentialledger", + "azure.mgmt.healthcareapis" => "azure-mgmt-healthcareapis", + "azure.mgmt.frontdoor" => "azure-mgmt-frontdoor", + "azure.mgmt.notificationhubs" => "azure-mgmt-notificationhubs", + "azure.mgmt.quantum" => "azure-mgmt-quantum", + "azure.mgmt.apimanagement" => "azure-mgmt-apimanagement", + "azure.mgmt.communication" => "azure-mgmt-communication", + "azure.mgmt.newrelicobservability" => "azure-mgmt-newrelicobservability", + "azure.mgmt.confluent" => "azure-mgmt-confluent", + "azure.mgmt.chaos" => "azure-mgmt-chaos", + "azure.mgmt.recoveryservicessiterecovery" => "azure-mgmt-recoveryservicessiterecovery", + "azure.mgmt.servicefabric" => "azure-mgmt-servicefabric", + "azure.mgmt.hybridcontainerservice" => "azure-mgmt-hybridcontainerservice", + "azure.mgmt.streamanalytics" => "azure-mgmt-streamanalytics", + "azure.mgmt.deviceupdate" => "azure-mgmt-deviceupdate", + "azure.mgmt.hybridnetwork" => "azure-mgmt-hybridnetwork", + "azure.mgmt.dashboard" => "azure-mgmt-dashboard", + "azure.mgmt.connectedvmware" => "azure-mgmt-connectedvmware", + "azure.mgmt.datadog" => "azure-mgmt-datadog", + "azure.mgmt.baremetalinfrastructure" => "azure-mgmt-baremetalinfrastructure", + "azure.mgmt.signalr" => "azure-mgmt-signalr", + "azure.mgmt.resourcemover" => "azure-mgmt-resourcemover", + "azure.mgmt.kubernetesconfiguration" => "azure-mgmt-kubernetesconfiguration", + "azure.mgmt.iothub" => "azure-mgmt-iothub", + "azure.mgmt.maps" => "azure-mgmt-maps", + "azure.mgmt.devspaces" => "azure-mgmt-devspaces", + "azure.mgmt.dynatrace" => "azure-mgmt-dynatrace", + "azure.mgmt.resourceconnector" => "azure-mgmt-resourceconnector", + "azure.mgmt.authorization" => "azure-mgmt-authorization", + "azure.mgmt.costmanagement" => "azure-mgmt-costmanagement", + "azure.mgmt.databricks" => "azure-mgmt-databricks", + "azure.mgmt.graphservices" => "azure-mgmt-graphservices", + "azure.mgmt.iothubprovisioningservices" => "azure-mgmt-iothubprovisioningservices", + "azure.mgmt.sqlvirtualmachine" => "azure-mgmt-sqlvirtualmachine", + "azure.mgmt.trafficmanager" => "azure-mgmt-trafficmanager", + "azure.mgmt.agfood" => "azure-mgmt-agfood", + "azure.mgmt.azureadb2c" => "azure-mgmt-azureadb2c", + "azure.mgmt.voiceservices" => "azure-mgmt-voiceservices", + "azure.mgmt.machinelearningservices" => "azure-mgmt-machinelearningservices", + "azure.mgmt.workloads" => "azure-mgmt-workloads", + "azure.mgmt.reservations" => "azure-mgmt-reservations", + "azure.mgmt.orbital" => "azure-mgmt-orbital", + "azure.mgmt.defendereasm" => "azure-mgmt-defendereasm", + "azure.mgmt.msi" => "azure-mgmt-msi", + "azure.mgmt.synapse" => "azure-mgmt-synapse", + "azure.mgmt.commerce" => "azure-mgmt-commerce", + "azure.mgmt.loadtesting" => "azure-mgmt-loadtesting", + "azure.mgmt.botservice" => "azure-mgmt-botservice", + "azure.mgmt.media" => "azure-mgmt-media", + "azure.mgmt.securitydevops" => "azure-mgmt-securitydevops", + "azure.mgmt.policyinsights" => "azure-mgmt-policyinsights", + "azure.mgmt.securityinsight" => "azure-mgmt-securityinsight", + "azure.mgmt.subscription" => "azure-mgmt-subscription", + "azure.mgmt.agrifood" => "azure-mgmt-agrifood", + "azure.mgmt.resourcegraph" => "azure-mgmt-resourcegraph", + "azure.mgmt.alertsmanagement" => "azure-mgmt-alertsmanagement", + "azure.mgmt.labservices" => "azure-mgmt-labservices", + "azure.mgmt.fluidrelay" => "azure-mgmt-fluidrelay", + "azure.mgmt.automanage" => "azure-mgmt-automanage", + "azure.mgmt.billingbenefits" => "azure-mgmt-billingbenefits", + "azure.mgmt.education" => "azure-mgmt-education", + "azure.mgmt.consumption" => "azure-mgmt-consumption", + "azure.mgmt.workloadmonitor" => "azure-mgmt-workloadmonitor", + "azure.mgmt.iotcentral" => "azure-mgmt-iotcentral", + "azure.mgmt.datamigration" => "azure-mgmt-datamigration", + "azure.mgmt.azurearcdata" => "azure-mgmt-azurearcdata", + "azure.mgmt.azurestack" => "azure-mgmt-azurestack", + "azure.mgmt.networkfunction" => "azure-mgmt-networkfunction", + "azure.mgmt.oep" => "azure-mgmt-oep", + "azure.mgmt.storagepool" => "azure-mgmt-storagepool", + "azure.mgmt.relay" => "azure-mgmt-relay", + "azure.mgmt.purview" => "azure-mgmt-purview", + "azure.mgmt.vmwarecloudsimple" => "azure-mgmt-vmwarecloudsimple", + "azure.mgmt.guestconfig" => "azure-mgmt-guestconfig", + "azure.mgmt.testbase" => "azure-mgmt-testbase", + "azure.mgmt.logic" => "azure-mgmt-logic", + "azure.mgmt.storageimportexport" => "azure-mgmt-storageimportexport", + "azure.mgmt.managementpartner" => "azure-mgmt-managementpartner", + "azure.mgmt.serialconsole" => "azure-mgmt-serialconsole", + "azure.mgmt.portal" => "azure-mgmt-portal", + "azure.mgmt.deploymentmanager" => "azure-mgmt-deploymentmanager", + "azure.mgmt.machinelearningcompute" => "azure-mgmt-machinelearningcompute", + "azure.mgmt.mixedreality" => "azure-mgmt-mixedreality", + "azure.mgmt.peering" => "azure-mgmt-peering", + "azure.mgmt.storagesync" => "azure-mgmt-storagesync", + "azure.mgmt.customproviders" => "azure-mgmt-customproviders", + "azure.mgmt.hanaonazure" => "azure-mgmt-hanaonazure", + "azure.mgmt.datashare" => "azure-mgmt-datashare", + "azure.mgmt.powerbidedicated" => "azure-mgmt-powerbidedicated", + "azure.mgmt.timeseriesinsights" => "azure-mgmt-timeseriesinsights", + "azure.mgmt.healthbot" => "azure-mgmt-healthbot", + "azure.mgmt.attestation" => "azure-mgmt-attestation", + "azure.mgmt.advisor" => "azure-mgmt-advisor", + "azure.mgmt.operationsmanagement" => "azure-mgmt-operationsmanagement", + "azure.mgmt.videoanalyzer" => "azure-mgmt-videoanalyzer", + "azure.mgmt.app" => "azure-mgmt-app", + "azure.mgmt.changeanalysis" => "azure-mgmt-changeanalysis", + "azure.mgmt.regionmove" => "azure-mgmt-regionmove", + "azure.mgmt.edgegateway" => "azure-mgmt-edgegateway", + "azure.mgmt.nspkg" => "azure-mgmt-nspkg", + "azure.keyvault.secrets" => "azure-keyvault-secrets", + "azure.storage.blob" => "azure-storage-blob", + // Add new entry here ^ +}; + +/// import x.y.z +/// ^ replaces x with [?] +/// +/// Additional rules: +/// 1. in x "_" are replaced with "-" +/// 2. If full imports had a hit, this one will not be called +pub static SHORT_IMPORTS_MAP: PyMap = phf_map! { + // import => requirement + "psycopg2" => "psycopg2-binary", + "psycopg" => "psycopg[binary, pool]", + "yaml" => "pyyaml", + "git" => "GitPython", + "shopify" => "ShopifyAPI", + "seleniumwire" => "selenium-wire", + "openbb-terminal" => "openbb[all]", + "riskfolio" => "riskfolio-lib", + "smb" => "pysmb", + "PIL" => "Pillow", + "googleapiclient" => "google-api-python-client", + "googlecloudbigquery" => "google-cloud-bigquery", + "dateutil" => "python-dateutil", + "mailparser" => "mail-parser", + "mailparser-reply" => "mail-parser-reply", + "gitlab" => "python-gitlab", + "smbclient" => "smbprotocol", + "playhouse" => "peewee", + "dns" => "dnspython", + "msoffcrypto" => "msoffcrypto-tool", + "tabula" => "tabula-py", + "shapefile" => "pyshp", + "sklearn" => "scikit-learn", + "umap" => "umap-learn", + "cv2" => "opencv-python", + "atlassian" => "atlassian-python-api", + "mysql" => "mysql-connector-python", + "tenable" => "pytenable", + "ns1" => "ns1-python", + "pymsql" => "PyMySQL", + "haystack" => "haystack-ai", + "github" => "PyGithub", + "ldap" => "python-ldap", + "opensearchpy" => "opensearch-py", + "lokalise" => "python-lokalise-api", + "msgraph" => "msgraph-sdk", + "pythonjsonlogger" => "python-json-logger", + "socks" => "PySocks", + "taiga" => "python-taiga", + "docx" => "python-docx", + // Add new entry here ^ +}; diff --git a/backend/parsers/windmill-parser-py-imports/tests/tests.rs b/backend/parsers/windmill-parser-py-imports/tests/tests.rs index a634f247dd..d734cb8ead 100644 --- a/backend/parsers/windmill-parser-py-imports/tests/tests.rs +++ b/backend/parsers/windmill-parser-py-imports/tests/tests.rs @@ -19,7 +19,7 @@ def main(): "; let mut already_visited = vec![]; - let r = parse_python_imports( + let (r, ..) = parse_python_imports( code, "test-workspace", "f/foo/bar", @@ -52,7 +52,7 @@ def main(): "; let mut already_visited = vec![]; - let r = parse_python_imports( + let (r, ..) = parse_python_imports( code, "test-workspace", "f/foo/bar", @@ -83,7 +83,7 @@ def main(): "; let mut already_visited = vec![]; - let r = parse_python_imports( + let (r, ..) = parse_python_imports( code, "test-workspace", "f/foo/bar", diff --git a/backend/parsers/windmill-parser-wasm/Cargo.toml b/backend/parsers/windmill-parser-wasm/Cargo.toml index fe450c32b4..5b1c884143 100644 --- a/backend/parsers/windmill-parser-wasm/Cargo.toml +++ b/backend/parsers/windmill-parser-wasm/Cargo.toml @@ -28,6 +28,7 @@ graphql-parser = [ "dep:windmill-parser-graphql"] ansible-parser = [ "dep:windmill-parser-yaml"] csharp-parser = [ "dep:windmill-parser-csharp"] nu-parser = [ "dep:windmill-parser-nu"] +java-parser = [ "dep:windmill-parser-java"] [dependencies] anyhow.workspace = true @@ -43,6 +44,7 @@ windmill-parser-rust = { workspace = true, optional = true } windmill-parser-yaml = { workspace = true, optional = true } windmill-parser-csharp = { workspace = true, optional = true } windmill-parser-nu = { workspace = true, optional = true } +windmill-parser-java = { workspace = true, optional = true } wasm-bindgen.workspace = true serde_json.workspace = true getrandom = { workspace = true, features = ["js"] } diff --git a/backend/parsers/windmill-parser-wasm/build-pkgs-cli.sh b/backend/parsers/windmill-parser-wasm/build-pkgs-cli.sh index 34c36e8820..33c6701e52 100755 --- a/backend/parsers/windmill-parser-wasm/build-pkgs-cli.sh +++ b/backend/parsers/windmill-parser-wasm/build-pkgs-cli.sh @@ -70,6 +70,10 @@ OUT_DIR="../../../cli/wasm/nu" mkdir -p $OUT_DIR wasm-pack build --release --target deno --out-dir $OUT_DIR --features "nu-parser" \ -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort -# sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-nu"/' $OUT_DIR/package.json rm $OUT_DIR/.gitignore +#-# Java +OUT_DIR="../../../cli/wasm/java" +mkdir -p $OUT_DIR +CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" wasm-pack build --release --target deno --out-dir $OUT_DIR --features "java-parser" +rm $OUT_DIR/.gitignore diff --git a/backend/parsers/windmill-parser-wasm/build-pkgs-mac.sh b/backend/parsers/windmill-parser-wasm/build-pkgs-mac.sh index 85de323a90..109a48e9b3 100755 --- a/backend/parsers/windmill-parser-wasm/build-pkgs-mac.sh +++ b/backend/parsers/windmill-parser-wasm/build-pkgs-mac.sh @@ -61,3 +61,8 @@ OUT_DIR="pkg-nu" wasm-pack build --release --target web --out-dir $OUT_DIR --features "nu-parser" \ -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-nu"/' $OUT_DIR/package.json + +#-# Java (needs some more stuff to compile C tree sitter into wasm) +OUT_DIR="pkg-java" +CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" wasm-pack build --release --target web --out-dir $OUT_DIR --features "java-parser" +sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-java"/' $OUT_DIR/package.json diff --git a/backend/parsers/windmill-parser-wasm/build-pkgs.sh b/backend/parsers/windmill-parser-wasm/build-pkgs.sh index e2f0b6b471..0d492e9dcb 100755 --- a/backend/parsers/windmill-parser-wasm/build-pkgs.sh +++ b/backend/parsers/windmill-parser-wasm/build-pkgs.sh @@ -60,3 +60,7 @@ wasm-pack build --release --target web --out-dir $OUT_DIR --features "nu-parser" -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-nu"/' $OUT_DIR/package.json +#-# Java (needs some more stuff to compile C tree sitter into wasm) +OUT_DIR="pkg-java" +CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" wasm-pack build --release --target web --out-dir $OUT_DIR --features "java-parser" +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-java"/' $OUT_DIR/package.json diff --git a/backend/parsers/windmill-parser-wasm/build.sh b/backend/parsers/windmill-parser-wasm/build.sh deleted file mode 100755 index c843d2b445..0000000000 --- a/backend/parsers/windmill-parser-wasm/build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -eou pipefail - -# Flags are needed to build correctly with C# -# NOTE: Currently does not work with nix nor nixos -CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" deno task wasmbuild --inline --out ../../../cli/wasm/ -p windmill-parser-wasm --all-features - - diff --git a/backend/parsers/windmill-parser-wasm/src/lib.rs b/backend/parsers/windmill-parser-wasm/src/lib.rs index 2ca8f2f2b0..2f4bc83c1f 100644 --- a/backend/parsers/windmill-parser-wasm/src/lib.rs +++ b/backend/parsers/windmill-parser-wasm/src/lib.rs @@ -155,3 +155,11 @@ pub fn parse_csharp(code: &str) -> String { pub fn parse_nu(code: &str) -> String { wrap_sig(windmill_parser_nu::parse_nu_signature(code)) } + +#[cfg(feature = "java-parser")] +#[wasm_bindgen] +pub fn parse_java(code: &str) -> String { + wrap_sig(windmill_parser_java::parse_java_signature(code)) +} + +// for related places search: ADD_NEW_LANG diff --git a/backend/pg_log_tail b/backend/pg_log_tail deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/backend/plot2.py b/backend/plot2.py new file mode 100644 index 0000000000..5a6624bc14 --- /dev/null +++ b/backend/plot2.py @@ -0,0 +1,33 @@ +import json +import matplotlib.pyplot as plt + +# Path to the profiling JSON file +# file_path = "/tmp/windmill/profiling_main.json" +file_path = "/tmp/profiling.json" + +# Load the JSON data +with open(file_path, "r") as f: + data = json.load(f) + +# Extract timings for "pre pull->post pull" +pre_post_pull_timings = [ + timing / 1000000.0 for entry in data["timings"] + for step, timing in entry["timings"] + # if step == "pre pull->post pull" + if step == "->job pulled from DB" +] + +# Plotting the distribution +plt.figure(figsize=(10, 6)) +# plt.hist(pre_post_pull_timings, bins=10, edgecolor='black') +plt.scatter(range(len(pre_post_pull_timings)), pre_post_pull_timings, + alpha=1.0, # Transparency level + s=40) # Size of the dots`) +plt.title("Distribution of 'pre pull->post pull' timings") +# plt.xlabel("Time (ms)") +# plt.ylabel("Frequency") +plt.xlabel("Sample Index") +plt.ylabel("Time (ms)") +plt.grid(True) +plt.tight_layout() +plt.show() \ No newline at end of file diff --git a/backend/src/main.rs b/backend/src/main.rs index c608b214b0..7f4bcda628 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -9,12 +9,13 @@ use anyhow::Context; use monitor::{ load_base_url, load_otel, reload_delete_logs_periodically_setting, reload_indexer_config, - reload_instance_python_version_setting, reload_nuget_config_setting, + reload_instance_python_version_setting, reload_maven_repos_setting, + reload_no_default_maven_setting, reload_nuget_config_setting, reload_timeout_wait_result_setting, send_current_log_file_to_object_store, send_logs_to_object_store, }; use rand::Rng; -use sqlx::{postgres::PgListener, Pool, Postgres}; +use sqlx::postgres::PgListener; use std::{ collections::HashMap, fs::{create_dir_all, DirBuilder}, @@ -29,6 +30,7 @@ use windmill_api::HTTP_CLIENT; use windmill_common::ee::{maybe_renew_license_key_on_start, LICENSE_KEY_ID, LICENSE_KEY_VALID}; use windmill_common::{ + agent_workers::build_agent_http_client, get_database_url, global_settings::{ BASE_URL_SETTING, BUNFIG_INSTALL_SCOPES_SETTING, CRITICAL_ALERT_MUTE_UI_SETTING, @@ -37,16 +39,19 @@ use windmill_common::{ EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING, EXTRA_PIP_INDEX_URL_SETTING, HUB_BASE_URL_SETTING, INDEXER_SETTING, INSTANCE_PYTHON_VERSION_SETTING, JOB_DEFAULT_TIMEOUT_SECS_SETTING, JWT_SECRET_SETTING, KEEP_JOB_DIR_SETTING, - LICENSE_KEY_SETTING, MONITOR_LOGS_ON_OBJECT_STORE_SETTING, NPM_CONFIG_REGISTRY_SETTING, - NUGET_CONFIG_SETTING, OAUTH_SETTING, OTEL_SETTING, PIP_INDEX_URL_SETTING, - REQUEST_SIZE_LIMIT_SETTING, REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, - RETENTION_PERIOD_SECS_SETTING, SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, SMTP_SETTING, - TEAMS_SETTING, TIMEOUT_WAIT_RESULT_SETTING, + LICENSE_KEY_SETTING, MAVEN_REPOS_SETTING, MONITOR_LOGS_ON_OBJECT_STORE_SETTING, + NO_DEFAULT_MAVEN_SETTING, NPM_CONFIG_REGISTRY_SETTING, NUGET_CONFIG_SETTING, OAUTH_SETTING, + OTEL_SETTING, PIP_INDEX_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING, + REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING, + SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, SMTP_SETTING, TEAMS_SETTING, + TIMEOUT_WAIT_RESULT_SETTING, }, scripts::ScriptLang, stats_ee::schedule_stats, utils::{hostname, rd_string, Mode, GIT_VERSION, MODE_AND_ADDONS}, - worker::{reload_custom_tags_setting, HUB_CACHE_DIR, TMP_DIR, TMP_LOGS_DIR, WORKER_GROUP}, + worker::{ + reload_custom_tags_setting, Connection, HUB_CACHE_DIR, TMP_DIR, TMP_LOGS_DIR, WORKER_GROUP, + }, KillpillSender, METRICS_ENABLED, }; @@ -66,9 +71,9 @@ use windmill_common::global_settings::OBJECT_STORE_CACHE_CONFIG_SETTING; use windmill_worker::{ get_hub_script_content_and_requirements, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR, CSHARP_CACHE_DIR, DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS, DENO_CACHE_DIR_NPM, GO_BIN_CACHE_DIR, GO_CACHE_DIR, - NU_CACHE_DIR, POWERSHELL_CACHE_DIR, PY310_CACHE_DIR, PY311_CACHE_DIR, PY312_CACHE_DIR, - PY313_CACHE_DIR, RUST_CACHE_DIR, TAR_PY310_CACHE_DIR, TAR_PY311_CACHE_DIR, TAR_PY312_CACHE_DIR, - TAR_PY313_CACHE_DIR, UV_CACHE_DIR, + JAVA_CACHE_DIR, NU_CACHE_DIR, POWERSHELL_CACHE_DIR, PY310_CACHE_DIR, PY311_CACHE_DIR, + PY312_CACHE_DIR, PY313_CACHE_DIR, RUST_CACHE_DIR, TAR_JAVA_CACHE_DIR, TAR_PY310_CACHE_DIR, + TAR_PY311_CACHE_DIR, TAR_PY312_CACHE_DIR, TAR_PY313_CACHE_DIR, UV_CACHE_DIR, }; use crate::monitor::{ @@ -93,6 +98,31 @@ const DEFAULT_SERVER_BIND_ADDR: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0); mod ee; mod monitor; +pub fn setup_deno_runtime() -> anyhow::Result<()> { + // https://github.com/denoland/deno/blob/main/cli/main.rs#L477 + #[cfg(feature = "deno_core")] + let unrecognized_v8_flags = deno_core::v8_set_flags(vec![ + "--stack-size=1024".to_string(), + // TODO(bartlomieju): I think this can be removed as it's handled by `deno_core` + // and its settings. + // deno_ast removes TypeScript `assert` keywords, so this flag only affects JavaScript + // TODO(petamoriken): Need to check TypeScript `assert` keywords in deno_ast + "--no-harmony-import-assertions".to_string(), + ]) + .into_iter() + .skip(1) + .collect::>(); + + #[cfg(feature = "deno_core")] + if !unrecognized_v8_flags.is_empty() { + println!("Unrecognized V8 flags: {:?}", unrecognized_v8_flags); + } + + #[cfg(feature = "deno_core")] + deno_core::JsRuntime::init_platform(None, false); + Ok(()) +} + #[inline(always)] fn create_and_run_current_thread_inner(future: F) -> R where @@ -123,27 +153,7 @@ lazy_static::lazy_static! { } pub fn main() -> anyhow::Result<()> { - // https://github.com/denoland/deno/blob/main/cli/main.rs#L477 - #[cfg(feature = "deno_core")] - let unrecognized_v8_flags = deno_core::v8_set_flags(vec![ - "--stack-size=1024".to_string(), - // TODO(bartlomieju): I think this can be removed as it's handled by `deno_core` - // and its settings. - // deno_ast removes TypeScript `assert` keywords, so this flag only affects JavaScript - // TODO(petamoriken): Need to check TypeScript `assert` keywords in deno_ast - "--no-harmony-import-assertions".to_string(), - ]) - .into_iter() - .skip(1) - .collect::>(); - - #[cfg(feature = "deno_core")] - if !unrecognized_v8_flags.is_empty() { - println!("Unrecognized V8 flags: {:?}", unrecognized_v8_flags); - } - - #[cfg(feature = "deno_core")] - deno_core::JsRuntime::init_platform(None, false); + setup_deno_runtime()?; create_and_run_current_thread_inner(windmill_main()) } @@ -319,23 +329,37 @@ async fn windmill_main() -> anyhow::Result<()> { IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)) }; - println!("Connecting to database..."); - let db = windmill_common::initial_connection().await?; + let (conn, first_suffix) = if mode == Mode::Agent { + tracing::info!( + "Creating http client for cluster using base internal url {}", + std::env::var("BASE_INTERNAL_URL").unwrap_or_default() + ); + let suffix = windmill_common::utils::worker_suffix(&hostname, &rd_string(5)); + ( + Connection::Http(build_agent_http_client(&suffix)), + Some(suffix), + ) + } else { + println!("Connecting to database..."); - let num_version = sqlx::query_scalar!("SELECT version()").fetch_one(&db).await; + let db = windmill_common::initial_connection().await?; - tracing::info!( - "PostgreSQL version: {} (windmill require PG >= 14)", - num_version - .ok() - .flatten() - .unwrap_or_else(|| "UNKNOWN".to_string()) - ); - load_otel(&db).await; + let num_version = sqlx::query_scalar!("SELECT version()").fetch_one(&db).await; - tracing::info!("Database connected"); + tracing::info!( + "PostgreSQL version: {} (windmill require PG >= 14)", + num_version + .ok() + .flatten() + .unwrap_or_else(|| "UNKNOWN".to_string()) + ); + load_otel(&db).await; - let environment = load_base_url(&db) + tracing::info!("Database connected"); + (Connection::Sql(db), None) + }; + + let environment = load_base_url(&conn) .await .unwrap_or_else(|_| "local".to_string()) .trim_start_matches("https://") @@ -355,23 +379,30 @@ async fn windmill_main() -> anyhow::Result<()> { .ok() .is_some_and(|x| x == "1" || x == "true"); - if !is_agent && !indexer_mode { - let skip_migration = std::env::var("SKIP_MIGRATION") - .map(|val| val == "true") - .unwrap_or(false); + if let Some(db) = conn.as_sql() { + if !is_agent && !indexer_mode { + let skip_migration = std::env::var("SKIP_MIGRATION") + .map(|val| val == "true") + .unwrap_or(false); - if !skip_migration { - // migration code to avoid break - migration_handle = windmill_api::migrate_db(&db).await?; - } else { - tracing::info!("SKIP_MIGRATION set, skipping db migration...") + if !skip_migration { + // migration code to avoid break + migration_handle = windmill_api::migrate_db(&db).await?; + } else { + tracing::info!("SKIP_MIGRATION set, skipping db migration...") + } } } - drop(db); let worker_mode = num_workers > 0; - let db = windmill_common::connect_db(server_mode, indexer_mode, worker_mode).await?; + let conn = if mode == Mode::Agent { + conn + } else { + // This time we use a pool of connections + let db = windmill_common::connect_db(server_mode, indexer_mode, worker_mode).await?; + Connection::Sql(db) + }; let (killpill_tx, mut killpill_rx) = KillpillSender::new(2); let mut monitor_killpill_rx = killpill_tx.subscribe(); @@ -399,21 +430,13 @@ Windmill Community Edition {GIT_VERSION} display_config(&ENV_SETTINGS); - if let Err(e) = reload_base_url_setting(&db).await { - tracing::error!("Error loading base url: {:?}", e) - } - - if let Err(e) = reload_critical_error_channels_setting(&db).await { - tracing::error!("Could loading critical error emails setting: {:?}", e); - } - #[cfg(feature = "enterprise")] { // load the license key and check if it's valid // if not valid and not server mode just quit // if not expired and server mode then force renewal // if key still invalid and num_workers > 0, set to 0 - if let Err(err) = reload_license_key(&db).await { + if let Err(err) = reload_license_key(&conn).await { tracing::error!("Failed to reload license key: {err:#}"); } let valid_key = *LICENSE_KEY_VALID.read().await; @@ -421,17 +444,21 @@ Windmill Community Edition {GIT_VERSION} tracing::error!("Invalid license key, workers require a valid license key"); } if server_mode { - // only force renewal if invalid but not empty (= expired) - let renewed_now = maybe_renew_license_key_on_start( - &HTTP_CLIENT, - &db, - !valid_key && !LICENSE_KEY_ID.read().await.is_empty(), - ) - .await; - if renewed_now { - if let Err(err) = reload_license_key(&db).await { - tracing::error!("Failed to reload license key: {err:#}"); + if let Some(db) = conn.as_sql() { + // only force renewal if invalid but not empty (= expired) + let renewed_now = maybe_renew_license_key_on_start( + &HTTP_CLIENT, + &db, + !valid_key && !LICENSE_KEY_ID.read().await.is_empty(), + ) + .await; + if renewed_now { + if let Err(err) = reload_license_key(&conn).await { + tracing::error!("Failed to reload license key: {err:#}"); + } } + } else { + panic!("Server mode requires a database connection"); } } } @@ -459,7 +486,7 @@ Windmill Community Edition {GIT_VERSION} }; initial_load( - &db, + &conn, killpill_tx.clone(), worker_mode, server_mode, @@ -469,7 +496,7 @@ Windmill Community Edition {GIT_VERSION} .await; monitor_db( - &db, + &conn, &base_internal_url, server_mode, worker_mode, @@ -479,9 +506,11 @@ Windmill Community Edition {GIT_VERSION} .await; #[cfg(feature = "prometheus")] - crate::monitor::monitor_pool(&db).await; + if let Some(db) = conn.as_sql() { + crate::monitor::monitor_pool(&db).await; + } - send_logs_to_object_store(&db, &hostname, &mode); + send_logs_to_object_store(&conn, &hostname, &mode); #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] if !worker_mode { @@ -500,14 +529,20 @@ Windmill Community Edition {GIT_VERSION} #[cfg(feature = "tantivy")] let should_index_jobs = mode == Mode::Indexer || mode_and_addons.indexer; - reload_indexer_config(&db).await; + #[cfg(feature = "tantivy")] + if should_index_jobs { + if let Some(db) = conn.as_sql() { + reload_indexer_config(&db).await; + } + } #[cfg(feature = "tantivy")] let (index_reader, index_writer) = if should_index_jobs { - let mut indexer_rx = killpill_rx.resubscribe(); + if let Some(db) = conn.as_sql() { + let mut indexer_rx = killpill_rx.resubscribe(); - let (mut reader, mut writer) = (None, None); - tokio::select! { + let (mut reader, mut writer) = (None, None); + tokio::select! { _ = indexer_rx.recv() => { tracing::info!("Received killpill, aborting index initialization"); }, @@ -517,8 +552,11 @@ Windmill Community Edition {GIT_VERSION} writer = Some(res.1); } + } + (reader, writer) + } else { + (None, None) } - (reader, writer) } else { (None, None) }; @@ -528,13 +566,15 @@ Windmill Community Edition {GIT_VERSION} let indexer_rx = killpill_rx.resubscribe(); let index_writer2 = index_writer.clone(); async { - if let Some(index_writer) = index_writer2 { - windmill_indexer::completed_runs_ee::run_indexer( - db.clone(), - index_writer, - indexer_rx, - ) - .await?; + if let Some(db) = conn.as_sql() { + if let Some(index_writer) = index_writer2 { + windmill_indexer::completed_runs_ee::run_indexer( + db.clone(), + index_writer, + indexer_rx, + ) + .await?; + } } Ok(()) } @@ -542,21 +582,25 @@ Windmill Community Edition {GIT_VERSION} #[cfg(all(feature = "tantivy", feature = "parquet"))] let (log_index_reader, log_index_writer) = if should_index_jobs { - let mut indexer_rx = killpill_rx.resubscribe(); + if let Some(db) = conn.as_sql() { + let mut indexer_rx = killpill_rx.resubscribe(); + + let (mut reader, mut writer) = (None, None); + tokio::select! { + _ = indexer_rx.recv() => { + tracing::info!("Received killpill, aborting index initialization"); + }, + res = windmill_indexer::service_logs_ee::init_index(&db, killpill_tx.clone()) => { + let res = res?; + reader = Some(res.0); + writer = Some(res.1); + } - let (mut reader, mut writer) = (None, None); - tokio::select! { - _ = indexer_rx.recv() => { - tracing::info!("Received killpill, aborting index initialization"); - }, - res = windmill_indexer::service_logs_ee::init_index(&db, killpill_tx.clone()) => { - let res = res?; - reader = Some(res.0); - writer = Some(res.1); } - + (reader, writer) + } else { + (None, None) } - (reader, writer) } else { (None, None) }; @@ -566,13 +610,15 @@ Windmill Community Edition {GIT_VERSION} let log_indexer_rx = killpill_rx.resubscribe(); let log_index_writer2 = log_index_writer.clone(); async { - if let Some(log_index_writer) = log_index_writer2 { - windmill_indexer::service_logs_ee::run_indexer( - db.clone(), - log_index_writer, - log_indexer_rx, - ) - .await?; + if let Some(db) = conn.as_sql() { + if let Some(log_index_writer) = log_index_writer2 { + windmill_indexer::service_logs_ee::run_indexer( + db.clone(), + log_index_writer, + log_indexer_rx, + ) + .await?; + } } Ok(()) } @@ -592,18 +638,19 @@ Windmill Community Edition {GIT_VERSION} let server_f = async { if !is_agent { - windmill_api::run_server( - db.clone(), - index_reader, - log_index_reader, - addr, - server_killpill_rx, - base_internal_tx, - server_mode, - #[cfg(feature = "smtp")] - base_internal_url.clone(), - ) - .await?; + if let Some(db) = conn.as_sql() { + windmill_api::run_server( + db.clone(), + index_reader, + log_index_reader, + addr, + server_killpill_rx, + base_internal_tx, + server_mode, + base_internal_url.clone(), + ) + .await?; + } } else { base_internal_tx .send(base_internal_url.clone()) @@ -620,14 +667,34 @@ Windmill Community Edition {GIT_VERSION} if !killpill_rx.try_recv().is_ok() { let base_internal_url = base_internal_rx.await?; if worker_mode { + let mut workers = vec![]; + for i in 0..num_workers { + let suffix: String = if i == 0 && first_suffix.as_ref().is_some() { + first_suffix.as_ref().unwrap().clone() + } else { + windmill_common::utils::worker_suffix(&hostname, &rd_string(5)) + }; + let worker_conn = WorkerConn { + conn: if i == 0 || mode != Mode::Agent { + conn.clone() + } else { + Connection::Http(build_agent_http_client(&suffix)) + }, + worker_name: windmill_common::utils::worker_name_with_suffix( + mode == Mode::Agent, + WORKER_GROUP.as_str(), + &suffix, + ), + }; + workers.push(worker_conn); + } + run_workers( - db.clone(), rx, killpill_tx.clone(), - num_workers, base_internal_url.clone(), - is_agent, hostname.clone(), + &workers, ) .await?; tracing::info!("All workers exited."); @@ -649,275 +716,305 @@ Windmill Community Edition {GIT_VERSION} }; let monitor_f = async { - let db = db.clone(); let tx = killpill_tx.clone(); - - let base_internal_url = base_internal_url.to_string(); - let db_url: String = get_database_url().await?; - - let h = tokio::spawn(async move { - let mut listener = retry_listen_pg(&db_url).await; - let mut last_listener_refresh = Instant::now(); - loop { - tokio::select! { - biased; - Some(_) = async { if let Some(jh) = migration_handle.take() { - tracing::info!("migration job finished"); - Some(jh.await) - } else { - None - }} => { - continue; - }, - _ = monitor_killpill_rx.recv() => { - tracing::info!("received killpill for monitor job"); - break; - }, - notification = listener.try_recv() => { - match notification { - Ok(n) => { - if n.is_none() { - tracing::error!("Could not receive notification, attempting to reconnect to pg listener"); - continue; - } - let n = n.unwrap(); - tracing::info!("Received new pg notification: {n:?}"); - match n.channel() { - "notify_config_change" => { - match n.payload() { - "server" if server_mode => { - tracing::error!("Server config change detected but server config is obsolete: {}", n.payload()); + let conn = conn.clone(); + match conn { + Connection::Sql(ref db) => { + let base_internal_url = base_internal_url.to_string(); + let db_url: String = get_database_url().await?; + let db = db.clone(); + let h = tokio::spawn(async move { + let mut listener = retry_listen_pg(&db_url).await; + let mut last_listener_refresh = Instant::now(); + loop { + let db = db.clone(); + tokio::select! { + biased; + Some(_) = async { if let Some(jh) = migration_handle.take() { + tracing::info!("migration job finished"); + Some(jh.await) + } else { + None + }} => { + continue; + }, + _ = monitor_killpill_rx.recv() => { + tracing::info!("received killpill for monitor job"); + break; + }, + notification = listener.try_recv() => { + match notification { + Ok(n) => { + if n.is_none() { + tracing::error!("Could not receive notification, attempting to reconnect to pg listener"); + continue; + } + let n = n.unwrap(); + tracing::info!("Received new pg notification: {n:?}"); + match n.channel() { + "notify_config_change" => { + match n.payload() { + "server" if server_mode => { + tracing::error!("Server config change detected but server config is obsolete: {}", n.payload()); + }, + a@ _ if worker_mode && a == format!("worker__{}", *WORKER_GROUP) => { + tracing::info!("Worker config change detected: {}", n.payload()); + reload_worker_config(&db, tx.clone(), true).await; + }, + _ => { + tracing::debug!("config changed but did not target this server/worker"); + } + } }, - a@ _ if worker_mode && a == format!("worker__{}", *WORKER_GROUP) => { - tracing::info!("Worker config change detected: {}", n.payload()); - reload_worker_config(&db, tx.clone(), true).await; + "notify_webhook_change" => { + let workspace_id = n.payload(); + tracing::info!("Webhook change detected, invalidating webhook cache: {}", workspace_id); + windmill_api::webhook_util::WEBHOOK_CACHE.remove(workspace_id); + }, + "notify_workspace_envs_change" => { + let workspace_id = n.payload(); + tracing::info!("Workspace envs change detected, invalidating workspace envs cache: {}", workspace_id); + windmill_common::variables::CUSTOM_ENVS_CACHE.remove(workspace_id); + }, + "notify_workspace_premium_change" => { + let workspace_id = n.payload(); + tracing::info!("Workspace premium change detected, invalidating workspace premium cache: {}", workspace_id); + windmill_common::workspaces::IS_PREMIUM_CACHE.remove(workspace_id); + }, + "notify_global_setting_change" => { + tracing::info!("Global setting change detected: {}", n.payload()); + match n.payload() { + BASE_URL_SETTING => { + if let Err(e) = reload_base_url_setting(&conn).await { + tracing::error!(error = %e, "Could not reload base url setting"); + } + }, + OAUTH_SETTING => { + if let Err(e) = reload_base_url_setting(&conn).await { + tracing::error!(error = %e, "Could not reload oauth setting"); + } + }, + CUSTOM_TAGS_SETTING => { + if let Err(e) = reload_custom_tags_setting(&db).await { + tracing::error!(error = %e, "Could not reload custom tags setting"); + } + }, + LICENSE_KEY_SETTING => { + if let Err(e) = reload_license_key(&db.into()).await { + tracing::error!("Failed to reload license key: {e:#}"); + } + }, + DEFAULT_TAGS_PER_WORKSPACE_SETTING => { + if let Err(e) = load_tag_per_workspace_enabled(&db).await { + tracing::error!("Error loading default tag per workspace: {e:#}"); + } + }, + DEFAULT_TAGS_WORKSPACES_SETTING => { + if let Err(e) = load_tag_per_workspace_workspaces(&db).await { + tracing::error!("Error loading default tag per workspace workspaces: {e:#}"); + } + } + SMTP_SETTING => { + reload_smtp_config(&db).await; + }, + TEAMS_SETTING => { + tracing::info!("Teams setting changed."); + }, + INDEXER_SETTING => { + reload_indexer_config(&db).await; + }, + TIMEOUT_WAIT_RESULT_SETTING => { + reload_timeout_wait_result_setting(&conn).await + }, + RETENTION_PERIOD_SECS_SETTING => { + reload_retention_period_setting(&conn).await + }, + MONITOR_LOGS_ON_OBJECT_STORE_SETTING => { + reload_delete_logs_periodically_setting(&conn).await + }, + JOB_DEFAULT_TIMEOUT_SECS_SETTING => { + reload_job_default_timeout_setting(&conn).await + }, + #[cfg(feature = "parquet")] + OBJECT_STORE_CACHE_CONFIG_SETTING => { + if !disable_s3_store { + reload_s3_cache_setting(&db).await + } + }, + SCIM_TOKEN_SETTING => { + reload_scim_token_setting(&conn).await + }, + EXTRA_PIP_INDEX_URL_SETTING => { + reload_extra_pip_index_url_setting(&conn).await + }, + PIP_INDEX_URL_SETTING => { + reload_pip_index_url_setting(&conn).await + }, + INSTANCE_PYTHON_VERSION_SETTING => { + reload_instance_python_version_setting(&conn).await + }, + NPM_CONFIG_REGISTRY_SETTING => { + reload_npm_config_registry_setting(&conn).await + }, + BUNFIG_INSTALL_SCOPES_SETTING => { + reload_bunfig_install_scopes_setting(&conn).await + }, + NUGET_CONFIG_SETTING => { + reload_nuget_config_setting(&conn).await + }, + MAVEN_REPOS_SETTING => { + reload_maven_repos_setting(&conn).await + }, + NO_DEFAULT_MAVEN_SETTING => { + reload_no_default_maven_setting(&conn).await + }, + KEEP_JOB_DIR_SETTING => { + load_keep_job_dir(&conn).await; + }, + REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING => { + load_require_preexisting_user(&db).await; + }, + EXPOSE_METRICS_SETTING => { + tracing::info!("Metrics setting changed, restarting"); + send_delayed_killpill(&tx, 40, "metrics setting change").await; + }, + EMAIL_DOMAIN_SETTING => { + tracing::info!("Email domain setting changed"); + if server_mode { + send_delayed_killpill(&tx, 4, "email domain setting change").await; + } + }, + EXPOSE_DEBUG_METRICS_SETTING => { + if let Err(e) = load_metrics_debug_enabled(&conn).await { + tracing::error!(error = %e, "Could not reload debug metrics setting"); + } + }, + OTEL_SETTING => { + tracing::info!("OTEL setting changed, restarting"); + send_delayed_killpill(&tx, 4, "OTEL setting change").await; + }, + REQUEST_SIZE_LIMIT_SETTING => { + if server_mode { + tracing::info!("Request limit size change detected, killing server expecting to be restarted"); + send_delayed_killpill(&tx, 4, "request size limit change").await; + } + }, + SAML_METADATA_SETTING => { + tracing::info!("SAML metadata change detected, killing server expecting to be restarted"); + send_delayed_killpill(&tx, 0, "SAML metadata change").await; + }, + HUB_BASE_URL_SETTING => { + if let Err(e) = reload_hub_base_url_setting(&conn, server_mode).await { + tracing::error!(error = %e, "Could not reload hub base url setting"); + } + }, + CRITICAL_ERROR_CHANNELS_SETTING => { + if let Err(e) = reload_critical_error_channels_setting(&db).await { + tracing::error!(error = %e, "Could not reload critical error emails setting"); + } + }, + JWT_SECRET_SETTING => { + if let Err(e) = reload_jwt_secret_setting(&db).await { + tracing::error!(error = %e, "Could not reload jwt secret setting"); + } + }, + CRITICAL_ALERT_MUTE_UI_SETTING => { + tracing::info!("Critical alert UI setting changed"); + if let Err(e) = reload_critical_alert_mute_ui_setting(&conn).await { + tracing::error!(error = %e, "Could not reload critical alert UI setting"); + } + }, + + a @_ => { + tracing::info!("Unrecognized Global Setting Change Payload: {:?}", a); + } + } }, _ => { - tracing::debug!("config changed but did not target this server/worker"); + tracing::warn!("Unknown notification received"); + continue; } } }, - "notify_webhook_change" => { - let workspace_id = n.payload(); - tracing::info!("Webhook change detected, invalidating webhook cache: {}", workspace_id); - windmill_api::webhook_util::WEBHOOK_CACHE.remove(workspace_id); - }, - "notify_workspace_envs_change" => { - let workspace_id = n.payload(); - tracing::info!("Workspace envs change detected, invalidating workspace envs cache: {}", workspace_id); - windmill_common::variables::CUSTOM_ENVS_CACHE.remove(workspace_id); - }, - "notify_workspace_premium_change" => { - let workspace_id = n.payload(); - tracing::info!("Workspace premium change detected, invalidating workspace premium cache: {}", workspace_id); - windmill_common::workspaces::IS_PREMIUM_CACHE.remove(workspace_id); - }, - "notify_global_setting_change" => { - tracing::info!("Global setting change detected: {}", n.payload()); - match n.payload() { - BASE_URL_SETTING => { - if let Err(e) = reload_base_url_setting(&db).await { - tracing::error!(error = %e, "Could not reload base url setting"); - } + Err(e) => { + tracing::error!(error = %e, "Could not receive notification, attempting to reconnect listener"); + tokio::select! { + biased; + _ = monitor_killpill_rx.recv() => { + tracing::info!("received killpill for monitor job"); + break; }, - OAUTH_SETTING => { - if let Err(e) = reload_base_url_setting(&db).await { - tracing::error!(error = %e, "Could not reload oauth setting"); - } - }, - CUSTOM_TAGS_SETTING => { - if let Err(e) = reload_custom_tags_setting(&db).await { - tracing::error!(error = %e, "Could not reload custom tags setting"); - } - }, - LICENSE_KEY_SETTING => { - if let Err(e) = reload_license_key(&db).await { - tracing::error!("Failed to reload license key: {e:#}"); - } - }, - DEFAULT_TAGS_PER_WORKSPACE_SETTING => { - if let Err(e) = load_tag_per_workspace_enabled(&db).await { - tracing::error!("Error loading default tag per workspace: {e:#}"); - } - }, - DEFAULT_TAGS_WORKSPACES_SETTING => { - if let Err(e) = load_tag_per_workspace_workspaces(&db).await { - tracing::error!("Error loading default tag per workspace workspaces: {e:#}"); - } - } - SMTP_SETTING => { - reload_smtp_config(&db).await; - }, - TEAMS_SETTING => { - tracing::info!("Teams setting changed."); - }, - INDEXER_SETTING => { - reload_indexer_config(&db).await; - }, - TIMEOUT_WAIT_RESULT_SETTING => { - reload_timeout_wait_result_setting(&db).await - }, - RETENTION_PERIOD_SECS_SETTING => { - reload_retention_period_setting(&db).await - }, - MONITOR_LOGS_ON_OBJECT_STORE_SETTING => { - reload_delete_logs_periodically_setting(&db).await - }, - JOB_DEFAULT_TIMEOUT_SECS_SETTING => { - reload_job_default_timeout_setting(&db).await - }, - #[cfg(feature = "parquet")] - OBJECT_STORE_CACHE_CONFIG_SETTING => { - if !disable_s3_store { - reload_s3_cache_setting(&db).await - } - }, - SCIM_TOKEN_SETTING => { - reload_scim_token_setting(&db).await - }, - EXTRA_PIP_INDEX_URL_SETTING => { - reload_extra_pip_index_url_setting(&db).await - }, - PIP_INDEX_URL_SETTING => { - reload_pip_index_url_setting(&db).await - }, - INSTANCE_PYTHON_VERSION_SETTING => { - reload_instance_python_version_setting(&db).await - }, - NPM_CONFIG_REGISTRY_SETTING => { - reload_npm_config_registry_setting(&db).await - }, - BUNFIG_INSTALL_SCOPES_SETTING => { - reload_bunfig_install_scopes_setting(&db).await - }, - NUGET_CONFIG_SETTING => { - reload_nuget_config_setting(&db).await - }, - KEEP_JOB_DIR_SETTING => { - load_keep_job_dir(&db).await; - }, - REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING => { - load_require_preexisting_user(&db).await; - }, - EXPOSE_METRICS_SETTING => { - tracing::info!("Metrics setting changed, restarting"); - send_delayed_killpill(&tx, 40, "metrics setting change").await; - }, - EMAIL_DOMAIN_SETTING => { - tracing::info!("Email domain setting changed"); - if server_mode { - send_delayed_killpill(&tx, 4, "email domain setting change").await; - } - }, - EXPOSE_DEBUG_METRICS_SETTING => { - if let Err(e) = load_metrics_debug_enabled(&db).await { - tracing::error!(error = %e, "Could not reload debug metrics setting"); - } - }, - OTEL_SETTING => { - tracing::info!("OTEL setting changed, restarting"); - send_delayed_killpill(&tx, 4, "OTEL setting change").await; - }, - REQUEST_SIZE_LIMIT_SETTING => { - if server_mode { - tracing::info!("Request limit size change detected, killing server expecting to be restarted"); - send_delayed_killpill(&tx, 4, "request size limit change").await; - } - }, - SAML_METADATA_SETTING => { - tracing::info!("SAML metadata change detected, killing server expecting to be restarted"); - send_delayed_killpill(&tx, 0, "SAML metadata change").await; - }, - HUB_BASE_URL_SETTING => { - if let Err(e) = reload_hub_base_url_setting(&db, server_mode).await { - tracing::error!(error = %e, "Could not reload hub base url setting"); - } - }, - CRITICAL_ERROR_CHANNELS_SETTING => { - if let Err(e) = reload_critical_error_channels_setting(&db).await { - tracing::error!(error = %e, "Could not reload critical error emails setting"); - } - }, - JWT_SECRET_SETTING => { - if let Err(e) = reload_jwt_secret_setting(&db).await { - tracing::error!(error = %e, "Could not reload jwt secret setting"); - } - }, - CRITICAL_ALERT_MUTE_UI_SETTING => { - tracing::info!("Critical alert UI setting changed"); - if let Err(e) = reload_critical_alert_mute_ui_setting(&db).await { - tracing::error!(error = %e, "Could not reload critical alert UI setting"); - } - }, - a @_ => { - tracing::info!("Unrecognized Global Setting Change Payload: {:?}", a); + new_listener = retry_listen_pg(&db_url) => { + listener = new_listener; + continue; } } - }, - _ => { - tracing::warn!("Unknown notification received"); - continue; } + }; + }, + _ = tokio::time::sleep(Duration::from_secs(30)) => { + if last_listener_refresh.elapsed() > Duration::from_secs(*PG_LISTENER_REFRESH_PERIOD_SECS) { + tracing::info!("Refreshing pg listeners, settings and license key after {}s", Duration::from_secs(*PG_LISTENER_REFRESH_PERIOD_SECS).as_secs()); + if let Err(e) = listener.unlisten_all().await { + tracing::error!(error = %e, "Could not unlisten to database"); + } + listener = retry_listen_pg(&db_url).await; + initial_load( + &conn, + tx.clone(), + worker_mode, + server_mode, + #[cfg(feature = "parquet")] + disable_s3_store, + ) + .await; + #[cfg(feature = "enterprise")] + if let Err(err) = reload_license_key(&conn).await { + tracing::error!("Failed to reload license key: {err:#}"); + } + last_listener_refresh = Instant::now(); + } + + if server_mode { + tracing::info!("monitor task started"); + } + monitor_db( + &conn, + &base_internal_url, + server_mode, + worker_mode, + false, + tx.clone(), + ) + .await; + if server_mode { + tracing::info!("monitor task finished"); } }, - Err(e) => { - tracing::error!(error = %e, "Could not receive notification, attempting to reconnect listener"); - tokio::select! { - biased; - _ = monitor_killpill_rx.recv() => { - tracing::info!("received killpill for monitor job"); - break; - }, - new_listener = retry_listen_pg(&db_url) => { - listener = new_listener; - continue; - } - } - } - }; - }, - _ = tokio::time::sleep(Duration::from_secs(30)) => { - if last_listener_refresh.elapsed() > Duration::from_secs(*PG_LISTENER_REFRESH_PERIOD_SECS) { - tracing::info!("Refreshing pg listeners, settings and license key after {}s", Duration::from_secs(*PG_LISTENER_REFRESH_PERIOD_SECS).as_secs()); - if let Err(e) = listener.unlisten_all().await { - tracing::error!(error = %e, "Could not unlisten to database"); - } - listener = retry_listen_pg(&db_url).await; - initial_load( - &db, - tx.clone(), - worker_mode, - server_mode, - #[cfg(feature = "parquet")] - disable_s3_store, - ) - .await; - #[cfg(feature = "enterprise")] - if let Err(err) = reload_license_key(&db).await { - tracing::error!("Failed to reload license key: {err:#}"); - } - last_listener_refresh = Instant::now(); } + } + }); - tracing::info!("monitor task started"); - monitor_db( - &db, - &base_internal_url, - server_mode, - worker_mode, - false, - tx.clone(), - ) - .await; - tracing::info!("monitor task finished"); - }, + if let Err(e) = h.await { + tracing::error!("Error waiting for monitor handle: {e:#}") } } - }); + Connection::Http(_) => loop { + tokio::select! { + _ = monitor_killpill_rx.recv() => { + tracing::info!("Received killpill, exiting"); + break; + }, + _ = tokio::time::sleep(Duration::from_secs(12 * 60 * 60)) => { + tracing::info!("Reloading config after 12 hours"); + initial_load(&conn, tx.clone(), worker_mode, server_mode, #[cfg(feature = "parquet")] disable_s3_store).await; + #[cfg(feature = "enterprise")] + ee::verify_license_key().await; + } + } + }, + }; - if let Err(e) = h.await { - tracing::error!("Error waiting for monitor handle: {e:#}") - } tracing::info!("Monitor exited"); killpill_tx.send(); Ok(()) as anyhow::Result<()> @@ -947,7 +1044,9 @@ Windmill Community Edition {GIT_VERSION} }; if server_mode { - schedule_stats(&db, &HTTP_CLIENT).await; + if let Some(db) = conn.as_sql() { + schedule_stats(&db, &HTTP_CLIENT).await; + } } futures::try_join!( @@ -962,15 +1061,17 @@ Windmill Community Edition {GIT_VERSION} } else { tracing::info!("Nothing to do, exiting."); } - send_current_log_file_to_object_store(&db, &hostname, &mode).await; + send_current_log_file_to_object_store(&conn, &hostname, &mode).await; - tracing::info!("Exiting connection pool"); - tokio::select! { - _ = db.close() => { - tracing::info!("Database connection pool closed"); - }, - _ = tokio::time::sleep(Duration::from_secs(15)) => { - tracing::warn!("Could not close database connection pool in time (15s). Exiting anyway."); + if let Some(db) = conn.as_sql() { + tracing::info!("Exiting connection pool"); + tokio::select! { + _ = db.close() => { + tracing::info!("Database connection pool closed"); + }, + _ = tokio::time::sleep(Duration::from_secs(15)) => { + tracing::warn!("Could not close database connection pool in time (15s). Exiting anyway."); + } } } Ok(()) @@ -1034,16 +1135,20 @@ fn display_config(envs: &[&str]) { ) } +pub struct WorkerConn { + conn: Connection, + worker_name: String, +} + pub async fn run_workers( - db: Pool, mut rx: tokio::sync::broadcast::Receiver<()>, tx: KillpillSender, - num_workers: i32, base_internal_url: String, - agent_mode: bool, hostname: String, + workers: &[WorkerConn], ) -> anyhow::Result<()> { let mut killpill_rxs = vec![]; + let num_workers = workers.len(); for _ in 0..num_workers { killpill_rxs.push(rx.resubscribe()); } @@ -1052,14 +1157,6 @@ pub async fn run_workers( tracing::info!("Received killpill, exiting"); return Ok(()); } - let instance_name = hostname - .clone() - .replace(" ", "") - .split("-") - .last() - .unwrap() - .to_ascii_lowercase() - .to_string(); // #[cfg(tokio_unstable)] // let monitor = tokio_metrics::TaskMonitor::new(); @@ -1096,6 +1193,8 @@ pub async fn run_workers( NU_CACHE_DIR, HUB_CACHE_DIR, POWERSHELL_CACHE_DIR, + JAVA_CACHE_DIR, + TAR_JAVA_CACHE_DIR, // for related places search: ADD_NEW_LANG ] { DirBuilder::new() .recursive(true) @@ -1108,9 +1207,9 @@ pub async fn run_workers( *windmill_worker::SLEEP_QUEUE ); for i in 1..(num_workers + 1) { - let db1 = db.clone(); - let instance_name = instance_name.clone(); - let worker_name = format!("wk-{}-{}-{}", *WORKER_GROUP, &instance_name, rd_string(5)); + let wk_conf = &workers[i as usize - 1]; + let conn1 = wk_conf.conn.clone(); + let worker_name = wk_conf.worker_name.clone(); let ip = ip.clone(); let rx = killpill_rxs.pop().unwrap(); let tx = tx.clone(); @@ -1123,7 +1222,7 @@ pub async fn run_workers( } let f = windmill_worker::run_worker( - &db1, + &conn1, &hostname, worker_name, i as u64, @@ -1132,7 +1231,6 @@ pub async fn run_workers( rx, tx, &base_internal_url, - agent_mode, ); // #[cfg(tokio_unstable)] diff --git a/backend/src/monitor.rs b/backend/src/monitor.rs index a54011eef3..8dae3f8c5e 100644 --- a/backend/src/monitor.rs +++ b/backend/src/monitor.rs @@ -6,14 +6,14 @@ use std::{ str::FromStr, sync::{ atomic::{AtomicU16, Ordering}, - Arc, + Arc, Mutex, }, time::Duration, }; use chrono::{NaiveDateTime, Utc}; use futures::{stream::FuturesUnordered, StreamExt}; -use serde::{de::DeserializeOwned, Deserializer}; +use serde::de::DeserializeOwned; use sqlx::{Pool, Postgres}; use tokio::{ join, @@ -34,7 +34,8 @@ use windmill_common::ee::{jobs_waiting_alerts, worker_groups_alerts}; #[cfg(feature = "oauth2")] use windmill_common::global_settings::OAUTH_SETTING; use windmill_common::{ - ee::CriticalErrorChannel, error, flow_status::{FlowStatus, FlowStatusModule}, global_settings::{ + utils::empty_string_as_none, + agent_workers::DECODED_AGENT_TOKEN, auth::create_token_for_owner, ee::CriticalErrorChannel, error, flow_status::{FlowStatus, FlowStatusModule}, global_settings::{ BASE_URL_SETTING, BUNFIG_INSTALL_SCOPES_SETTING, CRITICAL_ALERT_MUTE_UI_SETTING, CRITICAL_ERROR_CHANNELS_SETTING, DEFAULT_TAGS_PER_WORKSPACE_SETTING, DEFAULT_TAGS_WORKSPACES_SETTING, EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING, @@ -45,16 +46,12 @@ use windmill_common::{ REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING, SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, TIMEOUT_WAIT_RESULT_SETTING, }, indexer::load_indexer_config, jobs::QueuedJob, jwt::JWT_SECRET, oauth2::REQUIRE_PREEXISTING_USER_FOR_OAUTH, server::load_smtp_config, tracing_init::JSON_FMT, users::truncate_token, utils::{now_from_db, rd_string, report_critical_error, Mode}, worker::{ - load_worker_config, make_pull_query, make_suspended_pull_query, reload_custom_tags_setting, - update_min_version, DEFAULT_TAGS_PER_WORKSPACE, DEFAULT_TAGS_WORKSPACES, INDEXER_CONFIG, - SMTP_CONFIG, TMP_DIR, WORKER_CONFIG, WORKER_GROUP, - }, KillpillSender, BASE_URL, CRITICAL_ALERT_MUTE_UI_ENABLED, CRITICAL_ERROR_CHANNELS, DB, DEFAULT_HUB_BASE_URL, HUB_BASE_URL, JOB_RETENTION_SECS, METRICS_DEBUG_ENABLED, METRICS_ENABLED, MONITOR_LOGS_ON_OBJECT_STORE, OTEL_LOGS_ENABLED, OTEL_METRICS_ENABLED, OTEL_TRACING_ENABLED, SERVICE_LOG_RETENTION_SECS + load_worker_config, reload_custom_tags_setting, store_pull_query, store_suspended_pull_query, update_min_version, Connection, DEFAULT_TAGS_PER_WORKSPACE, DEFAULT_TAGS_WORKSPACES, INDEXER_CONFIG, SCRIPT_TOKEN_EXPIRY, SMTP_CONFIG, TMP_DIR, WORKER_CONFIG, WORKER_GROUP + }, KillpillSender, BASE_URL, CRITICAL_ALERT_MUTE_UI_ENABLED, CRITICAL_ERROR_CHANNELS, DB, DEFAULT_HUB_BASE_URL, HUB_BASE_URL, JOB_RETENTION_SECS, METRICS_DEBUG_ENABLED, METRICS_ENABLED, MONITOR_LOGS_ON_OBJECT_STORE, OTEL_LOGS_ENABLED, OTEL_METRICS_ENABLED, OTEL_TRACING_ENABLED, SERVICE_LOG_RETENTION_SECS, }; -use windmill_queue::{cancel_job, MiniPulledJob}; +use windmill_queue::{cancel_job, MiniPulledJob, SameWorkerPayload}; use windmill_worker::{ - create_token_for_owner, handle_job_error, AuthedClient, SameWorkerPayload, SameWorkerSender, - SendResult, BUNFIG_INSTALL_SCOPES, INSTANCE_PYTHON_VERSION, JOB_DEFAULT_TIMEOUT, KEEP_JOB_DIR, - NPM_CONFIG_REGISTRY, NUGET_CONFIG, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL, SCRIPT_TOKEN_EXPIRY, + handle_job_error, AuthedClient, JobCompletedSender, SameWorkerSender, BUNFIG_INSTALL_SCOPES, INSTANCE_PYTHON_VERSION, JOB_DEFAULT_TIMEOUT, KEEP_JOB_DIR, MAVEN_REPOS, NO_DEFAULT_MAVEN, NPM_CONFIG_REGISTRY, NUGET_CONFIG, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL }; #[cfg(feature = "parquet")] @@ -109,6 +106,11 @@ lazy_static::lazy_static! { .and_then(|x| x.parse::().ok()) .unwrap_or(true); + pub static ref DISABLE_ZOMBIE_JOBS_MONITORING: bool = std::env::var("DISABLE_ZOMBIE_JOBS_MONITORING") + .ok() + .and_then(|x| x.parse::().ok()) + .unwrap_or(false); + static ref QUEUE_COUNT_TAGS: Arc>> = Arc::new(RwLock::new(Vec::new())); @@ -117,80 +119,113 @@ lazy_static::lazy_static! { } pub async fn initial_load( - db: &Pool, + conn: &Connection, tx: KillpillSender, worker_mode: bool, server_mode: bool, #[cfg(feature = "parquet")] disable_s3_store: bool, ) { - if let Err(e) = load_metrics_enabled(db).await { + if let Err(e) = reload_base_url_setting(&conn).await { + tracing::error!("Error loading base url: {:?}", e) + } + + if let Some(db) = conn.as_sql() { + if let Err(e) = reload_critical_error_channels_setting(&db).await { + tracing::error!("Could loading critical error emails setting: {:?}", e); + } + } + + + if let Err(e) = load_metrics_enabled(conn).await { tracing::error!("Error loading expose metrics: {e:#}"); } - if let Err(e) = load_metrics_debug_enabled(db).await { + if let Err(e) = load_metrics_debug_enabled(conn).await { tracing::error!("Error loading expose debug metrics: {e:#}"); } - if let Err(e) = reload_critical_alert_mute_ui_setting(db).await { + if let Err(e) = reload_critical_alert_mute_ui_setting(conn).await { tracing::error!("Error loading critical alert mute ui setting: {e:#}"); } - if let Err(e) = load_tag_per_workspace_enabled(db).await { - tracing::error!("Error loading default tag per workpsace: {e:#}"); - } + if let Some(db) = conn.as_sql() { + if let Err(e) = load_tag_per_workspace_enabled(db).await { + tracing::error!("Error loading default tag per workpsace: {e:#}"); + } - if let Err(e) = load_tag_per_workspace_workspaces(db).await { - tracing::error!("Error loading default tag per workpsace workspaces: {e:#}"); + if let Err(e) = load_tag_per_workspace_workspaces(db).await { + tracing::error!("Error loading default tag per workpsace workspaces: {e:#}"); + } } if server_mode { - load_require_preexisting_user(db).await; + if let Some(db) = conn.as_sql() { + load_require_preexisting_user(db).await; + } } if worker_mode { - load_keep_job_dir(db).await; - reload_worker_config(&db, tx, false).await; + load_keep_job_dir(conn).await; + match conn { + Connection::Sql(db) => { + reload_worker_config(&db, tx, false).await; + } + Connection::Http(_) => { + // TODO: reload worker config from http + WORKER_CONFIG.write().await.worker_tags = DECODED_AGENT_TOKEN.as_ref().map(|x| x.tags.clone()).unwrap_or_default(); + } + } } + - if let Err(e) = reload_custom_tags_setting(db).await { - tracing::error!("Error reloading custom tags: {:?}", e) - } - - if let Err(e) = reload_hub_base_url_setting(db, server_mode).await { + if let Err(e) = reload_hub_base_url_setting(conn, server_mode).await { tracing::error!("Error reloading hub base url: {:?}", e) } - if let Err(e) = reload_jwt_secret_setting(&db).await { - tracing::error!("Could not reload jwt secret setting: {:?}", e); + if let Some(db) = conn.as_sql() { + if let Err(e) = reload_jwt_secret_setting(db).await { + tracing::error!("Could not reload jwt secret setting: {:?}", e); + } + + if let Err(e) = reload_custom_tags_setting(db).await { + tracing::error!("Error reloading custom tags: {:?}", e) + } + } #[cfg(feature = "parquet")] if !disable_s3_store { - reload_s3_cache_setting(&db).await; + if let Some(db) = conn.as_sql() { + reload_s3_cache_setting(db).await; + } } - reload_smtp_config(&db).await; + if let Some(db) = conn.as_sql() { + reload_smtp_config(db).await; + } if server_mode { - reload_retention_period_setting(&db).await; - reload_request_size(&db).await; - reload_saml_metadata_setting(&db).await; - reload_scim_token_setting(&db).await; + reload_retention_period_setting(&conn).await; + reload_request_size(&conn).await; + reload_saml_metadata_setting(&conn).await; + reload_scim_token_setting(&conn).await; } if worker_mode { - reload_job_default_timeout_setting(&db).await; - reload_extra_pip_index_url_setting(&db).await; - reload_pip_index_url_setting(&db).await; - reload_npm_config_registry_setting(&db).await; - reload_bunfig_install_scopes_setting(&db).await; - reload_instance_python_version_setting(&db).await; - reload_nuget_config_setting(&db).await; + reload_job_default_timeout_setting(&conn).await; + reload_extra_pip_index_url_setting(&conn).await; + reload_pip_index_url_setting(&conn).await; + reload_npm_config_registry_setting(&conn).await; + reload_bunfig_install_scopes_setting(&conn).await; + reload_instance_python_version_setting(&conn).await; + reload_nuget_config_setting(&conn).await; + reload_maven_repos_setting(&conn).await; + reload_no_default_maven_setting(&conn).await; } } -pub async fn load_metrics_enabled(db: &DB) -> error::Result<()> { - let metrics_enabled = load_value_from_global_settings(db, EXPOSE_METRICS_SETTING).await; +pub async fn load_metrics_enabled(conn: &Connection) -> error::Result<()> { + let metrics_enabled = load_value_from_global_settings_with_conn(conn, EXPOSE_METRICS_SETTING, true).await; match metrics_enabled { Ok(Some(serde_json::Value::Bool(t))) => METRICS_ENABLED.store(t, Ordering::Relaxed), _ => (), @@ -198,14 +233,6 @@ pub async fn load_metrics_enabled(db: &DB) -> error::Result<()> { Ok(()) } -fn empty_string_as_none<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let option = as serde::Deserialize>::deserialize(deserializer)?; - Ok(option.filter(|s| !s.is_empty())) -} - #[derive(serde::Deserialize)] struct OtelSetting { metrics_enabled: Option, @@ -313,26 +340,18 @@ pub async fn load_tag_per_workspace_workspaces(db: &DB) -> error::Result<()> { Ok(()) } -pub async fn reload_critical_alert_mute_ui_setting(db: &DB) -> error::Result<()> { +pub async fn reload_critical_alert_mute_ui_setting(conn: &Connection) -> error::Result<()> { if let Ok(Some(serde_json::Value::Bool(t))) = - load_value_from_global_settings(db, CRITICAL_ALERT_MUTE_UI_SETTING).await + load_value_from_global_settings_with_conn(conn, CRITICAL_ALERT_MUTE_UI_SETTING, true).await { CRITICAL_ALERT_MUTE_UI_ENABLED.store(t, Ordering::Relaxed); - if t { - if let Err(e) = sqlx::query!("UPDATE alerts SET acknowledged = true") - .execute(db) - .await - { - tracing::error!("Error updating alerts: {}", e.to_string()); - } - } } Ok(()) } -pub async fn load_metrics_debug_enabled(db: &DB) -> error::Result<()> { - let metrics_enabled = load_value_from_global_settings(db, EXPOSE_DEBUG_METRICS_SETTING).await; +pub async fn load_metrics_debug_enabled(conn: &Connection) -> error::Result<()> { + let metrics_enabled = load_value_from_global_settings_with_conn(conn, EXPOSE_DEBUG_METRICS_SETTING, true).await; match metrics_enabled { Ok(Some(serde_json::Value::Bool(t))) => { METRICS_DEBUG_ENABLED.store(t, Ordering::Relaxed); @@ -483,8 +502,8 @@ fn get_worker_group(mode: &Mode) -> Option { } } -pub fn send_logs_to_object_store(db: &DB, hostname: &str, mode: &Mode) { - let db = db.clone(); +pub fn send_logs_to_object_store(conn: &Connection, hostname: &str, mode: &Mode) { + let conn = conn.clone(); let hostname = hostname.to_string(); let mode = mode.clone(); let worker_group = get_worker_group(&mode); @@ -499,7 +518,7 @@ pub fn send_logs_to_object_store(db: &DB, hostname: &str, mode: &Mode) { &hostname, &mode, &worker_group, - &db, + &conn, snd_highest_file, false, ) @@ -508,11 +527,11 @@ pub fn send_logs_to_object_store(db: &DB, hostname: &str, mode: &Mode) { }); } -pub async fn send_current_log_file_to_object_store(db: &DB, hostname: &str, mode: &Mode) { +pub async fn send_current_log_file_to_object_store(conn: &Connection, hostname: &str, mode: &Mode) { tracing::info!("Sending current log file to object store"); let (highest_file, _) = find_two_highest_files(hostname).await; let worker_group = get_worker_group(&mode); - send_log_file_to_object_store(hostname, mode, &worker_group, db, highest_file, true).await; + send_log_file_to_object_store(hostname, mode, &worker_group, conn, highest_file, true).await; } fn get_now_and_str() -> (NaiveDateTime, String) { @@ -524,11 +543,15 @@ fn get_now_and_str() -> (NaiveDateTime, String) { ) } +lazy_static::lazy_static! { + static ref LAST_LOG_FILE_SENT: Arc>> = Arc::new(Mutex::new(None)); +} + async fn send_log_file_to_object_store( hostname: &str, mode: &Mode, worker_group: &Option, - db: &Pool, + conn: &Connection, snd_highest_file: Option, use_now: bool, ) { @@ -551,23 +574,12 @@ async fn send_log_file_to_object_store( .unwrap_or_else(get_now_and_str) }; - let exists = sqlx::query_scalar!( - "SELECT EXISTS(SELECT 1 FROM log_file WHERE hostname = $1 AND log_ts = $2)", - hostname, - ts - ) - .fetch_one(db) - .await; + let exists = LAST_LOG_FILE_SENT.lock().map(|last_log_file_sent| { + last_log_file_sent.map(|last_log_file_sent| last_log_file_sent >= ts).unwrap_or(false) + }); - match exists { - Ok(Some(true)) => { - return; - } - Err(e) => { - tracing::error!("Error checking if log file exists: {:?}", e); - return; - } - _ => (), + if exists.unwrap_or(false) { + return; } #[cfg(feature = "parquet")] @@ -599,11 +611,23 @@ async fn send_log_file_to_object_store( let (ok_lines, err_lines) = read_log_counters(ts_str); - if let Err(e) = sqlx::query!("INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7, $8)", - hostname, mode.to_string(), worker_group.clone(), ts, highest_file, ok_lines as i64, err_lines as i64, *JSON_FMT) - .execute(db) - .await { - tracing::error!("Error inserting log file: {:?}", e); + if let Some(db) = conn.as_sql() { + if let Err(e) = sqlx::query!("INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7, $8)", + hostname, mode.to_string(), worker_group.clone(), ts, highest_file, ok_lines as i64, err_lines as i64, *JSON_FMT) + .execute(db) + .await { + tracing::error!("Error inserting log file: {:?}", e); + } else { + if let Err(e) = LAST_LOG_FILE_SENT.lock().map(|mut last_log_file_sent| { + last_log_file_sent.replace(ts); + }) { + tracing::error!("Error updating last log file sent: {:?}", e); + } + tracing::info!("Log file sent: {}", highest_file); + } + } else { + // tracing::warn!("Not sending log file to object store in agent mode"); + () } } } @@ -626,8 +650,8 @@ fn read_log_counters(ts_str: String) -> (usize, usize) { (ok_lines, err_lines) } -pub async fn load_keep_job_dir(db: &DB) { - let value = load_value_from_global_settings(db, KEEP_JOB_DIR_SETTING).await; +pub async fn load_keep_job_dir(conn: &Connection) { + let value = load_value_from_global_settings_with_conn(conn, KEEP_JOB_DIR_SETTING, true).await; match value { Ok(Some(serde_json::Value::Bool(t))) => KEEP_JOB_DIR.store(t, Ordering::Relaxed), Err(e) => { @@ -894,23 +918,23 @@ async fn delete_log_files_from_disk_and_store( let _: Vec<_> = delete_futures.collect().await; } -pub async fn reload_scim_token_setting(db: &DB) { - reload_option_setting_with_tracing(db, SCIM_TOKEN_SETTING, "SCIM_TOKEN", SCIM_TOKEN.clone()) +pub async fn reload_scim_token_setting(conn: &Connection) { + reload_option_setting_with_tracing(conn, SCIM_TOKEN_SETTING, "SCIM_TOKEN", SCIM_TOKEN.clone()) .await; } -pub async fn reload_timeout_wait_result_setting(db: &DB) { +pub async fn reload_timeout_wait_result_setting(conn: &Connection) { reload_option_setting_with_tracing( - db, + conn, TIMEOUT_WAIT_RESULT_SETTING, "TIMEOUT_WAIT_RESULT", TIMEOUT_WAIT_RESULT.clone(), ) .await; } -pub async fn reload_saml_metadata_setting(db: &DB) { +pub async fn reload_saml_metadata_setting(conn: &Connection) { reload_option_setting_with_tracing( - db, + conn, SAML_METADATA_SETTING, "SAML_METADATA", SAML_METADATA.clone(), @@ -918,9 +942,9 @@ pub async fn reload_saml_metadata_setting(db: &DB) { .await; } -pub async fn reload_extra_pip_index_url_setting(db: &DB) { +pub async fn reload_extra_pip_index_url_setting(conn: &Connection) { reload_option_setting_with_tracing( - db, + conn, EXTRA_PIP_INDEX_URL_SETTING, "PIP_EXTRA_INDEX_URL", PIP_EXTRA_INDEX_URL.clone(), @@ -928,9 +952,9 @@ pub async fn reload_extra_pip_index_url_setting(db: &DB) { .await; } -pub async fn reload_pip_index_url_setting(db: &DB) { +pub async fn reload_pip_index_url_setting(conn: &Connection) { reload_option_setting_with_tracing( - db, + conn, PIP_INDEX_URL_SETTING, "PIP_INDEX_URL", PIP_INDEX_URL.clone(), @@ -938,9 +962,9 @@ pub async fn reload_pip_index_url_setting(db: &DB) { .await; } -pub async fn reload_instance_python_version_setting(db: &DB) { +pub async fn reload_instance_python_version_setting(conn: &Connection) { reload_option_setting_with_tracing( - db, + conn, INSTANCE_PYTHON_VERSION_SETTING, "INSTANCE_PYTHON_VERSION", INSTANCE_PYTHON_VERSION.clone(), @@ -948,9 +972,9 @@ pub async fn reload_instance_python_version_setting(db: &DB) { .await; } -pub async fn reload_npm_config_registry_setting(db: &DB) { +pub async fn reload_npm_config_registry_setting(conn: &Connection) { reload_option_setting_with_tracing( - db, + conn, NPM_CONFIG_REGISTRY_SETTING, "NPM_CONFIG_REGISTRY", NPM_CONFIG_REGISTRY.clone(), @@ -958,9 +982,9 @@ pub async fn reload_npm_config_registry_setting(db: &DB) { .await; } -pub async fn reload_bunfig_install_scopes_setting(db: &DB) { +pub async fn reload_bunfig_install_scopes_setting(conn: &Connection) { reload_option_setting_with_tracing( - db, + conn, BUNFIG_INSTALL_SCOPES_SETTING, "BUNFIG_INSTALL_SCOPES", BUNFIG_INSTALL_SCOPES.clone(), @@ -968,19 +992,33 @@ pub async fn reload_bunfig_install_scopes_setting(db: &DB) { .await; } -pub async fn reload_nuget_config_setting(db: &DB) { +pub async fn reload_nuget_config_setting(conn: &Connection) { reload_option_setting_with_tracing( - db, + conn, NUGET_CONFIG_SETTING, "NUGET_CONFIG", NUGET_CONFIG.clone(), ) .await; } +pub async fn reload_maven_repos_setting(conn: &Connection) { + reload_option_setting_with_tracing(conn, windmill_common::global_settings::MAVEN_REPOS_SETTING, "MAVEN_REPOS", MAVEN_REPOS.clone()) + .await; +} +pub async fn reload_no_default_maven_setting(conn: &Connection) { + let value = load_value_from_global_settings_with_conn(conn, windmill_common::global_settings::NO_DEFAULT_MAVEN_SETTING, true).await; + match value { + Ok(Some(serde_json::Value::Bool(t))) => NO_DEFAULT_MAVEN.store(t, Ordering::Relaxed), + Err(e) => { + tracing::error!("Error loading no default maven repository: {e:#}"); + } + _ => (), + }; +} -pub async fn reload_retention_period_setting(db: &DB) { +pub async fn reload_retention_period_setting(conn: &Connection) { if let Err(e) = reload_setting( - db, + conn, RETENTION_PERIOD_SECS_SETTING, "JOB_RETENTION_SECS", 60 * 60 * 24 * 30, @@ -992,9 +1030,9 @@ pub async fn reload_retention_period_setting(db: &DB) { tracing::error!("Error reloading retention period: {:?}", e) } } -pub async fn reload_delete_logs_periodically_setting(db: &DB) { +pub async fn reload_delete_logs_periodically_setting(conn: &Connection) { if let Err(e) = reload_setting( - db, + conn, MONITOR_LOGS_ON_OBJECT_STORE_SETTING, "MONITOR_LOGS_ON_OBJECT_STORE", false, @@ -1062,9 +1100,9 @@ pub async fn reload_s3_cache_setting(db: &DB) { } } -pub async fn reload_job_default_timeout_setting(db: &DB) { +pub async fn reload_job_default_timeout_setting(conn: &Connection) { reload_option_setting_with_tracing( - db, + conn, JOB_DEFAULT_TIMEOUT_SECS_SETTING, "JOB_DEFAULT_TIMEOUT_SECS", JOB_DEFAULT_TIMEOUT.clone(), @@ -1072,9 +1110,9 @@ pub async fn reload_job_default_timeout_setting(db: &DB) { .await; } -pub async fn reload_request_size(db: &DB) { +pub async fn reload_request_size(conn: &Connection) { if let Err(e) = reload_setting( - db, + conn, REQUEST_SIZE_LIMIT_SETTING, "REQUEST_SIZE_LIMIT", DEFAULT_BODY_LIMIT, @@ -1087,8 +1125,8 @@ pub async fn reload_request_size(db: &DB) { } } -pub async fn reload_license_key(db: &DB) -> anyhow::Result<()> { - let q = load_value_from_global_settings(db, LICENSE_KEY_SETTING) +pub async fn reload_license_key(conn: &Connection) -> anyhow::Result<()> { + let q = load_value_from_global_settings_with_conn(conn, LICENSE_KEY_SETTING, true) .await .map_err(|err| anyhow::anyhow!("Error reloading license key: {}", err.to_string()))?; @@ -1113,12 +1151,12 @@ pub async fn reload_license_key(db: &DB) -> anyhow::Result<()> { } pub async fn reload_option_setting_with_tracing( - db: &DB, + conn: &Connection, setting_name: &str, std_env_var: &str, lock: Arc>>, ) { - if let Err(e) = reload_option_setting(db, setting_name, std_env_var, lock.clone()).await { + if let Err(e) = reload_option_setting(conn, setting_name, std_env_var, lock.clone()).await { tracing::error!("Error reloading setting {}: {:?}", setting_name, e) } } @@ -1137,8 +1175,28 @@ pub async fn load_value_from_global_settings( Ok(r) } + +pub async fn load_value_from_global_settings_with_conn( + conn: &Connection, + setting_name: &str, + load_from_http: bool, +) -> anyhow::Result> { + match conn { + Connection::Sql(db) => Ok(load_value_from_global_settings(db, setting_name).await?), + Connection::Http(client) => { + if load_from_http { + client.get::>(&format!("/api/agent_workers/get_global_setting/{}", setting_name)).await + .map_err(|e| anyhow::anyhow!("Error loading setting {}: {}", setting_name, e)) + } else { + Ok(None) + } + } + } + +} + pub async fn reload_option_setting( - db: &DB, + conn: &Connection, setting_name: &str, std_env_var: &str, lock: Arc>>, @@ -1153,7 +1211,7 @@ pub async fn reload_option_setting( return Ok(()); } - let q = load_value_from_global_settings(db, setting_name).await?; + let q = load_value_from_global_settings_with_conn(conn, setting_name, true).await?; let mut value = std::env::var(std_env_var) .ok() @@ -1180,14 +1238,14 @@ pub async fn reload_option_setting( } pub async fn reload_setting( - db: &DB, + conn: &Connection, setting_name: &str, std_env_var: &str, default: T, lock: Arc>, transformer: fn(T) -> T, ) -> error::Result<()> { - let q = load_value_from_global_settings(db, setting_name).await?; + let q = load_value_from_global_settings_with_conn(conn, setting_name, true).await?; let mut value = std::env::var(std_env_var) .ok() @@ -1245,27 +1303,32 @@ pub async fn monitor_pool(db: &DB) { } pub async fn monitor_db( - db: &Pool, + conn: &Connection, base_internal_url: &str, server_mode: bool, _worker_mode: bool, initial_load: bool, _killpill_tx: KillpillSender, ) { + tracing::info!("Starting periodic monitor task"); let zombie_jobs_f = async { - if server_mode && !initial_load { + if server_mode && !initial_load && !*DISABLE_ZOMBIE_JOBS_MONITORING { + if let Some(db) = conn.as_sql() { handle_zombie_jobs(db, base_internal_url, "server").await; match handle_zombie_flows(db).await { Err(err) => { tracing::error!("Error handling zombie flows: {:?}", err); - } + }, _ => {} + } } } }; let expired_items_f = async { if server_mode && !initial_load { + if let Some(db) = conn.as_sql() { delete_expired_items(&db).await; + } } }; @@ -1278,35 +1341,43 @@ pub async fn monitor_db( let expose_queue_metrics_f = async { if !initial_load && server_mode { - expose_queue_metrics(&db).await; + if let Some(db) = conn.as_sql() { + expose_queue_metrics(&db).await; + } } }; let worker_groups_alerts_f = async { #[cfg(feature = "enterprise")] if server_mode && !initial_load { - worker_groups_alerts(&db).await; + if let Some(db) = conn.as_sql() { + worker_groups_alerts(&db).await; + } } }; let jobs_waiting_alerts_f = async { #[cfg(feature = "enterprise")] if server_mode { - jobs_waiting_alerts(&db).await; + if let Some(db) = conn.as_sql() { + jobs_waiting_alerts(&db).await; + } } }; let apply_autoscaling_f = async { #[cfg(feature = "enterprise")] if server_mode && !initial_load { - if let Err(e) = windmill_autoscaling::apply_all_autoscaling(db).await { - tracing::error!("Error applying autoscaling: {:?}", e); + if let Some(db) = conn.as_sql() { + if let Err(e) = windmill_autoscaling::apply_all_autoscaling(db).await { + tracing::error!("Error applying autoscaling: {:?}", e); + } } } }; let update_min_worker_version_f = async { - update_min_version(db).await; + update_min_version(conn).await; }; join!( @@ -1319,6 +1390,7 @@ pub async fn monitor_db( apply_autoscaling_f, update_min_worker_version_f, ); + tracing::info!("Periodic monitor task completed"); } pub async fn expose_queue_metrics(db: &Pool) { @@ -1429,7 +1501,7 @@ pub async fn reload_worker_config( tx: KillpillSender, kill_if_change: bool, ) { - let config = load_worker_config(&db, tx.clone()).await; + let config = load_worker_config(db, tx.clone()).await; if let Err(e) = config { tracing::error!("Error reloading worker config: {:?}", e) } else { @@ -1463,15 +1535,15 @@ pub async fn reload_worker_config( let mut wc = WORKER_CONFIG.write().await; tracing::info!("Reloading worker config..."); - make_suspended_pull_query(&config).await; - make_pull_query(&config).await; + store_suspended_pull_query(&config).await; + store_pull_query(&config).await; *wc = config } } } -pub async fn load_base_url(db: &DB) -> error::Result { - let q_base_url = load_value_from_global_settings(db, BASE_URL_SETTING).await?; +pub async fn load_base_url(conn: &Connection) -> error::Result { + let q_base_url = load_value_from_global_settings_with_conn(conn, BASE_URL_SETTING, false).await?; let std_base_url = std::env::var("BASE_URL") .ok() @@ -1501,34 +1573,39 @@ pub async fn load_base_url(db: &DB) -> error::Result { Ok(base_url) } -pub async fn reload_base_url_setting(db: &DB) -> error::Result<()> { - #[cfg(feature = "oauth2")] - let q_oauth = load_value_from_global_settings(db, OAUTH_SETTING).await?; +pub async fn reload_base_url_setting(conn: &Connection) -> error::Result<()> { #[cfg(feature = "oauth2")] - let oauths = if let Some(q) = q_oauth { - if let Ok(v) = serde_json::from_value::< - Option>, - >(q.clone()) - { - v + let oauths = if let Some(db) = conn.as_sql() { + let q_oauth = load_value_from_global_settings (db, OAUTH_SETTING).await?; + + if let Some(q) = q_oauth { + if let Ok(v) = serde_json::from_value::< + Option>, + >(q.clone()) + { + v + } else { + tracing::error!("Could not parse oauth setting as a json, found: {:#?}", &q); + None + } } else { - tracing::error!("Could not parse oauth setting as a json, found: {:#?}", &q); None } } else { None }; - - let base_url = load_base_url(db).await?; + let base_url = load_base_url(conn).await?; let is_secure = base_url.starts_with("https://"); #[cfg(feature = "oauth2")] { - let mut l = windmill_api::OAUTH_CLIENTS.write().await; - *l = windmill_api::oauth2_ee::build_oauth_clients(&base_url, oauths, db).await - .map_err(|e| tracing::error!("Error building oauth clients (is the oauth.json mounted and in correct format? Use '{}' as minimal oauth.json): {}", "{}", e)) - .unwrap(); + if let Some(db) = conn.as_sql() { + let mut l = windmill_api::OAUTH_CLIENTS.write().await; + *l = windmill_api::oauth2_ee::build_oauth_clients(&base_url, oauths, db).await + .map_err(|e| tracing::error!("Error building oauth clients (is the oauth.json mounted and in correct format? Use '{}' as minimal oauth.json): {}", "{}", e)) + .unwrap(); + } } { @@ -1786,7 +1863,7 @@ async fn handle_zombie_jobs(db: &Pool, base_internal_url: &str, worker mpsc::channel::(1); let same_worker_tx_never_used = SameWorkerSender(same_worker_tx_never_used, Arc::new(AtomicU16::new(0))); - let (send_result_never_used, _send_result_rx_never_used) = mpsc::channel::(1); + let (send_result_never_used, _send_result_rx_never_used) = JobCompletedSender::new_never_used(); let label = if job.permissioned_as != format!("u/{}", job.created_by) && job.permissioned_as != job.created_by @@ -1837,7 +1914,7 @@ async fn handle_zombie_jobs(db: &Pool, base_internal_url: &str, worker worker_name, send_result_never_used, #[cfg(feature = "benchmark")] - &mut windmill_worker::bench::BenchmarkIter::new(), + &mut windmill_common::bench::BenchmarkIter::new(), ) .await; } @@ -1996,8 +2073,8 @@ async fn cancel_zombie_flow_job( Ok(()) } -pub async fn reload_hub_base_url_setting(db: &DB, server_mode: bool) -> error::Result<()> { - let hub_base_url = load_value_from_global_settings(db, HUB_BASE_URL_SETTING).await?; +pub async fn reload_hub_base_url_setting(conn: &Connection, server_mode: bool) -> error::Result<()> { + let hub_base_url = load_value_from_global_settings_with_conn(conn, HUB_BASE_URL_SETTING, true).await?; let base_url = if let Some(q) = hub_base_url { if let Ok(v) = serde_json::from_value::(q.clone()) { @@ -2020,16 +2097,18 @@ pub async fn reload_hub_base_url_setting(db: &DB, server_mode: bool) -> error::R let mut l = HUB_BASE_URL.write().await; if server_mode { #[cfg(feature = "embedding")] - if *l != base_url { - let disable_embedding = std::env::var("DISABLE_EMBEDDING") - .ok() - .map(|x| x.parse::().unwrap_or(false)) - .unwrap_or(false); - if !disable_embedding { - let db_clone = db.clone(); - tokio::spawn(async move { - update_embeddings_db(&db_clone).await; - }); + if let Some(db) = conn.as_sql() { + if *l != base_url { + let disable_embedding = std::env::var("DISABLE_EMBEDDING") + .ok() + .map(|x| x.parse::().unwrap_or(false)) + .unwrap_or(false); + if !disable_embedding { + let db_clone = db.clone(); + tokio::spawn(async move { + update_embeddings_db(&db_clone).await; + }); + } } } } @@ -2038,9 +2117,9 @@ pub async fn reload_hub_base_url_setting(db: &DB, server_mode: bool) -> error::R Ok(()) } -pub async fn reload_critical_error_channels_setting(db: &DB) -> error::Result<()> { +pub async fn reload_critical_error_channels_setting(conn: &DB) -> error::Result<()> { let critical_error_channels = - load_value_from_global_settings(db, CRITICAL_ERROR_CHANNELS_SETTING).await?; + load_value_from_global_settings(conn, CRITICAL_ERROR_CHANNELS_SETTING).await?; let critical_error_channels = if let Some(q) = critical_error_channels { if let Ok(v) = serde_json::from_value::>(q.clone()) { diff --git a/backend/tests/fixtures/lockfile_python.sql b/backend/tests/fixtures/lockfile_python.sql new file mode 100644 index 0000000000..27f7b103f0 --- /dev/null +++ b/backend/tests/fixtures/lockfile_python.sql @@ -0,0 +1,51 @@ +INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock) VALUES ( +'test-workspace', +'test-user', +' +# requirements: +# microdot==2.2.0 + +import pandas +import requests +import tiny # pin: tiny==0.1.2 + +def main(): + pass +', +'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}', +'', +'', +'f/system/requirements', 12346, 'python3', ''); + +INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock) VALUES ( +'test-workspace', +'test-user', +' +# extra_requirements: +# bottle==0.13.2 + +import tiny + +def main(): + pass +', +'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}', +'', +'', +'f/system/extra_requirements', 12347, 'python3', ''); + + +INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock) VALUES ( +'test-workspace', +'test-user', +' +import tiny # pin: bottle==0.13.2 +import simplejson # pin: simplejson==3.19.3 + +def main(): + return [test1(), test2(), test3(), test4()] +', +'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}', +'', +'', +'f/system/pins', 12348, 'python3', ''); diff --git a/backend/tests/worker.rs b/backend/tests/worker.rs index 2c1e47f2af..182ed60f2e 100644 --- a/backend/tests/worker.rs +++ b/backend/tests/worker.rs @@ -137,7 +137,6 @@ impl ApiServer { rx, port_tx, false, - #[cfg(feature = "smtp")] format!("http://localhost:{}", addr.port()), )); @@ -315,7 +314,7 @@ mod suspend_resume { let second = completed.next().await.unwrap(); // print_job(second, &db).await; - let token = windmill_worker::create_token_for_owner(&db, "test-workspace", "u/test-user", "", 100, "", &Uuid::nil(), None).await.unwrap(); + let token = windmill_common::auth::create_token_for_owner(&db, "test-workspace", "u/test-user", "", 100, "", &Uuid::nil(), None).await.unwrap(); let secret = reqwest::get(format!( "http://localhost:{port}/api/w/test-workspace/jobs/job_signature/{second}/0?token={token}&approver=ruben" )) @@ -418,7 +417,7 @@ mod suspend_resume { /* ... and send a request resume it. */ let second = completed.next().await.unwrap(); - let token = windmill_worker::create_token_for_owner(&db, "test-workspace", "u/test-user", "", 100, "", &Uuid::nil(), None).await.unwrap(); + let token = windmill_common::auth::create_token_for_owner(&db, "test-workspace", "u/test-user", "", 100, "", &Uuid::nil(), None).await.unwrap(); let secret = reqwest::get(format!( "http://localhost:{port}/api/w/test-workspace/jobs/job_signature/{second}/0?token={token}" )) @@ -1033,11 +1032,11 @@ fn spawn_test_worker( priority: 0, tags: (*wc).worker_tags.clone(), }]; - windmill_common::worker::make_suspended_pull_query(&wc).await; - windmill_common::worker::make_pull_query(&wc).await; + windmill_common::worker::store_suspended_pull_query(&wc).await; + windmill_common::worker::store_pull_query(&wc).await; } windmill_worker::run_worker( - &db, + &db.into(), worker_instance, worker_name, 1, @@ -1046,7 +1045,6 @@ fn spawn_test_worker( rx, tx2, &base_internal_url, - false, ) .await }; @@ -1988,6 +1986,51 @@ def main [ assert_eq!(result, serde_json::json!(0)); } +#[cfg(feature = "java")] +#[sqlx::test(fixtures("base"))] +async fn test_java_job(db: Pool) { + initialize_tracing().await; + let server = ApiServer::start(db.clone()).await; + let port = server.addr.port(); + + let content = r#" +public class Main { + public static Object main( + // Primitive + int a, + float b, + // Objects + Integer age, + Float d + ){ + return "hello world"; + } +} + +"# + .to_owned(); + + let job = RunJob::from(JobPayload::Code(RawCode { + hash: None, + content, + path: None, + lock: None, + language: ScriptLang::Java, + custom_concurrency_key: None, + concurrent_limit: None, + concurrency_time_window_s: None, + cache_ttl: None, + dedicated_worker: None, + })) + .arg("a", json!(3)) + .arg("b", json!(3.0)) + .arg("age", json!(30)) + .arg("d", json!(3.0)) + .run_until_complete(&db, port) + .await; + assert_eq!(job.json_result(), Some(json!("hello world"))); +} + #[sqlx::test(fixtures("base"))] async fn test_python_job(db: Pool) { initialize_tracing().await; @@ -3788,6 +3831,209 @@ def main(): run_preview_relative_imports(&db, content, ScriptLang::Python3).await; } +async fn assert_lockfile( + db: &Pool, + script_content: String, + language: ScriptLang, + expected_lines: Vec<&str>, +) { + initialize_tracing().await; + let server = ApiServer::start(db.clone()).await; + let port = server.addr.port(); + let client = windmill_api_client::create_client( + &format!("http://localhost:{port}"), + "SECRET_TOKEN".to_string(), + ); + + client + .create_script( + "test-workspace", + &NewScript { + language: NewScriptLanguage::from_str(language.as_str()).unwrap(), + content: script_content, + path: "f/system/test_import".to_string(), + concurrent_limit: None, + concurrency_time_window_s: None, + cache_ttl: None, + dedicated_worker: None, + description: "".to_string(), + draft_only: None, + envs: vec![], + is_template: None, + kind: None, + parent_hash: None, + lock: None, + summary: "".to_string(), + tag: None, + schema: std::collections::HashMap::new(), + ws_error_handler_muted: Some(false), + priority: None, + delete_after_use: None, + timeout: None, + restart_unless_cancelled: None, + deployment_message: None, + concurrency_key: None, + visible_to_runner_only: None, + no_main_func: None, + codebase: None, + has_preprocessor: None, + on_behalf_of_email: None, + }, + ) + .await + .unwrap(); + + let mut completed = listen_for_completed_jobs(&db).await; + let db2 = db.clone(); + in_test_worker( + &db, + async move { + completed.next().await; // deployed script + + let script = sqlx::query!( + "SELECT hash FROM script WHERE path = $1", + "f/system/test_import".to_string() + ) + .fetch_one(&db2) + .await + .unwrap(); + + let job = RunJob::from(JobPayload::Dependencies { + path: "f/system/test_import".to_string(), + hash: ScriptHash(script.hash), + dedicated_worker: None, + language, + }) + .push(&db2) + .await; + + completed.next().await; // completed job + + let result = completed_job(job, &db2).await.json_result().unwrap(); + + assert_eq!( + result, + json!({ + "lock": expected_lines.join("\n"), + "status": "Successful lock file generation" + }) + ); + }, + port, + ) + .await; +} +#[sqlx::test(fixtures("base", "lockfile_python"))] +async fn test_requirements_python(db: Pool) { + let content = r#" +# py311 +# requirements: +# tiny==0.1.3 + +import bar +import baz # pin: foo +import baz # repin: fee +import bug # repin: free + +def main(): + pass +"# + .to_string(); + + assert_lockfile( + &db, + content, + ScriptLang::Python3, + vec!["# py311", "tiny==0.1.3"], + ) + .await; +} +#[sqlx::test(fixtures("base", "lockfile_python"))] +async fn test_extra_requirements_python(db: Pool) { + { + let content = r#" +# py311 +# extra_requirements: +# tiny + +import f.system.extra_requirements +import tiny # pin: tiny==0.1.0 +import tiny # pin: tiny==0.1.1 +import tiny # repin: tiny==0.1.2 + +def main(): + pass + "# + .to_string(); + + assert_lockfile( + &db, + content, + ScriptLang::Python3, + vec!["# py311", "bottle==0.13.2", "tiny==0.1.2"], + ) + .await; + } +} +#[sqlx::test(fixtures("base", "lockfile_python"))] +async fn test_extra_requirements_python2(db: Pool) { + + let content = r#" +# py311 +# extra_requirements: +# tiny==0.1.3 + +import simplejson # pin: simplejson==3.20.1 +def main(): + pass +"# + .to_string(); + + assert_lockfile( + &db, + content, + ScriptLang::Python3, + vec![ + "# py311", + "simplejson==3.20.1", + "tiny==0.1.3" + ], + ) + .await; + +} + +#[sqlx::test(fixtures("base", "lockfile_python"))] +async fn test_pins_python(db: Pool) { + let content = r#" +# py311 +# extra_requirements: +# tiny==0.1.3 + +import f.system.requirements +import f.system.pins +import tiny # repin: bottle==0.13.0 +import simplejson + +def main(): + pass +"# + .to_string(); + + assert_lockfile( + &db, + content, + ScriptLang::Python3, + vec![ + "# py311", + "bottle==0.13.0", + "microdot==2.2.0", + "simplejson==3.19.3", + "tiny==0.1.3" + ], + ) + .await; +} #[sqlx::test(fixtures("base", "result_format"))] async fn test_result_format(db: Pool) { let ordered_result_job_id = "1eecb96a-c8b0-4a3d-b1b6-087878c55e41"; @@ -3798,7 +4044,7 @@ async fn test_result_format(db: Pool) { let port = server.addr.port(); - let token = windmill_worker::create_token_for_owner( + let token = windmill_common::auth::create_token_for_owner( &db, "test-workspace", "u/test-user", @@ -3839,7 +4085,7 @@ async fn test_result_format(db: Pool) { assert_eq!(job_result.get(), correct_result); let response = windmill_api::jobs::run_wait_result( - &db, + &db.into(), Uuid::parse_str(ordered_result_job_id).unwrap(), "test-workspace".to_string(), None, diff --git a/backend/windmill-api-client/codegen.rs b/backend/windmill-api-client/codegen.rs index 2e91abc036..ec1a363f88 100644 --- a/backend/windmill-api-client/codegen.rs +++ b/backend/windmill-api-client/codegen.rs @@ -2261,6 +2261,8 @@ the execution of this script will be permissioned_as and by extension its DT_TOK #[serde(default, skip_serializing_if = "Option::is_none")] pub summary: Option, #[serde(default, skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] pub tag: Option, pub timezone: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -6212,6 +6214,8 @@ the execution of this script will be permissioned_as and by extension its DT_TOK #[serde(default, skip_serializing_if = "Option::is_none")] pub summary: Option, #[serde(default, skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] pub tag: Option, pub timezone: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -7940,6 +7944,8 @@ the execution of this script will be permissioned_as and by extension its DT_TOK #[serde(default, skip_serializing_if = "Option::is_none")] pub summary: Option, #[serde(default, skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] pub tag: Option, pub timezone: String, #[serde(default, skip_serializing_if = "Option::is_none")] diff --git a/backend/windmill-api-client/src/codegen.rs b/backend/windmill-api-client/src/codegen.rs index 9ca3abdc91..2ee220f87d 100644 --- a/backend/windmill-api-client/src/codegen.rs +++ b/backend/windmill-api-client/src/codegen.rs @@ -5420,6 +5420,8 @@ the execution of this script will be permissioned_as and by extension its DT_TOK #[serde(default, skip_serializing_if = "Option::is_none")] pub summary: Option, #[serde(default, skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] pub tag: Option, pub timezone: String, #[serde(default, skip_serializing_if = "Option::is_none")] diff --git a/backend/windmill-api/Cargo.toml b/backend/windmill-api/Cargo.toml index 97928baa19..0996b5956d 100644 --- a/backend/windmill-api/Cargo.toml +++ b/backend/windmill-api/Cargo.toml @@ -10,13 +10,14 @@ path = "src/lib.rs" [features] default = [] -enterprise = ["windmill-queue/enterprise", "windmill-audit/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise"] -stripe = ["dep:async-stripe"] +enterprise = ["windmill-queue/enterprise", "windmill-audit/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise", "windmill-worker/enterprise"] +stripe = [] +agent_worker_server = [] enterprise_saml = ["dep:samael"] benchmark = [] embedding = ["dep:tinyvector", "dep:hf-hub", "dep:tokenizers", "dep:candle-core", "dep:candle-transformers", "dep:candle-nn", "dep:half"] -parquet = ["dep:datafusion", "dep:object_store", "dep:url", "windmill-common/parquet"] -prometheus = ["windmill-common/prometheus", "windmill-queue/prometheus", "dep:prometheus"] +parquet = ["dep:datafusion", "dep:object_store", "dep:url", "windmill-common/parquet", "windmill-worker/parquet"] +prometheus = ["windmill-common/prometheus", "windmill-queue/prometheus", "dep:prometheus", "windmill-worker/prometheus"] openidconnect = ["dep:openidconnect"] tantivy = ["dep:windmill-indexer"] kafka = ["dep:rdkafka"] @@ -26,11 +27,13 @@ smtp = ["dep:mail-parser", "dep:openssl", "windmill-common/smtp"] license = ["dep:rsa"] zip = ["dep:async_zip"] oauth2 = ["dep:async-oauth2"] -http_trigger = ["dep:matchit"] +http_trigger = ["dep:matchit", "dep:thiserror", "dep:sha1", "dep:constant_time_eq"] static_frontend = ["dep:rust-embed"] postgres_trigger = ["dep:rust-postgres", "dep:pg_escape", "dep:byteorder", "dep:thiserror", "dep:rust_decimal", "dep:rust-postgres-native-tls"] mqtt_trigger = ["dep:thiserror", "dep:rumqttc"] sqs_trigger = ["dep:aws-sdk-sqs", "dep:thiserror", "dep:aws-config"] +deno_core = ["dep:deno_core", "dep:deno_error"] +gcp_trigger = ["dep:thiserror", "dep:google-cloud-pubsub", "dep:google-cloud-googleapis", "dep:tonic"] cloud = ["windmill-common/cloud"] [dependencies] @@ -40,9 +43,12 @@ windmill-audit.workspace = true windmill-parser.workspace = true windmill-parser-ts.workspace = true windmill-parser-py.workspace = true +windmill-parser-py-imports.workspace = true windmill-git-sync.workspace = true windmill-indexer = { workspace = true, optional = true } +windmill-worker.workspace = true tokio.workspace = true +tokio-stream.workspace = true anyhow.workspace = true argon2.workspace = true axum.workspace = true @@ -85,8 +91,9 @@ tokio-tar.workspace = true hmac.workspace = true cookie.workspace = true sha2.workspace = true +sha1 = { workspace = true, optional = true } +constant_time_eq = { workspace = true, optional = true } urlencoding.workspace = true -async-stripe = { workspace = true, optional = true } lazy_static.workspace = true prometheus = { workspace = true, optional = true } async_zip = { workspace = true, optional = true } @@ -125,4 +132,12 @@ rust_decimal = { workspace = true, optional = true } rust-postgres-native-tls = { workspace = true, optional = true} rumqttc = { workspace = true, optional = true } aws-sdk-sqs = { workspace = true, optional = true } -aws-config = { workspace = true, optional = true} +aws-config = { workspace = true, optional = true } +google-cloud-pubsub = { workspace = true, optional = true } +google-cloud-googleapis = { workspace = true , optional = true } +tonic = { workspace = true, optional = true } +deno_error = { workspace = true, optional = true } +deno_core = { workspace = true, optional = true } + +[build-dependencies] +deno_core = { workspace = true, optional = true } \ No newline at end of file diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 3d73899486..5ed6537931 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.478.1 + version: 1.481.0 title: Windmill API contact: @@ -573,6 +573,20 @@ paths: schema: type: string + /github_app/connected_repositories: + get: + summary: get connected repositories + operationId: getGlobalConnectedRepositories + tags: + - git_sync + responses: + "200": + description: connected repositories + content: + application/json: + schema: + $ref: "#/components/schemas/GithubInstallations" + /workspaces/list: get: summary: list all workspaces visible to me @@ -1286,6 +1300,144 @@ paths: schema: $ref: "#/components/schemas/User" + /w/{workspace}/github_app/token: + post: + summary: get github app token + operationId: getGithubAppToken + tags: + - workspace + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: jwt job token + required: true + content: + application/json: + schema: + type: object + properties: + job_token: + type: string + required: + - job_token + responses: + "200": + description: github app token + content: + application/json: + schema: + type: object + properties: + token: + type: string + required: + - token + + /w/{workspace}/github_app/install_from_workspace: + post: + tags: + - Git Sync + summary: Install a GitHub installation from another workspace + operationId: installFromWorkspace + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + source_workspace_id: + type: string + description: The ID of the workspace containing the installation to copy + installation_id: + type: number + description: The ID of the GitHub installation to copy + required: + - source_workspace_id + - installation_id + responses: + "200": + description: Installation successfully copied + + /w/{workspace}/github_app/installation/{installation_id}: + delete: + summary: Delete a GitHub installation from a workspace + operationId: deleteFromWorkspace + description: Removes a GitHub installation from the specified workspace. Requires admin privileges. + tags: + - Git Sync + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - name: installation_id + in: path + required: true + schema: + type: integer + format: int64 + description: The ID of the GitHub installation to delete + responses: + "200": + description: Installation successfully deleted + + /w/{workspace}/github_app/export/{installationId}: + get: + summary: Export GitHub installation JWT token + description: Exports the JWT token for a specific GitHub installation in the workspace + operationId: exportInstallation + tags: + - Git Sync + parameters: + - name: workspace + in: path + required: true + schema: + type: string + - name: installationId + in: path + required: true + schema: + type: integer + responses: + "200": + description: Successfully exported the JWT token + content: + application/json: + schema: + type: object + properties: + jwt_token: + type: string + + /w/{workspace}/github_app/import: + post: + summary: Import GitHub installation from JWT token + description: Imports a GitHub installation from a JWT token exported from another instance + operationId: importInstallation + tags: + - Git Sync + parameters: + - name: workspace + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - jwt_token + properties: + jwt_token: + type: string + responses: + "200": + description: Successfully imported the installation + /users/accept_invite: post: summary: accept invite to workspace @@ -1639,7 +1791,7 @@ paths: schema: $ref: "#/components/schemas/OperatorSettings" responses: - '200': + "200": description: Operator settings updated successfully content: text/plain: @@ -1747,22 +1899,14 @@ paths: type: boolean plan: type: string - automatic_billing: - type: boolean customer_id: type: string webhook: type: string deploy_to: type: string - ai_resource: - $ref: "#/components/schemas/AIResource" - code_completion_model: - type: string - ai_models: - type: array - items: - type: string + ai_config: + $ref: "#/components/schemas/AIConfig" error_handler: type: string error_handler_extra_args: @@ -1786,8 +1930,6 @@ paths: operator_settings: $ref: "#/components/schemas/OperatorSettings" required: - - ai_models - - automatic_billing - error_handler_muted_on_cancel /w/{workspace}/workspaces/get_deploy_to: @@ -1848,48 +1990,14 @@ paths: type: boolean usage: type: number - seats: - type: number - automatic_billing: - type: boolean owner: type: string + status: + type: string required: - premium - - automatic_billing - owner - /w/{workspace}/workspaces/set_automatic_billing: - post: - summary: set automatic billing - operationId: setAutomaticBilling - tags: - - workspace - parameters: - - $ref: "#/components/parameters/WorkspaceId" - requestBody: - description: automatic billing - required: true - content: - application/json: - schema: - type: object - properties: - automatic_billing: - type: boolean - seats: - type: number - required: - - automatic_billing - responses: - "200": - description: status - content: - text/plain: - schema: - type: string - - /w/{workspace}/workspaces/threshold_alert: get: summary: get threshold alert info @@ -2013,7 +2121,7 @@ paths: type: string team_id: type: string - + /w/{workspace}/workspaces/available_teams_channels: get: summary: list available teams channels @@ -2102,7 +2210,7 @@ paths: properties: job_uuid: type: string - + /w/{workspace}/workspaces/run_teams_message_test_job: post: summary: run a job that sends a message to Teams @@ -2235,18 +2343,7 @@ paths: content: application/json: schema: - type: object - required: - - ai_models - properties: - ai_resource: - $ref: "#/components/schemas/AIResource" - code_completion_model: - type: string - ai_models: - type: array - items: - type: string + $ref: "#/components/schemas/AIConfig" responses: "200": description: status @@ -2268,23 +2365,9 @@ paths: "200": description: status content: - text/plain: + application/json: schema: - type: object - properties: - ai_provider: - $ref: "#/components/schemas/AIProvider" - exists_ai_resource: - type: boolean - code_completion_model: - type: string - ai_models: - type: array - items: - type: string - required: - - exists_ai_resource - - ai_models + $ref: "#/components/schemas/AIConfig" /w/{workspace}/workspaces/edit_error_handler: post: @@ -2618,6 +2701,8 @@ paths: type: boolean mqtt_used: type: boolean + gcp_used: + type: boolean sqs_used: type: boolean required: @@ -2627,6 +2712,7 @@ paths: - nats_used - postgres_used - mqtt_used + - gcp_used - sqs_used /w/{workspace}/users/list: get: @@ -3443,7 +3529,7 @@ paths: type: array items: type: string - + /teams/sync: post: operationId: syncTeams @@ -3451,14 +3537,14 @@ paths: tags: - teams responses: - '200': + "200": description: Teams information successfully synchronized content: application/json: schema: type: array items: - $ref: '#/components/schemas/TeamInfo' + $ref: "#/components/schemas/TeamInfo" /teams/activities: post: @@ -3492,7 +3578,7 @@ paths: description: The card block to be sent in the Teams card responses: - '200': + "200": description: Activity processed successfully /w/{workspace}/resources/create: @@ -4342,7 +4428,7 @@ paths: type: string - name: last_parent_hash description: | - mask to filter scripts whom last parent in the chain has exact hash. + mask to filter scripts whom last parent in the chain has exact hash. Beware that each script stores only a limited number of parents. Hence the last parent hash for a script is not necessarily its top-most parent. To find the top-most parent you will have to jump from last to last hash @@ -4363,7 +4449,7 @@ paths: (default false) show only the archived files. when multiple archived hash share the same path, only the ones with the latest create_at - are + are ed. in: query schema: @@ -4859,8 +4945,7 @@ paths: /scripts_u/tokened_raw/{workspace}/{token}/{path}: get: - summary: - raw script by path with a token (mostly used by lsp to be used with + summary: raw script by path with a token (mostly used by lsp to be used with import maps to resolve scripts) operationId: rawScriptByPathTokened tags: @@ -4954,6 +5039,63 @@ paths: lock_error_logs: type: string + /w/{workspace}/jobs/list_selected_job_groups: + # We use post because sending a huge array as a query param can produce + # URLs that may be too long + post: + summary: list selected jobs script/flow schemas grouped by (kind, path) + operationId: listSelectedJobGroups + tags: + - job + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: script args + required: true + content: + application/json: + schema: + type: array + items: + type: string + format: uuid + responses: + "200": + description: result + content: + text/plain: + schema: + type: array + items: + type: object + properties: + kind: + type: string + enum: ["script", "flow"] + script_path: + type: string + latest_schema: + type: object + schemas: + type: array + items: + type: object + properties: + schema: + type: object + script_hash: + type: string + job_ids: + type: array + items: + type: string + required: [schema, script_hash, job_ids] + required: + - kind + - script_path + - latest_schema + - schemas + /w/{workspace}/jobs/run/p/{path}: post: summary: run script by path @@ -5438,7 +5580,6 @@ paths: lock_error_logs: type: string - /w/{workspace}/flows/get_triggers_count/{path}: get: summary: get triggers count of flow @@ -6220,6 +6361,38 @@ paths: schema: type: boolean + /w/{workspace}/apps/sign_s3_objects: + post: + summary: sign s3 objects, to be used by anonymous users in public apps + operationId: signS3Objects + tags: + - app + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: s3 objects to sign + required: true + content: + application/json: + schema: + type: object + properties: + s3_objects: + type: array + items: + $ref: "#/components/schemas/S3Object" + required: + - s3_objects + responses: + "200": + description: signed s3 objects + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/S3Object" + /w/{workspace}/apps_u/execute_component/{path}: post: summary: executeComponent @@ -6404,7 +6577,6 @@ paths: in: query schema: type: boolean - requestBody: description: flow args required: true @@ -6412,7 +6584,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ScriptArgs" - responses: "201": description: job created @@ -6422,6 +6593,60 @@ paths: type: string format: uuid + /w/{workspace}/jobs/run/batch_rerun_jobs: + post: + summary: re-run multiple jobs + operationId: batchReRunJobs + tags: + - job + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: list of job ids to re run and arg tranforms + required: true + content: + application/json: + schema: + type: object + required: [job_ids, script_options_by_path, flow_options_by_path] + properties: + job_ids: + type: array + items: + type: string + script_options_by_path: + type: object + additionalProperties: + type: object + properties: + input_transforms: + type: object + additionalProperties: + $ref: "#/components/schemas/InputTransform" + use_latest_version: boolean + flow_options_by_path: + type: object + additionalProperties: + type: object + properties: + input_transforms: + type: object + additionalProperties: + $ref: "#/components/schemas/InputTransform" + use_latest_version: boolean + responses: + "201": + description: stream of created job uuids separated by \n. Lines may start with 'Error:' + example: | + a1a74c0d-708e-4539-9768-e8b3d37996bd + f0949132-5b30-48fe-bac8-873f047df810 + Error: Could not re-run 0b885808-ae89-4458-af95-c1ca3a13b0a5 + 52b9c01d-1125-4bbb-8bee-d41f26b70066 + content: + text/event-stream: + schema: + type: string + /w/{workspace}/jobs/restart/f/{id}/from/{step_id}/{branch_or_iteration_n}: post: summary: restart a completed flow at a given step @@ -6438,8 +6663,7 @@ paths: schema: type: string - name: branch_or_iteration_n - description: - for branchall or loop, the iteration at which the flow should + description: for branchall or loop, the iteration at which the flow should restart required: true in: path @@ -6702,6 +6926,7 @@ paths: - $ref: "#/components/parameters/Running" - $ref: "#/components/parameters/ArgsFilter" - $ref: "#/components/parameters/ResultFilter" + - $ref: "#/components/parameters/AllowWildcards" - $ref: "#/components/parameters/Tag" - $ref: "#/components/parameters/Page" - $ref: "#/components/parameters/PerPage" @@ -6806,10 +7031,82 @@ paths: schema: type: integer - /w/{workspace}/jobs/queue/list_filtered_uuids: + /w/{workspace}/jobs/list_filtered_uuids: get: summary: get the ids of all jobs matching the given filters - operationId: listFilteredUuids + operationId: listFilteredJobsUuids + tags: + - job + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/CreatedBy" + - $ref: "#/components/parameters/Label" + - $ref: "#/components/parameters/Worker" + - $ref: "#/components/parameters/ParentJob" + - $ref: "#/components/parameters/ScriptExactPath" + - $ref: "#/components/parameters/ScriptStartPath" + - $ref: "#/components/parameters/SchedulePath" + - $ref: "#/components/parameters/ScriptExactHash" + - $ref: "#/components/parameters/StartedBefore" + - $ref: "#/components/parameters/StartedAfter" + - $ref: "#/components/parameters/CreatedBefore" + - $ref: "#/components/parameters/CreatedAfter" + - $ref: "#/components/parameters/CreatedOrStartedBefore" + - $ref: "#/components/parameters/Running" + - $ref: "#/components/parameters/ScheduledForBeforeNow" + - $ref: "#/components/parameters/CreatedOrStartedAfter" + - $ref: "#/components/parameters/CreatedOrStartedAfterCompletedJob" + - $ref: "#/components/parameters/JobKinds" + - $ref: "#/components/parameters/Suspended" + - $ref: "#/components/parameters/ArgsFilter" + - $ref: "#/components/parameters/Tag" + - $ref: "#/components/parameters/ResultFilter" + - $ref: "#/components/parameters/Page" + - $ref: "#/components/parameters/PerPage" + - name: is_skipped + description: is the job skipped + in: query + schema: + type: boolean + - name: is_flow_step + description: is the job a flow step + in: query + schema: + type: boolean + - name: has_null_parent + description: has null parent + in: query + schema: + type: boolean + - name: success + description: filter on successful jobs + in: query + schema: + type: boolean + - name: all_workspaces + description: get jobs from all workspaces (only valid if request come from the `admins` workspace) + in: query + schema: + type: boolean + - name: is_not_schedule + description: is not a scheduled job + in: query + schema: + type: boolean + responses: + "200": + description: uuids of jobs + content: + application/json: + schema: + type: array + items: + type: string + + /w/{workspace}/jobs/queue/list_filtered_uuids: + get: + summary: get the ids of all queued jobs matching the given filters + operationId: listFilteredQueueUuids tags: - job parameters: @@ -6830,6 +7127,7 @@ paths: - $ref: "#/components/parameters/Running" - $ref: "#/components/parameters/ArgsFilter" - $ref: "#/components/parameters/ResultFilter" + - $ref: "#/components/parameters/AllowWildcards" - $ref: "#/components/parameters/Tag" - $ref: "#/components/parameters/Page" - $ref: "#/components/parameters/PerPage" @@ -6908,6 +7206,7 @@ paths: - $ref: "#/components/parameters/JobKinds" - $ref: "#/components/parameters/ArgsFilter" - $ref: "#/components/parameters/ResultFilter" + - $ref: "#/components/parameters/AllowWildcards" - $ref: "#/components/parameters/Tag" - $ref: "#/components/parameters/Page" - $ref: "#/components/parameters/PerPage" @@ -6971,6 +7270,7 @@ paths: - $ref: "#/components/parameters/ArgsFilter" - $ref: "#/components/parameters/Tag" - $ref: "#/components/parameters/ResultFilter" + - $ref: "#/components/parameters/AllowWildcards" - $ref: "#/components/parameters/Page" - $ref: "#/components/parameters/PerPage" - name: is_skipped @@ -8616,7 +8916,7 @@ paths: summary: delete nats trigger operationId: deleteNatsTrigger tags: - - nats_trigger + - nats_trigger parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/Path" @@ -8645,7 +8945,6 @@ paths: schema: $ref: "#/components/schemas/NatsTrigger" - /w/{workspace}/nats_triggers/list: get: summary: list nats triggers @@ -8680,7 +8979,6 @@ paths: items: $ref: "#/components/schemas/NatsTrigger" - /w/{workspace}/nats_triggers/exists/{path}: get: summary: does nats trigger exists @@ -8727,7 +9025,6 @@ paths: schema: type: string - /w/{workspace}/nats_triggers/test: post: summary: test NATS connection @@ -9134,6 +9431,264 @@ paths: schema: type: string + /w/{workspace}/gcp_triggers/create: + post: + summary: create gcp trigger + operationId: createGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: new gcp trigger + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/NewGcpTrigger" + responses: + "201": + description: gcp trigger created + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/update/{path}: + post: + summary: update gcp trigger + operationId: updateGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/EditGcpTrigger" + responses: + "200": + description: gcp trigger updated + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/delete/{path}: + delete: + summary: delete gcp trigger + operationId: deleteGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: gcp trigger deleted + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/get/{path}: + get: + summary: get gcp trigger + operationId: getGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: gcp trigger deleted + content: + application/json: + schema: + $ref: "#/components/schemas/GcpTrigger" + + /w/{workspace}/gcp_triggers/list: + get: + summary: list gcp triggers + operationId: listGcpTriggers + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + required: true + - $ref: "#/components/parameters/Page" + - $ref: "#/components/parameters/PerPage" + - name: path + description: filter by path + in: query + schema: + type: string + - name: is_flow + in: query + schema: + type: boolean + - name: path_start + in: query + schema: + type: string + responses: + "200": + description: gcp trigger list + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/GcpTrigger" + + /w/{workspace}/gcp_triggers/exists/{path}: + get: + summary: does gcp trigger exists + operationId: existsGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: gcp trigger exists + content: + application/json: + schema: + type: boolean + + /w/{workspace}/gcp_triggers/setenabled/{path}: + post: + summary: set enabled gcp trigger + operationId: setGcpTriggerEnabled + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: updated gcp trigger enable + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + "200": + description: gcp trigger enabled set + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/test: + post: + summary: test gcp connection + operationId: testGcpConnection + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: test gcp connection + required: true + content: + application/json: + schema: + type: object + properties: + connection: + type: object + required: + - connection + responses: + "200": + description: try to connect to a gcp broker + content: + text/plain: + schema: + type: string + + + /w/{workspace}/gcp_triggers/subscriptions/delete/{path}: + delete: + summary: delete gcp trigger + operationId: deleteGcpSubscription + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: args to delete subscription from google cloud + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/DeleteGcpSubscription" + responses: + "200": + description: gcp trigger deleted + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/topics/list/{path}: + get: + summary: list all topics of google cloud service + operationId: listGoogleTopics + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: get all google topics + content: + application/json: + schema: + type: array + items: + type: string + + /w/{workspace}/gcp_triggers/subscriptions/list/{path}: + post: + summary: list all subscription of a give topic from google cloud service + operationId: listAllTGoogleTopicSubscriptions + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: args to get subscription's topic from google cloud + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/GetAllTopicSubscription" + responses: + "200": + description: get all google topic subscriptions name + content: + application/json: + schema: + type: array + items: + type: string /w/{workspace}/postgres_triggers/is_valid_postgres_configuration/{path}: get: @@ -9142,8 +9697,8 @@ paths: tags: - postgres_trigger parameters: - - $ref: "#/components/parameters/WorkspaceId" - - $ref: "#/components/parameters/Path" + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" responses: "200": description: boolean that indicates if postgres is set to logical level or not @@ -9213,7 +9768,7 @@ paths: /w/{workspace}/postgres_triggers/slot/create/{path}: post: - summary: create replication slot for postgres + summary: create replication slot for postgres operationId: createPostgresReplicationSlot tags: - postgres_trigger @@ -9346,7 +9901,6 @@ paths: schema: type: string - /w/{workspace}/postgres_triggers/publication/delete/{publication}/{path}: delete: summary: delete postgres publication @@ -10087,7 +10641,7 @@ paths: application/json: schema: $ref: "#/components/schemas/Folder" - + /w/{workspace}/folders/exists/{name}: get: summary: exists folder @@ -10410,6 +10964,41 @@ paths: items: $ref: "#/components/schemas/AutoscalingEvent" + /agent_workers/create_agent_token: + post: + summary: create agent token + operationId: createAgentToken + tags: + - agent_workers + requestBody: + description: agent token + required: true + content: + application/json: + schema: + type: object + properties: + worker_group: + type: string + tags: + type: array + items: + type: string + exp: + type: integer + required: + - worker_group + - tags + - exp + responses: + "200": + description: agent token created + content: + application/json: + schema: + type: string + + /w/{workspace}/acls/get/{kind}/{path}: get: summary: get granular acls @@ -10424,7 +11013,8 @@ paths: required: true schema: type: string - enum: [ + enum: + [ script, group_, resource, @@ -10440,6 +11030,7 @@ paths: nats_trigger, postgres_trigger, mqtt_trigger, + gcp_trigger, sqs_trigger ] responses: @@ -10483,6 +11074,7 @@ paths: nats_trigger, postgres_trigger, mqtt_trigger, + gcp_trigger, sqs_trigger ] requestBody: @@ -10537,6 +11129,7 @@ paths: nats_trigger, postgres_trigger, mqtt_trigger, + gcp_trigger, sqs_trigger ] requestBody: @@ -10589,6 +11182,10 @@ paths: responses: "200": description: capture config set + content: + application/json: + schema: + type: object /w/{workspace}/capture/ping_config/{trigger_kind}/{runnable_kind}/{path}: post: @@ -10654,7 +11251,6 @@ paths: type: array items: $ref: "#/components/schemas/Capture" - /w/{workspace}/capture/move/{runnable_kind}/{path}: post: @@ -10913,8 +11509,7 @@ paths: /w/{workspace}/job_helpers/duckdb_connection_settings: post: - summary: - Converts an S3 resource to the set of instructions necessary to connect + summary: Converts an S3 resource to the set of instructions necessary to connect DuckDB to an S3 bucket operationId: duckdbConnectionSettings tags: @@ -10943,8 +11538,7 @@ paths: type: string /w/{workspace}/job_helpers/v2/duckdb_connection_settings: post: - summary: - Converts an S3 resource to the set of instructions necessary to connect + summary: Converts an S3 resource to the set of instructions necessary to connect DuckDB to an S3 bucket operationId: duckdbConnectionSettingsV2 tags: @@ -10980,8 +11574,7 @@ paths: /w/{workspace}/job_helpers/polars_connection_settings: post: - summary: - Converts an S3 resource to the set of arguments necessary to connect + summary: Converts an S3 resource to the set of arguments necessary to connect Polars to an S3 bucket operationId: polarsConnectionSettings tags: @@ -11025,8 +11618,7 @@ paths: - client_kwargs /w/{workspace}/job_helpers/v2/polars_connection_settings: post: - summary: - Converts an S3 resource to the set of arguments necessary to connect + summary: Converts an S3 resource to the set of arguments necessary to connect Polars to an S3 bucket operationId: polarsConnectionSettingsV2 tags: @@ -11103,8 +11695,7 @@ paths: parameters: - $ref: "#/components/parameters/WorkspaceId" requestBody: - description: - S3 resource path to use. If empty, the S3 resource defined in the + description: S3 resource path to use. If empty, the S3 resource defined in the workspace settings will be used required: true content: @@ -11804,6 +12395,7 @@ paths: - $ref: "#/components/parameters/ArgsFilter" - $ref: "#/components/parameters/Tag" - $ref: "#/components/parameters/ResultFilter" + - $ref: "#/components/parameters/AllowWildcards" - $ref: "#/components/parameters/Page" - $ref: "#/components/parameters/PerPage" - name: is_skipped @@ -12147,8 +12739,7 @@ components: type: string ParentJob: name: parent_job - description: - The parent job that is at the origin and responsible for the execution + description: The parent job that is at the origin and responsible for the execution of this script if any in: query schema: @@ -12168,8 +12759,7 @@ components: type: string NewJobId: name: job_id - description: - The job id to assign to the created job. if missing, job is chosen + description: The job id to assign to the created job. if missing, job is chosen randomly using the ULID scheme. If a job id already exists in the queue or as a completed job, the request to create one will fail (Bad Request) in: query @@ -12260,8 +12850,7 @@ components: format: date-time CreatedOrStartedAfter: name: created_or_started_after - description: - filter on created_at for non non started job and started_at otherwise + description: filter on created_at for non non started job and started_at otherwise after (exclusive) timestamp in: query schema: @@ -12269,8 +12858,7 @@ components: format: date-time CreatedOrStartedAfterCompletedJob: name: created_or_started_after_completed_jobs - description: - filter on created_at for non non started job and started_at otherwise + description: filter on created_at for non non started job and started_at otherwise after (exclusive) timestamp but only for the completed jobs in: query schema: @@ -12278,8 +12866,7 @@ components: format: date-time CreatedOrStartedBefore: name: created_or_started_before - description: - filter on created_at for non non started job and started_at otherwise + description: filter on created_at for non non started job and started_at otherwise before (inclusive) timestamp in: query schema: @@ -12309,6 +12896,12 @@ components: in: query schema: type: boolean + AllowWildcards: + name: allow_wildcards + description: allow wildcards (*) in the filter of label, tag, worker + in: query + schema: + type: boolean ArgsFilter: name: args description: filter on jobs containing those args as a json subset (@> in postgres) @@ -12361,8 +12954,7 @@ components: enum: [Create, Update, Delete, Execute] JobKinds: name: job_kinds - description: - filter on job kind (values 'preview', 'script', 'dependencies', 'flow') + description: filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query schema: @@ -12413,19 +13005,44 @@ components: AIProvider: type: string - enum: [openai, anthropic, mistral, deepseek, googleai, groq, openrouter, customai] + enum: [openai, azure_openai, anthropic, mistral, deepseek, googleai, groq, openrouter, togetherai, customai] - AIResource: + AIProviderModel: type: object properties: - path: + model: type: string provider: $ref: "#/components/schemas/AIProvider" required: - - path + - model - provider + AIProviderConfig: + type: object + properties: + resource_path: + type: string + models: + type: array + items: + type: string + required: + - resource_path + - models + + AIConfig: + type: object + properties: + providers: + type: object + additionalProperties: + $ref: "#/components/schemas/AIProviderConfig" + default_model: + $ref: "#/components/schemas/AIProviderModel" + code_completion_model: + $ref: "#/components/schemas/AIProviderModel" + Script: type: object properties: @@ -12745,14 +13362,14 @@ components: "singlescriptflow", "flowscript", "flownode", - "appscript", + "appscript" ] schedule_path: type: string permissioned_as: type: string description: | - The user (u/userfoo) or group (g/groupfoo) whom + The user (u/userfoo) or group (g/groupfoo) whom the execution of this script will be permissioned_as and by extension its DT_TOKEN. flow_status: $ref: "../../openflow.openapi.yaml#/components/schemas/FlowStatus" @@ -12852,14 +13469,14 @@ components: "singlescriptflow", "flowscript", "flownode", - "appscript", + "appscript" ] schedule_path: type: string permissioned_as: type: string description: | - The user (u/userfoo) or group (g/groupfoo) whom + The user (u/userfoo) or group (g/groupfoo) whom the execution of this script will be permissioned_as and by extension its DT_TOKEN. flow_status: $ref: "../../openflow.openapi.yaml#/components/schemas/FlowStatus" @@ -13302,7 +13919,7 @@ components: "bytes", "dict", "datetime", - "sql", + "sql" ] - type: object properties: @@ -13342,7 +13959,7 @@ components: "bytes", "dict", "datetime", - "sql", + "sql" ] - type: object properties: @@ -13368,7 +13985,7 @@ components: "bytes", "dict", "datetime", - "sql", + "sql" ] - type: object properties: @@ -13400,8 +14017,7 @@ components: ScriptLang: type: string - enum: - [ + enum: [ python3, deno, go, @@ -13420,7 +14036,9 @@ components: rust, ansible, csharp, - nu + nu, + java + # for related places search: ADD_NEW_LANG ] Preview: @@ -13647,6 +14265,8 @@ components: $ref: "../../openflow.openapi.yaml#/components/schemas/Retry" summary: type: string + description: + type: string no_flow_overlap: type: boolean tag: @@ -13733,6 +14353,8 @@ components: type: boolean summary: type: string + description: + type: string tag: type: string paused_until: @@ -13784,6 +14406,8 @@ components: type: boolean summary: type: string + description: + type: string tag: type: string paused_until: @@ -13830,6 +14454,16 @@ components: - edited_at - is_flow + AuthenticationMethod: + type: string + enum: + - none + - windmill + - api_key + - basic_http + - custom_script + - signature + HttpTrigger: allOf: - $ref: "#/components/schemas/TriggerExtraProperty" @@ -13856,10 +14490,12 @@ components: - put - delete - patch + authentication_resource_path: + type: string is_async: type: boolean - requires_auth: - type: boolean + authentication_method: + $ref: "#/components/schemas/AuthenticationMethod" is_static_website: type: boolean workspaced_route: @@ -13872,7 +14508,7 @@ components: required: - route_path - is_async - - requires_auth + - authentication_method - http_method - is_static_website - workspaced_route @@ -13911,16 +14547,18 @@ components: - put - delete - patch + authentication_resource_path: + type: string is_async: type: boolean - requires_auth: - type: boolean + authentication_method: + $ref: "#/components/schemas/AuthenticationMethod" is_static_website: type: boolean wrap_body: type: boolean raw_string: - type: boolean + type: boolean required: - path @@ -13928,7 +14566,7 @@ components: - route_path - is_flow - is_async - - requires_auth + - authentication_method - http_method - is_static_website @@ -13954,6 +14592,8 @@ components: type: string required: - s3 + authentication_resource_path: + type: string is_flow: type: boolean http_method: @@ -13966,8 +14606,8 @@ components: - patch is_async: type: boolean - requires_auth: - type: boolean + authentication_method: + $ref: "#/components/schemas/AuthenticationMethod" is_static_website: type: boolean wrap_body: @@ -13980,7 +14620,7 @@ components: - is_flow - kind - is_async - - requires_auth + - authentication_method - http_method - is_static_website @@ -14010,6 +14650,8 @@ components: type: number mqtt_count: type: number + gcp_count: + type: number sqs_count: type: number @@ -14162,8 +14804,8 @@ components: MqttQoS: type: string - enum: ['qos0', 'qos1', 'qos2'] - + enum: ["qos0", "qos1", "qos2"] + MqttV3Config: type: object properties: @@ -14233,7 +14875,7 @@ components: type: object properties: mqtt_resource_path: - type: string + type: string subscribe_topics: type: array items: @@ -14291,9 +14933,176 @@ components: - script_path - is_flow - enabled - - subscribe_topics + - subscribe_topics - mqtt_resource_path + + DeliveryType: + type: string + enum: + - push + - pull + + PushConfig: + type: object + properties: + audience: + type: string + authenticate: + type: boolean + base_endpoint: + type: string + required: + - authenticate + - base_endpoint + + GcpTrigger: + allOf: + - $ref: "#/components/schemas/TriggerExtraProperty" + type: object + properties: + gcp_resource_path: + type: string + topic_id: + type: string + subscription_id: + type: string + server_id: + type: string + delivery_type: + $ref: "#/components/schemas/DeliveryType" + delivery_config: + $ref: "#/components/schemas/PushConfig" + last_server_ping: + type: string + format: date-time + error: + type: string + enabled: + type: boolean + required: + - gcp_resource_path + - topic_id + - subscription_id + - enabled + - delivery_type + + SubscriptionMode: + type: string + enum: + - existing + - create_update + description: "The mode of subscription. 'existing' means using an existing GCP subscription, while 'create_update' involves creating or updating a new subscription." + + GcpExistingSubscription: + type: object + properties: + subscription_id: + type: string + base_endpoint: + type: string + required: + - subscription_id + - base_endpoint + GcpCreateUpdateSubscription: + type: object + properties: + subscription_id: + type: string + delivery_type: + $ref: "#/components/schemas/DeliveryType" + delivery_config: + $ref: "#/components/schemas/PushConfig" + required: + - delivery_type + + + GcpSubscriptionModeConfig: + type: object + properties: + subscription_mode: + $ref: "#/components/schemas/SubscriptionMode" + required: + - subscription_mode + allOf: + - oneOf: + - $ref: "#/components/schemas/GcpExistingSubscription" + - $ref: "#/components/schemas/GcpCreateUpdateSubscription" + description: | + "This is a union type representing the subscription mode. + - 'existing': Represents an existing GCP subscription, and should be accompanied by an 'ExistingGcpSubscription' object. + - 'create_update': Represents a new or updated GCP subscription, and should be accompanied by a 'CreateUpdateConfig' object." + + NewGcpTrigger: + type: object + properties: + gcp_resource_path: + type: string + topic_id: + type: string + subscription_mode: + $ref: "#/components/schemas/GcpSubscriptionModeConfig" + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + required: + - path + - script_path + - is_flow + - gcp_resource_path + - topic_id + - subscription_mode + + EditGcpTrigger: + type: object + properties: + gcp_resource_path: + type: string + topic_id: + type: string + subscription_mode: + $ref: "#/components/schemas/GcpSubscriptionModeConfig" + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + required: + - path + - script_path + - is_flow + - enabled + - mqtt_resource_path + - subscription_id + - delivery_type + - topic_id + - subscription_mode + + GetAllTopicSubscription: + type: object + properties: + topic_id: + type: string + required: + - topic_id + + + DeleteGcpSubscription: + type: object + properties: + subscription_id: + type: string + required: + - subscription_id + SqsTrigger: allOf: - $ref: "#/components/schemas/TriggerExtraProperty" @@ -14343,7 +15152,7 @@ components: type: boolean required: - queue_url - - aws_resource_path + - aws_resource_path - path - script_path - is_flow @@ -14369,13 +15178,12 @@ components: type: boolean required: - queue_url - - aws_resource_path + - aws_resource_path - path - script_path - is_flow - enabled - Slot: type: object properties: @@ -14403,7 +15211,7 @@ components: type: string required: - transaction_to_track - + TableToTrack: type: array items: @@ -14451,7 +15259,7 @@ components: - postgres_resource_path - relations - language - + PostgresTrigger: allOf: - $ref: "#/components/schemas/TriggerExtraProperty" @@ -14470,8 +15278,8 @@ components: error: type: string last_server_ping: - type: string - format: date-time + type: string + format: date-time required: - enabled - postgres_resource_path @@ -14503,7 +15311,7 @@ components: - is_flow - enabled - postgres_resource_path - + EditPostgresTrigger: type: object properties: @@ -14641,7 +15449,7 @@ components: type: string enabled: type: boolean - + required: - nats_resource_path - use_jetstream @@ -14671,7 +15479,7 @@ components: type: string enabled: type: boolean - + required: - path - script_path @@ -14701,7 +15509,7 @@ components: type: string is_flow: type: boolean - + required: - path - script_path @@ -15267,13 +16075,7 @@ components: properties: type: type: string - enum: - [ - "S3Storage", - "AzureBlobStorage", - "AzureWorkloadIdentity", - "S3AwsOidc", - ] + enum: ["S3Storage", "AzureBlobStorage", "AzureWorkloadIdentity", "S3AwsOidc"] s3_resource_path: type: string azure_blob_resource_path: @@ -15288,12 +16090,7 @@ components: type: type: string enum: - [ - "S3Storage", - "AzureBlobStorage", - "AzureWorkloadIdentity", - "S3AwsOidc", - ] + ["S3Storage", "AzureBlobStorage", "AzureWorkloadIdentity", "S3AwsOidc"] s3_resource_path: type: string azure_blob_resource_path: @@ -15679,7 +16476,7 @@ components: CaptureTriggerKind: type: string - enum: [webhook, http, websocket, kafka, email, nats, postgres, sqs, mqtt] + enum: [webhook, http, websocket, kafka, email, nats, postgres, sqs, mqtt, gcp] Capture: type: object @@ -15773,7 +16570,7 @@ components: type: array description: List of channels within the team items: - $ref: '#/components/schemas/ChannelInfo' + $ref: "#/components/schemas/ChannelInfo" ChannelInfo: type: object @@ -15798,4 +16595,57 @@ components: service_url: type: string description: The service URL for the channel - example: "https://smba.trafficmanager.net/amer/12345678-1234-1234-1234-123456789012/" \ No newline at end of file + example: "https://smba.trafficmanager.net/amer/12345678-1234-1234-1234-123456789012/" + + GithubInstallations: + type: array + items: + type: object + properties: + workspace_id: + type: string + installation_id: + type: number + account_id: + type: string + repositories: + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + required: + - name + - url + required: + - installation_id + - account_id + - repositories + + WorkspaceGithubInstallation: + type: object + properties: + account_id: + type: string + installation_id: + type: number + required: + - account_id + - installation_id + + S3Object: + type: object + properties: + s3: + type: string + filename: + type: string + storage: + type: string + presigned: + type: string + required: + - s3 \ No newline at end of file diff --git a/backend/windmill-api/src/agent_workers_ee.rs b/backend/windmill-api/src/agent_workers_ee.rs new file mode 100644 index 0000000000..af31e61229 --- /dev/null +++ b/backend/windmill-api/src/agent_workers_ee.rs @@ -0,0 +1,52 @@ +/* + * Author: Ruben Fiszel + * Copyright: Windmill Labs, Inc 2042 + * This file and its contents are licensed under the AGPLv3 License. + * Please see the included NOTICE for copyright information and + * LICENSE-AGPL for a copy of the license. + */ + +use crate::db::DB; + +use axum::Router; + +use serde::{Deserialize, Serialize}; + +pub fn global_service() -> Router { + Router::new() +} + +pub fn workspaced_service( + db: DB, + _base_internal_url: String, +) -> ( + Router, + Option>, + windmill_worker::JobCompletedSender, +) { + use windmill_common::worker::Connection; + use windmill_worker::JobCompletedSender; + + let (job_completed_tx, _job_completed_rx) = + JobCompletedSender::new(&Connection::Sql(db.clone()), 100); + + let router = Router::new(); + + (router, None, job_completed_tx) +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct AgentAuth { + pub worker_group: String, + pub suffix: Option, + pub tags: Vec, + pub exp: Option, +} + +pub struct AgentCache {} + +impl AgentCache { + pub fn new() -> Self { + AgentCache {} + } +} diff --git a/backend/windmill-api/src/ai.rs b/backend/windmill-api/src/ai.rs index d9469900b1..6b33a70730 100644 --- a/backend/windmill-api/src/ai.rs +++ b/backend/windmill-api/src/ai.rs @@ -3,192 +3,109 @@ use crate::{ variables::get_variable_or_self, }; -use anthropic::AnthropicCache; -use anyhow::Context; use axum::{body::Bytes, extract::Path, response::IntoResponse, routing::post, Extension, Router}; use http::HeaderMap; -use lazy_static::lazy_static; use quick_cache::sync::Cache; use reqwest::{Client, RequestBuilder}; use serde::{Deserialize, Serialize}; -use serde_json::value::{RawValue, Value}; +use serde_json::value::RawValue; use std::collections::HashMap; use windmill_audit::{audit_ee::audit_log, ActionKind}; use windmill_common::error::{to_anyhow, Error, Result}; -use mistral::MistralCache; -use openai::OpenaiCache; -use openai_api_compatible::OpenaiApiCompatibleCache; - lazy_static::lazy_static! { static ref HTTP_CLIENT: Client = reqwest::ClientBuilder::new() .timeout(std::time::Duration::from_secs(60 * 5)) .user_agent("windmill/beta") .build().unwrap(); + + static ref OPENAI_AZURE_BASE_PATH: Option = std::env::var("OPENAI_AZURE_BASE_PATH").ok(); + + pub static ref AI_REQUEST_CACHE: Cache<(String, AIProvider), ExpiringAIRequestConfig> = Cache::new(500); } -mod openai_api_compatible { - use super::*; +const AZURE_API_VERSION: &str = "2024-10-21"; +const OPENAI_BASE_URL: &str = "https://api.openai.com/v1"; - #[derive(Deserialize, Clone, Debug)] - pub struct OpenaiApiCompatibleCache { - pub base_url: String, - pub api_key: Option, - } +#[derive(Deserialize, Debug)] +struct AIOAuthResource { + client_id: String, + client_secret: String, + token_url: String, + user: Option, +} - impl OpenaiApiCompatibleCache { - pub fn prepare_request(self, path: &str, body: Bytes) -> Result { - let url = format!("{}/{}", self.base_url, path); +#[derive(Deserialize, Debug)] +struct AIStandardResource { + #[serde(alias = "baseUrl")] + base_url: Option, + #[serde(alias = "apiKey")] + api_key: Option, + organization_id: Option, +} - let mut request = HTTP_CLIENT - .post(url) - .header("content-type", "application/json") - .body(body); +#[derive(Deserialize, Debug)] +struct OAuthTokens { + access_token: String, +} - if let Some(api_key) = self.api_key { - request = request.header("Authorization", format!("Bearer {}", api_key)); - } +#[derive(Deserialize, Debug)] +#[serde(untagged)] +enum AIResource { + OAuth(AIOAuthResource), + Standard(AIStandardResource), +} - Ok(request) - } - } +#[derive(Deserialize, Clone, Debug)] +struct AIRequestConfig { + pub base_url: String, + pub api_key: Option, + pub access_token: Option, + pub organization_id: Option, + pub user: Option, +} - pub async fn get_cached_value( +impl AIRequestConfig { + pub async fn new( + provider: &AIProvider, db: &DB, w_id: &str, - resource: Value, - base_url: Option, - ) -> Result { - let mut resource: OpenaiApiCompatibleCache = if let Some(base_url) = base_url { - let api_key = match resource { - Value::Object(mut obj) => obj - .remove("api_key") - .map(|v| serde_json::from_value::(v.clone()).ok()) - .flatten(), - _ => None, - }; - OpenaiApiCompatibleCache { base_url, api_key } - } else { - serde_json::from_value(resource).with_context(|| "validating custom AI resource")? + resource: AIResource, + ) -> Result { + let (api_key, access_token, organization_id, base_url, user) = match resource { + AIResource::Standard(resource) => { + let base_url = provider.get_base_url(resource.base_url, db).await?; + let api_key = if let Some(api_key) = resource.api_key { + Some(get_variable_or_self(api_key, db, w_id).await?) + } else { + None + }; + let organization_id = if let Some(organization_id) = resource.organization_id { + Some(get_variable_or_self(organization_id, db, w_id).await?) + } else { + None + }; + + (api_key, None, organization_id, base_url, None) + } + AIResource::OAuth(resource) => { + let user = if let Some(user) = resource.user.clone() { + Some(get_variable_or_self(user, db, w_id).await?) + } else { + None + }; + let token = Self::get_token_using_oauth(resource, db, w_id).await?; + let base_url = provider.get_base_url(None, db).await?; + + (None, Some(token), None, base_url, user) + } }; - if let Some(api_key) = resource.api_key { - resource.api_key = Some(get_variable_or_self(api_key, db, w_id).await?); - } - - Ok(KeyCache::OpenaiApiCompatible(resource)) - } -} - -mod openai { - use super::*; - - const API_VERSION: &str = "2024-10-21"; - - #[derive(Deserialize, Debug)] - struct OpenaiResource { - api_key: String, - organization_id: Option, + Ok(Self { base_url, organization_id, api_key, access_token, user }) } - #[derive(Deserialize, Debug)] - struct OpenaiClientCredentialsOauthResource { - client_id: String, - client_secret: String, - token_url: String, - user: Option, - } - - #[derive(Deserialize, Debug)] - #[serde(untagged, rename_all = "snake_case")] - enum OpenaiConfig { - Resource(OpenaiResource), - ClientCredentialsOauthResource(OpenaiClientCredentialsOauthResource), - } - - lazy_static::lazy_static! { - pub static ref OPENAI_AZURE_BASE_PATH: Option = std::env::var("OPENAI_AZURE_BASE_PATH").ok(); - } - - #[derive(Deserialize, Debug)] - struct OpenaiCredentials { - access_token: String, - } - - #[derive(Clone, Debug, Deserialize)] - pub struct OpenaiCache { - api_key: String, - organization_id: Option, - azure_base_path: Option, - user: Option, - } - - impl OpenaiCache { - pub fn new( - api_key: String, - organization_id: Option, - azure_base_path: Option, - user: Option, - ) -> Self { - Self { api_key, organization_id, azure_base_path, user } - } - } - - const BASE_URL: &str = "https://api.openai.com/v1"; - impl OpenaiCache { - pub fn prepare_request(self, openai_path: &str, mut body: Bytes) -> Result { - let OpenaiCache { api_key, azure_base_path, organization_id, user } = self; - if user.is_some() { - tracing::debug!("Adding user to request body"); - let mut json_body: HashMap> = serde_json::from_slice(&body) - .map_err(|e| { - Error::internal_err(format!("Failed to parse request body: {}", e)) - })?; - - let user_json_string = serde_json::Value::String(user.unwrap()).to_string(); // makes sure to escape characters - - json_body.insert( - "user".to_string(), - RawValue::from_string(user_json_string) - .map_err(|e| Error::internal_err(format!("Failed to parse user: {}", e)))?, - ); - - body = serde_json::to_vec(&json_body) - .map_err(|e| { - Error::internal_err(format!("Failed to reserialize request body: {}", e)) - })? - .into(); - } - - let base_url = if let Some(base_url) = azure_base_path { - base_url - } else { - BASE_URL.to_string() - }; - let url = format!("{}/{}", base_url, openai_path); - let mut request = HTTP_CLIENT - .post(url) - .header("content-type", "application/json") - .body(body); - - if base_url != BASE_URL { - request = request - .header("api-key", api_key) - .query(&[("api-version", API_VERSION)]) - } else { - request = request.header("authorization", format!("Bearer {}", api_key)) - } - - if let Some(org_id) = organization_id { - request = request.header("OpenAI-Organization", org_id); - } - - Ok(request) - } - } - - async fn get_openai_key_using_credentials_flow( - mut resource: OpenaiClientCredentialsOauthResource, + async fn get_token_using_oauth( + mut resource: AIOAuthResource, db: &DB, w_id: &str, ) -> Result { @@ -197,208 +114,167 @@ mod openai { resource.token_url = get_variable_or_self(resource.token_url, db, w_id).await?; let mut params = HashMap::new(); params.insert("grant_type", "client_credentials"); + params.insert("scope", "https://cognitiveservices.azure.com/.default"); let response = HTTP_CLIENT .post(resource.token_url) .form(¶ms) .basic_auth(resource.client_id, Some(resource.client_secret)) .send() .await + .and_then(|r| r.error_for_status()) .map_err(|err| { Error::internal_err(format!( - "Failed to get OpenAI credentials using credentials flow: {}", + "Failed to get access token using credentials flow: {}", err )) })?; - let response = response.json::().await.map_err(|err| { + let response = response.json::().await.map_err(|err| { Error::internal_err(format!( - "Failed to parse OpenAI credentials from credentials flow: {}", + "Failed to parse access token from credentials flow: {}", err )) })?; Ok(response.access_token) } - pub async fn get_cached_value(db: &DB, w_id: &str, resource: Value) -> Result { - let config = serde_json::from_value(resource) - .map_err(|e| Error::internal_err(format!("validating openai resource {e:#}")))?; + pub fn prepare_request( + self, + provider: &AIProvider, + path: &str, + body: Bytes, + ) -> Result { + let url = format!("{}/{}", self.base_url, path); - let mut user = None::; - let mut resource = match config { - OpenaiConfig::Resource(resource) => { - tracing::debug!("Getting OpenAI key from static resource"); - resource - } - OpenaiConfig::ClientCredentialsOauthResource(resource) => { - tracing::debug!("Getting OpenAI key with client credentials flow"); - user = resource.user.clone(); - let token = get_openai_key_using_credentials_flow(resource, db, w_id).await?; - OpenaiResource { api_key: token, organization_id: None } - } - }; - - resource.api_key = get_variable_or_self(resource.api_key, db, w_id).await?; - - if let Some(organization_id) = resource.organization_id { - resource.organization_id = Some(get_variable_or_self(organization_id, db, w_id).await?); - } - - if user.is_some() { - user = Some(get_variable_or_self(user.unwrap(), db, w_id).await?); - } - - let azure_base_path = sqlx::query_scalar!( - "SELECT value - FROM global_settings - WHERE name = 'openai_azure_base_path'", - ) - .fetch_optional(db) - .await?; - - let azure_base_path = if let Some(azure_base_path) = azure_base_path { - Some( - serde_json::from_value::(azure_base_path).map_err(|e| { - Error::internal_err(format!("validating openai azure base path {e:#}")) - })?, - ) + let body = if let Some(user) = self.user { + Self::add_user_to_body(body, user)? } else { - OPENAI_AZURE_BASE_PATH.clone() + body }; - let workspace_cache = OpenaiCache::new( - resource.api_key.clone(), - resource.organization_id.clone(), - azure_base_path.clone(), - user.clone(), + let is_azure = matches!(provider, AIProvider::OpenAI) && self.base_url != OPENAI_BASE_URL + || matches!(provider, AIProvider::AzureOpenAI); + + let mut request = HTTP_CLIENT + .post(url) + .header("content-type", "application/json") + .body(body); + + if is_azure { + request = request.query(&[("api-version", AZURE_API_VERSION)]) + } + + if let Some(api_key) = self.api_key { + if is_azure { + request = request.header("api-key", api_key) + } else { + request = request.header("authorization", format!("Bearer {}", api_key)) + } + } + + if let Some(access_token) = self.access_token { + request = request.header("authorization", format!("Bearer {}", access_token)) + } + + if let Some(org_id) = self.organization_id { + request = request.header("OpenAI-Organization", org_id); + } + + Ok(request) + } + + fn add_user_to_body(body: Bytes, user: String) -> Result { + tracing::debug!("Adding user to request body"); + let mut json_body: HashMap> = serde_json::from_slice(&body) + .map_err(|e| Error::internal_err(format!("Failed to parse request body: {}", e)))?; + + let user_json_string = serde_json::Value::String(user).to_string(); // makes sure to escape characters + + json_body.insert( + "user".to_string(), + RawValue::from_string(user_json_string) + .map_err(|e| Error::internal_err(format!("Failed to parse user: {}", e)))?, ); - Ok(KeyCache::Openai(workspace_cache)) - } -} -mod anthropic { - - use super::*; - - #[derive(Clone, Deserialize, Debug)] - pub struct AnthropicCache { - #[serde(rename = "apiKey")] - pub api_key: String, - } - - const API_VERSION: &str = "2023-06-01"; - - const BASE_URL: &str = "https://api.anthropic.com"; - impl AnthropicCache { - pub fn prepare_request(self, anthropic_path: &str, body: Bytes) -> Result { - let AnthropicCache { api_key } = self; - let url = format!("{}/{}", BASE_URL, anthropic_path); - let request = HTTP_CLIENT - .post(url) - .header("x-api-key", api_key) - .header("anthropic-version", API_VERSION) - .header("content-type", "application/json") - .body(body); - Ok(request) - } - } - - pub async fn get_cached_value(db: &DB, w_id: &str, resource: Value) -> Result { - let mut resource: AnthropicCache = serde_json::from_value(resource) - .map_err(|e| Error::internal_err(format!("validating anthropic resource {e:#}")))?; - resource.api_key = get_variable_or_self(resource.api_key, db, w_id).await?; - Ok(KeyCache::Anthropic(resource)) - } -} - -mod mistral { - use super::*; - #[derive(Deserialize, Clone, Debug)] - pub struct MistralCache { - #[serde(rename = "apiKey")] - pub api_key: String, - } - - const BASE_URL: &str = "https://api.mistral.ai"; - impl MistralCache { - pub fn prepare_request(self, mistral_path: &str, body: Bytes) -> Result { - let MistralCache { api_key } = self; - - let url = format!("{}/{}", BASE_URL, mistral_path); - let request = HTTP_CLIENT - .post(url) - .header("content-type", "application/json") - .header("Accept", "application/json") - .header("authorization", format!("Bearer {}", api_key)) - .body(body); - Ok(request) - } - } - - pub async fn get_cached_value(db: &DB, w_id: &str, resource: Value) -> Result { - let mut resource: MistralCache = serde_json::from_value(resource) - .map_err(|e| Error::internal_err(format!("validating mistral resource {e:#}")))?; - resource.api_key = get_variable_or_self(resource.api_key, db, w_id).await?; - Ok(KeyCache::Mistral(resource)) + Ok(serde_json::to_vec(&json_body) + .map_err(|e| Error::internal_err(format!("Failed to reserialize request body: {}", e)))? + .into()) } } #[derive(Clone, Debug)] -pub enum KeyCache { - Openai(OpenaiCache), - Anthropic(AnthropicCache), - Mistral(MistralCache), - OpenaiApiCompatible(OpenaiApiCompatibleCache), +pub struct ExpiringAIRequestConfig { + config: AIRequestConfig, + expires_at: std::time::Instant, } -#[derive(Clone, Debug)] -pub struct AICache { - pub path: String, - pub cached_key: KeyCache, - pub expires_at: std::time::Instant, -} - -impl AICache { - pub fn new(path: String, cached_key: KeyCache) -> Self { - Self { - path, - cached_key, - expires_at: std::time::Instant::now() + std::time::Duration::from_secs(60), - } +impl ExpiringAIRequestConfig { + fn new(config: AIRequestConfig) -> Self { + Self { config, expires_at: std::time::Instant::now() + std::time::Duration::from_secs(60) } } fn is_expired(&self) -> bool { self.expires_at < std::time::Instant::now() } } -lazy_static! { - pub static ref AI_KEY_CACHE: Cache = Cache::new(500); -} - -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Clone)] #[serde(rename_all = "lowercase")] pub enum AIProvider { OpenAI, + #[serde(rename = "azure_openai")] + AzureOpenAI, Anthropic, Mistral, DeepSeek, GoogleAI, Groq, OpenRouter, + TogetherAI, CustomAI, } impl AIProvider { - pub fn get_openai_compatible_base_url(&self) -> Result> { + pub async fn get_base_url(&self, resource_base_url: Option, db: &DB) -> Result { match self { - AIProvider::DeepSeek => Ok(Some("https://api.deepseek.com/v1".to_string())), - AIProvider::GoogleAI => Ok(Some( - "https://generativelanguage.googleapis.com/v1beta/openai".to_string(), - )), - AIProvider::Groq => Ok(Some("https://api.groq.com/openai/v1".to_string())), - AIProvider::OpenRouter => Ok(Some("https://openrouter.ai/api/v1".to_string())), - AIProvider::CustomAI => Ok(None), - _ => Err(Error::BadRequest( - "Please use the specific provider instead of the OpenAI compatible one".to_string(), - )), + AIProvider::OpenAI => { + let azure_base_path = sqlx::query_scalar!( + "SELECT value + FROM global_settings + WHERE name = 'openai_azure_base_path'", + ) + .fetch_optional(db) + .await?; + + let azure_base_path = if let Some(azure_base_path) = azure_base_path { + Some( + serde_json::from_value::(azure_base_path).map_err(|e| { + Error::internal_err(format!("validating openai azure base path {e:#}")) + })?, + ) + } else { + OPENAI_AZURE_BASE_PATH.clone() + }; + + Ok(azure_base_path.unwrap_or(OPENAI_BASE_URL.to_string())) + } + AIProvider::DeepSeek => Ok("https://api.deepseek.com/v1".to_string()), + AIProvider::GoogleAI => { + Ok("https://generativelanguage.googleapis.com/v1beta/openai".to_string()) + } + AIProvider::Groq => Ok("https://api.groq.com/openai/v1".to_string()), + AIProvider::OpenRouter => Ok("https://openrouter.ai/api/v1".to_string()), + AIProvider::TogetherAI => Ok("https://api.together.xyz/v1".to_string()), + AIProvider::Anthropic => Ok("https://api.anthropic.com/v1".to_string()), + AIProvider::Mistral => Ok("https://api.mistral.ai/v1".to_string()), + p @ (AIProvider::CustomAI | AIProvider::AzureOpenAI) => { + if let Some(base_url) = resource_base_url { + Ok(base_url) + } else { + Err(Error::BadRequest(format!( + "{:?} provider requires a base URL in the resource", + p + ))) + } + } } } } @@ -406,30 +282,100 @@ impl AIProvider { impl TryFrom<&str> for AIProvider { type Error = Error; fn try_from(s: &str) -> Result { - match s { - "openai" => Ok(AIProvider::OpenAI), - "anthropic" => Ok(AIProvider::Anthropic), - "mistral" => Ok(AIProvider::Mistral), - "groq" => Ok(AIProvider::Groq), - "openrouter" => Ok(AIProvider::OpenRouter), - "deepseek" => Ok(AIProvider::DeepSeek), - "googleai" => Ok(AIProvider::GoogleAI), - "customai" => Ok(AIProvider::CustomAI), - _ => Err(Error::BadRequest(format!("Invalid AI provider: {}", s))), - } + let s = serde_json::from_value::(serde_json::Value::String(s.to_string())) + .map_err(|e| Error::BadRequest(format!("Invalid AI provider: {}", e)))?; + Ok(s) } } -#[derive(Deserialize, Debug)] -pub struct AIResource { - pub path: Option, +#[derive(Serialize, Deserialize, Debug)] +pub struct ProviderConfig { + pub resource_path: String, + pub models: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ProviderModel { + pub model: String, pub provider: AIProvider, } -pub fn workspaced_service() -> Router { - let router = Router::new().route("/proxy/*ai", post(proxy)); +#[derive(Serialize, Deserialize, Debug)] +pub struct AIConfig { + #[serde(skip_serializing_if = "Option::is_none")] + pub providers: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub default_model: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub code_completion_model: Option, +} - router +pub fn global_service() -> Router { + Router::new().route("/proxy/*ai", post(global_proxy)) +} + +pub fn workspaced_service() -> Router { + Router::new().route("/proxy/*ai", post(proxy)) +} + +async fn global_proxy( + authed: ApiAuthed, + Extension(db): Extension, + Path(ai_path): Path, + headers: HeaderMap, + body: Bytes, +) -> impl IntoResponse { + let provider = headers + .get("X-Provider") + .map(|v| v.to_str().unwrap_or("").to_string()); + let api_key = headers + .get("X-API-Key") + .map(|v| v.to_str().unwrap_or("").to_string()); + + let provider = match provider { + Some(provider) => AIProvider::try_from(provider.as_str())?, + None => return Err(Error::BadRequest("Provider is required".to_string())), + }; + + let Some(api_key) = api_key else { + return Err(Error::BadRequest("API key is required".to_string())); + }; + + let base_url = provider.get_base_url(None, &db).await?; + + let url = format!("{}/{}", base_url, ai_path); + + let request = HTTP_CLIENT + .post(url) + .header("content-type", "application/json") + .header("Authorization", format!("Bearer {}", api_key)) + .body(body); + + let response = request.send().await.map_err(to_anyhow)?; + + let mut tx = db.begin().await?; + + audit_log( + &mut *tx, + &authed, + "ai.global_request", + ActionKind::Execute, + "global", + Some(&authed.email), + None, + ) + .await?; + tx.commit().await?; + + if response.error_for_status_ref().is_err() { + let err_msg = response.text().await.unwrap_or("".to_string()); + return Err(Error::AIError(err_msg)); + } + + let status_code = response.status(); + let headers = response.headers().clone(); + let stream = response.bytes_stream(); + Ok((status_code, headers, axum::body::Body::from_stream(stream))) } async fn proxy( @@ -439,111 +385,88 @@ async fn proxy( headers: HeaderMap, body: Bytes, ) -> impl IntoResponse { - let workspace_cache = AI_KEY_CACHE.get(&w_id); + let provider = headers + .get("X-Provider") + .map(|v| v.to_str().unwrap_or("").to_string()); + + let provider = match provider { + Some(provider) => AIProvider::try_from(provider.as_str())?, + None => return Err(Error::BadRequest("Provider is required".to_string())), + }; + + let workspace_cache = AI_REQUEST_CACHE.get(&(w_id.clone(), provider.clone())); + let forced_resource_path = headers .get("X-Resource-Path") .map(|v| v.to_str().unwrap_or("").to_string()); - let ai_cache = match workspace_cache { - Some(cache) if !cache.is_expired() && forced_resource_path.is_none() => cache.cached_key, + let request_config = match workspace_cache { + Some(request_cache) if !request_cache.is_expired() && forced_resource_path.is_none() => { + request_cache.config + } _ => { - let (resource, resource_path, ai_provider) = if let Some(resource_path) = - forced_resource_path - { - // guess the provider from the resource type - let record = sqlx::query!( - "SELECT value, resource_type FROM resource WHERE path = $1 AND workspace_id = $2", - &resource_path, - &w_id - ) - .fetch_optional(&db) - .await? - .ok_or_else(|| { - Error::NotFound(format!( - "Could not find the resource {}, update the resource path in the workspace settings", resource_path - )) - })?; - - ( - record.value, - resource_path, - AIProvider::try_from(record.resource_type.as_str())?, - ) + let (resource_path, save_to_cache) = if let Some(resource_path) = forced_resource_path { + // forced resource path + (resource_path, false) } else { - let ai_resource = sqlx::query_scalar!( - "SELECT ai_resource FROM workspace_settings WHERE workspace_id = $1", + let ai_config = sqlx::query_scalar!( + "SELECT ai_config FROM workspace_settings WHERE workspace_id = $1", &w_id ) .fetch_one(&db) .await?; - if ai_resource.is_none() { + if ai_config.is_none() { return Err(Error::internal_err( "AI resource not configured".to_string(), )); } - let ai_resource = serde_json::from_value::(ai_resource.unwrap()) + let mut ai_config = serde_json::from_value::(ai_config.unwrap()) .map_err(|e| Error::BadRequest(e.to_string()))?; - let path = ai_resource.path.unwrap_or("".to_string()); - if path.is_empty() { + let provider_config = ai_config + .providers + .as_mut() + .map(|providers| providers.remove(&provider)) + .flatten() + .ok_or_else(|| { + Error::BadRequest(format!("Provider {:?} not configured", provider)) + })?; + + if provider_config.resource_path.is_empty() { return Err(Error::BadRequest("Resource path is empty".to_string())); } - let resource = sqlx::query_scalar!( - "SELECT value - FROM resource - WHERE path = $1 AND workspace_id = $2", - &path, - &w_id - ) - .fetch_optional(&db) - .await? - .ok_or_else(|| { - Error::NotFound(format!( - "Could not find the {:?} resource at path {}, update the resource path in the workspace settings", ai_resource.provider, path - )) - })?; - (resource, path, ai_resource.provider) + (provider_config.resource_path, true) }; - if resource.is_none() { - return Err(Error::internal_err(format!( - "{:?} resource missing value", - ai_provider - ))); + let resource= sqlx::query_scalar!( + "SELECT value as \"value: sqlx::types::Json>\" FROM resource WHERE path = $1 AND workspace_id = $2", + &resource_path, + &w_id + ) + .fetch_optional(&db) + .await? + .ok_or_else(|| Error::NotFound(format!("Could not find the resource {}, update the resource path in the workspace settings", resource_path)))? + .ok_or_else(|| Error::BadRequest(format!("Empty resource value for {}", resource_path)))?; + + let resource = serde_json::from_str::(resource.0.get()) + .map_err(|e| Error::BadRequest(e.to_string()))?; + + let request_config = AIRequestConfig::new(&provider, &db, &w_id, resource).await?; + if save_to_cache { + AI_REQUEST_CACHE.insert( + (w_id.clone(), provider.clone()), + ExpiringAIRequestConfig::new(request_config.clone()), + ); } - - let resource = resource.unwrap(); - - let ai_cache = match ai_provider { - AIProvider::OpenAI => openai::get_cached_value(&db, &w_id, resource).await, - AIProvider::Anthropic => anthropic::get_cached_value(&db, &w_id, resource).await, - AIProvider::Mistral => mistral::get_cached_value(&db, &w_id, resource).await, - _ => { - openai_api_compatible::get_cached_value( - &db, - &w_id, - resource, - ai_provider.get_openai_compatible_base_url()?, - ) - .await - } - }; - let ai_cache = ai_cache?; - AI_KEY_CACHE.insert(w_id.clone(), AICache::new(resource_path, ai_cache.clone())); - ai_cache + request_config } }; - let request = match ai_cache { - KeyCache::Openai(cached) => cached.prepare_request(&ai_path, body), - KeyCache::Anthropic(cached) => cached.prepare_request(&ai_path, body), - KeyCache::Mistral(cached) => cached.prepare_request(&ai_path, body), - KeyCache::OpenaiApiCompatible(cached) => cached.prepare_request(&ai_path, body), - }; + let request = request_config.prepare_request(&provider, &ai_path, body)?; - let response = request?.send().await.map_err(to_anyhow)?; + let response = request.send().await.map_err(to_anyhow)?; let mut tx = db.begin().await?; @@ -554,14 +477,14 @@ async fn proxy( ActionKind::Execute, &w_id, Some(&authed.email), - Some([("ai_resource_path", &format!("{:?}", ai_path)[..])].into()), + Some([("ai_config_path", &format!("{:?}", ai_path)[..])].into()), ) .await?; tx.commit().await?; if response.error_for_status_ref().is_err() { let err_msg = response.text().await.unwrap_or("".to_string()); - return Err(Error::AiError(err_msg)); + return Err(Error::AIError(err_msg)); } let status_code = response.status(); diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs index 78159218c7..b3ffdb896b 100644 --- a/backend/windmill-api/src/apps.rs +++ b/backend/windmill-api/src/apps.rs @@ -20,8 +20,7 @@ use crate::{ use crate::{ job_helpers_ee::{ download_s3_file_internal, get_random_file_name, get_s3_resource, - get_workspace_s3_resource, load_image_preview_internal, upload_file_from_req, - DownloadFileQuery, LoadImagePreviewQuery, + get_workspace_s3_resource, upload_file_from_req, DownloadFileQuery, }, users::fetch_api_authed_from_permissioned_as, }; @@ -51,7 +50,6 @@ use sqlx::{types::Uuid, FromRow}; use std::str; use windmill_audit::audit_ee::audit_log; use windmill_audit::ActionKind; -use windmill_common::variables::encrypt; use windmill_common::{ apps::{AppScriptId, ListAppQuery}, cache::{self, future::FutureCachedExt}, @@ -63,16 +61,24 @@ use windmill_common::{ http_get_from_hub, not_found_if_none, paginate, query_elems_from_hub, require_admin, Pagination, StripPath, }, - variables::{build_crypt, build_crypt_with_key_suffix}, + variables::{build_crypt, build_crypt_with_key_suffix, encrypt}, worker::{to_raw_value, CLOUD_HOSTED}, HUB_BASE_URL, }; -#[cfg(feature = "parquet")] -use windmill_common::{jwt, s3_helpers::build_object_store_client}; use windmill_git_sync::{handle_deployment_metadata, DeployedObject}; use windmill_queue::{push, PushArgs, PushArgsOwned, PushIsolationLevel}; +#[cfg(feature = "parquet")] +use hmac::Mac; +#[cfg(feature = "parquet")] +use windmill_common::{ + jwt, + oauth2::HmacSha256, + s3_helpers::{build_object_store_client, S3Object}, + variables::get_workspace_key, +}; + pub fn workspaced_service() -> Router { Router::new() .route("/list", get(list_apps)) @@ -94,6 +100,7 @@ pub fn workspaced_service() -> Router { get(list_paths_from_workspace_runnable), ) .route("/custom_path_exists/*custom_path", get(custom_path_exists)) + .route("/sign_s3_objects", post(sign_s3_objects)) } pub fn unauthed_service() -> Router { @@ -102,10 +109,6 @@ pub fn unauthed_service() -> Router { .route("/upload_s3_file/*path", post(upload_s3_file_from_app)) .route("/delete_s3_file", delete(delete_s3_file_from_app)) .route("/download_s3_file/*path", get(download_s3_file_from_app)) - .route( - "/load_image_preview/*path", - get(load_s3_file_image_preview_from_app), - ) .route("/public_app/:secret", get(get_public_app_by_secret)) .route("/public_resource/*path", get(get_public_resource)) } @@ -232,7 +235,8 @@ pub struct S3Input { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct S3Key { s3_path: String, - resource: String, + #[serde(skip_serializing_if = "Option::is_none")] + storage: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Default)] @@ -1554,15 +1558,97 @@ struct UploadFileToS3Query { #[cfg(feature = "parquet")] #[derive(Serialize, Deserialize)] -struct DeleteTokenClaims { +struct S3DeleteTokenClaims { file_key: String, on_behalf_of_email: String, permissioned_as: String, username: String, s3_resource_path: Option, + workspace: String, pub exp: usize, } +#[cfg(feature = "parquet")] +#[derive(Deserialize)] +struct S3TokenRequestBody { + s3_objects: Vec, +} +#[cfg(feature = "parquet")] +async fn sign_s3_objects( + Extension(db): Extension, + Path(w_id): Path, + Json(body): Json, +) -> Result>> { + let workspace_key = get_workspace_key(&w_id, &db).await?; + + let futures = body.s3_objects.into_iter().map(|s3_object| async { + let exp = (chrono::Utc::now() + chrono::Duration::hours(12)).timestamp(); + let mut message = format!("file_key={}&exp={}", s3_object.s3.clone(), exp); + if let Some(ref storage) = s3_object.storage { + message = format!("{}&storage={}", message, storage); + } + + let mut max = HmacSha256::new_from_slice(workspace_key.as_bytes()) + .map_err(|err| Error::internal_err(format!("Failed to create hmac: {}", err)))?; + max.update(message.as_bytes()); + let result = max.finalize(); + let signature = hex::encode(result.into_bytes()); + + let presigned = format!("exp={}&sig={}", exp, signature); + + Ok::<_, Error>(S3Object { presigned: Some(presigned), ..s3_object }) + }); + + let signed_s3_objects = futures::future::try_join_all(futures).await?; + + Ok(Json(signed_s3_objects)) +} + +#[cfg(feature = "parquet")] +async fn validate_s3_signature(file_query: &AppS3FileQuery, w_id: &str, db: &DB) -> Result<()> { + let workspace_key = get_workspace_key(w_id, &db).await?; + + let Some(exp) = file_query + .exp + .as_ref() + .map(|e| e.parse::().unwrap_or_default()) + else { + return Err(Error::BadRequest("Missing exp".to_string())); + }; + + let Some(ref sig) = file_query.sig else { + return Err(Error::BadRequest("Missing signature".to_string())); + }; + + let mut message = format!("file_key={}&exp={}", file_query.s3, exp); + + if let Some(ref storage) = file_query.storage { + message = format!("{}&storage={}", message, storage); + } + + let mut mac = HmacSha256::new_from_slice(workspace_key.as_bytes()) + .map_err(|err| Error::internal_err(format!("Failed to create hmac: {}", err)))?; + + mac.update(message.as_bytes()); + + let sig_bytes = hex::decode(sig)?; + mac.verify_slice(&sig_bytes) + .map_err(|err| Error::BadRequest(format!("Invalid signature: {}", err)))?; + + if exp < chrono::Utc::now().timestamp() { + return Err(Error::BadRequest("Signature expired".to_string())); + } + + Ok(()) +} + +#[cfg(not(feature = "parquet"))] +async fn sign_s3_objects() -> Result<()> { + return Err(Error::BadRequest( + "This endpoint requires the parquet feature to be enabled".to_string(), + )); +} + #[cfg(feature = "parquet")] #[derive(Serialize)] struct AppUploadFileResponse { @@ -1817,13 +1903,14 @@ async fn upload_s3_file_from_app( upload_file_from_req(s3_client, &file_key, request, options).await?; - let delete_token = jwt::encode_with_internal_secret(DeleteTokenClaims { + let delete_token = jwt::encode_with_internal_secret(S3DeleteTokenClaims { file_key: file_key.clone(), on_behalf_of_email, permissioned_as, username, s3_resource_path: query.s3_resource_path, - exp: (chrono::Utc::now() + chrono::Duration::seconds(3600 * 24)).timestamp() as usize, + workspace: w_id.clone(), + exp: (chrono::Utc::now() + chrono::Duration::hours(12)).timestamp() as usize, }) .await?; @@ -1843,14 +1930,19 @@ async fn delete_s3_file_from_app( Path(w_id): Path, Query(query): Query, ) -> Result<()> { - let DeleteTokenClaims { + let S3DeleteTokenClaims { file_key, on_behalf_of_email, permissioned_as, username, s3_resource_path, + workspace, .. - } = jwt::decode_with_internal_secret::(&query.delete_token).await?; + } = jwt::decode_with_internal_secret::(&query.delete_token).await?; + + if workspace != w_id { + return Err(Error::BadRequest("Invalid workspace".to_string())); + } let on_behalf_authed = fetch_api_authed_from_permissioned_as( permissioned_as, @@ -1958,7 +2050,7 @@ async fn get_on_behalf_authed_from_app( async fn check_if_allowed_to_access_s3_file_from_app( db: &DB, opt_authed: &Option, - file_key: &str, + file_query: &AppS3FileQuery, w_id: &str, path: &str, policy: &Policy, @@ -1966,40 +2058,59 @@ async fn check_if_allowed_to_access_s3_file_from_app( // if anonymous, check that the file was the result of an app script ran by an anonymous user in the last 3 hours // otherwise, if logged in, allow any file (TODO: change that when we implement better s3 policy) - let allowed = opt_authed.is_some() - || sqlx::query_scalar!( - r#"SELECT EXISTS ( - SELECT 1 FROM v2_as_completed_job - WHERE workspace_id = $2 - AND (job_kind = 'appscript' OR job_kind = 'preview') - AND created_by = 'anonymous' - AND started_at > now() - interval '3 hours' - AND script_path LIKE $3 || '/%' - AND result @> ('{"s3":"' || $1 || '"}')::jsonb - )"#, - file_key, - w_id, - path, - ) - .fetch_one(db) - .await? - .unwrap_or(false) - - // check if the file is allowed by the allowed_s3_keys policy - || policy.allowed_s3_keys.as_ref().unwrap().iter().any(|key| key.s3_path == file_key); - - if !allowed { - Err(Error::BadRequest("File restricted".to_string())) - } else { + if file_query.sig.is_some() { + validate_s3_signature(file_query, w_id, &db).await + } else if opt_authed.is_some() { Ok(()) + } else { + let allowed = policy + .allowed_s3_keys + .as_ref() + .unwrap() + .iter() + .any(|key| key.s3_path == file_query.s3 && key.storage == file_query.storage) + || { + sqlx::query_scalar!( + r#"SELECT EXISTS ( + SELECT 1 FROM v2_as_completed_job + WHERE workspace_id = $2 + AND (job_kind = 'appscript' OR job_kind = 'preview') + AND created_by = 'anonymous' + AND started_at > now() - interval '3 hours' + AND script_path LIKE $3 || '/%' + AND result @> ('{"s3":"' || $1 || '"}')::jsonb + )"#, + file_query.s3, + w_id, + path, + ) + .fetch_one(db) + .await? + .unwrap_or(false) + }; + + if !allowed { + Err(Error::BadRequest("File restricted".to_string())) + } else { + Ok(()) + } } } #[cfg(feature = "parquet")] -#[derive(Deserialize)] -pub struct DownloadFileQueryWithForceViewerAllowedS3Keys { +#[derive(Deserialize, Debug)] +struct AppS3FileQuery { + s3: String, + storage: Option, + sig: Option, + exp: Option, +} + +#[cfg(feature = "parquet")] +#[derive(Deserialize, Debug)] +struct AppS3FileQueryWithForceViewerAllowedS3Keys { #[serde(flatten)] - pub file_query: DownloadFileQuery, + pub file_query: AppS3FileQuery, pub force_viewer_allowed_s3_keys: Option, } @@ -2008,7 +2119,7 @@ async fn download_s3_file_from_app( OptAuthed(opt_authed): OptAuthed, Extension(db): Extension, Path((w_id, path)): Path<(String, StripPath)>, - Query(query): Query, + Query(query): Query, ) -> Result { let path = path.to_path(); @@ -2027,46 +2138,26 @@ async fn download_s3_file_from_app( check_if_allowed_to_access_s3_file_from_app( &db, &opt_authed, - &query.file_query.file_key, + &query.file_query, &w_id, &path, &policy, ) .await?; - download_s3_file_internal(on_behalf_authed, &db, None, "", &w_id, query.file_query).await -} - -#[cfg(not(feature = "parquet"))] -async fn load_s3_file_image_preview_from_app() -> Result<()> { - return Err(Error::BadRequest( - "This endpoint requires the parquet feature to be enabled".to_string(), - )); -} - -#[cfg(feature = "parquet")] -async fn load_s3_file_image_preview_from_app( - OptAuthed(opt_authed): OptAuthed, - Extension(db): Extension, - Path((w_id, path)): Path<(String, StripPath)>, - Query(query): Query, -) -> Result { - let path = path.to_path(); - - let (on_behalf_authed, policy) = - get_on_behalf_authed_from_app(&db, &path, &w_id, &opt_authed, None).await?; - - check_if_allowed_to_access_s3_file_from_app( + download_s3_file_internal( + on_behalf_authed, &db, - &opt_authed, - &query.file_key, + None, + "", &w_id, - &path, - &policy, + DownloadFileQuery { + file_key: query.file_query.s3, + s3_resource_path: None, + storage: query.file_query.storage, + }, ) - .await?; - - load_image_preview_internal(on_behalf_authed, &db, "", &w_id, query).await + .await } fn get_on_behalf_of(policy: &Policy) -> Result<(String, String)> { diff --git a/backend/windmill-api/src/auth.rs b/backend/windmill-api/src/auth.rs index b0a18112d4..8175e0eae5 100644 --- a/backend/windmill-api/src/auth.rs +++ b/backend/windmill-api/src/auth.rs @@ -509,7 +509,6 @@ where .map(|x| x.0) .unwrap_or_default(); let path_vec: Vec<&str> = original_uri.path().split("/").collect(); - let workspace_id = if path_vec.len() >= 4 && path_vec[0] == "" && path_vec[2] == "w" { Some(path_vec[3].to_owned()) } else { diff --git a/backend/windmill-api/src/capture.rs b/backend/windmill-api/src/capture.rs index 06e4f4ad4d..93a11752d7 100644 --- a/backend/windmill-api/src/capture.rs +++ b/backend/windmill-api/src/capture.rs @@ -7,30 +7,47 @@ */ #[cfg(feature = "http_trigger")] -use crate::http_triggers::{build_http_trigger_extra, HttpMethod}; +use { + crate::{ + args::try_from_request_body, + http_triggers::{build_http_trigger_extra, HttpMethod}, + }, + axum::response::{IntoResponse, Response}, + std::collections::HashMap, +}; + +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +use crate::gcp_triggers_ee::{ + manage_google_subscription, process_google_push_request, validate_jwt_token, SubscriptionMode, +}; + +#[cfg(any( + feature = "http_trigger", + all(feature = "enterprise", feature = "gcp_trigger") +))] +use { + axum::extract::Request, http::HeaderMap, serde::de::DeserializeOwned, + windmill_common::error::Error, +}; + #[cfg(all(feature = "enterprise", feature = "kafka"))] use crate::kafka_triggers_ee::KafkaTriggerConfigConnection; + #[cfg(feature = "mqtt_trigger")] use crate::mqtt_triggers::{MqttClientVersion, MqttV3Config, MqttV5Config, SubscribeTopic}; + #[cfg(all(feature = "enterprise", feature = "nats"))] use crate::nats_triggers_ee::NatsTriggerConfigConnection; + #[cfg(feature = "postgres_trigger")] -use crate::postgres_triggers::{ - create_logical_replication_slot_query, create_publication_query, drop_publication_query, - generate_random_string, get_database_connection, PublicationData, +use { + crate::postgres_triggers::{ + create_logical_replication_slot_query, create_publication_query, drop_publication_query, + generate_random_string, get_database_connection, PublicationData, + }, + itertools::Itertools, + pg_escape::quote_literal, }; -#[cfg(feature = "http_trigger")] -use http::HeaderMap; -#[cfg(feature = "postgres_trigger")] -use itertools::Itertools; -#[cfg(feature = "postgres_trigger")] -use pg_escape::quote_literal; -#[cfg(feature = "http_trigger")] -use serde::de::DeserializeOwned; -#[cfg(feature = "http_trigger")] -use std::collections::HashMap; -#[cfg(feature = "http_trigger")] -use windmill_common::error::Error; use crate::{ args::WebhookArgs, @@ -38,23 +55,26 @@ use crate::{ users::fetch_api_authed, utils::RunnableKind, }; + use axum::{ extract::{Extension, Path, Query}, routing::{delete, get, head, post}, Json, Router, }; + use hyper::StatusCode; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; use sqlx::types::Json as SqlxJson; + use windmill_common::{ db::UserDB, error::{JsonResult, Result}, utils::{not_found_if_none, paginate, Pagination, StripPath}, worker::{to_raw_value, CLOUD_HOSTED}, }; -use windmill_queue::TriggerKind; -use windmill_queue::{PushArgs, PushArgsOwned}; + +use windmill_queue::{PushArgs, PushArgsOwned, TriggerKind}; const KEEP_LAST: i64 = 20; @@ -81,14 +101,26 @@ pub fn workspaced_unauthed_service() -> Router { head(|| async {}).post(webhook_payload), ); - #[cfg(feature = "http_trigger")] + #[cfg(any( + feature = "http_trigger", + all(feature = "enterprise", feature = "gcp_trigger") + ))] { - router.route("/http/:runnable_kind/:path/*route_path", { + #[cfg(feature = "http_trigger")] + let router = router.route("/http/:runnable_kind/:path/*route_path", { head(|| async {}).fallback(http_payload) - }) + }); + + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + let router = router.route("/gcp/:runnable_kind/*path", post(gcp_payload)); + + router } - #[cfg(not(feature = "http_trigger"))] + #[cfg(not(any( + feature = "http_trigger", + all(feature = "enterprise", feature = "gcp_trigger") + )))] { router } @@ -99,6 +131,8 @@ pub fn workspaced_unauthed_service() -> Router { struct HttpTriggerConfig { route_path: String, http_method: HttpMethod, + raw_string: Option, + wrap_body: Option, } #[cfg(all(feature = "enterprise", feature = "kafka"))] @@ -118,6 +152,15 @@ pub struct SqsTriggerConfig { pub message_attributes: Option>, } +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +#[derive(Debug, Serialize, Deserialize)] +pub struct GcpTriggerConfig { + pub gcp_resource_path: String, + #[serde(flatten)] + pub subscription_mode: SubscriptionMode, + pub topic_id: String, +} + #[cfg(all(feature = "enterprise", feature = "nats"))] #[derive(Serialize, Deserialize)] pub struct NatsTriggerConfig { @@ -175,6 +218,8 @@ enum TriggerConfig { Nats(NatsTriggerConfig), #[cfg(feature = "mqtt_trigger")] Mqtt(MqttTriggerConfig), + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + Gcp(GcpTriggerConfig), } #[derive(Serialize, Deserialize)] @@ -202,15 +247,26 @@ async fn get_configs( let configs = sqlx::query_as!( CaptureConfig, - r#"SELECT trigger_config as "trigger_config: _", trigger_kind as "trigger_kind: _", error, last_server_ping - FROM capture_config - WHERE workspace_id = $1 AND path = $2 AND is_flow = $3"#, + r#" + SELECT + trigger_config AS "trigger_config: _", + trigger_kind AS "trigger_kind: _", + error, + last_server_ping + FROM + capture_config + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 + "#, &w_id, &path.to_path(), matches!(runnable_kind, RunnableKind::Flow), ) .fetch_all(&mut *tx) .await?; + tx.commit().await?; Ok(Json(configs)) @@ -278,33 +334,100 @@ async fn set_postgres_trigger_config( Ok(capture_config) } +#[inline] +#[cfg(not(feature = "postgres_trigger"))] +async fn set_postgres_trigger_config( + _w_id: &str, + _authed: ApiAuthed, + _db: &DB, + _user_db: UserDB, + capture_config: NewCaptureConfig, +) -> Result { + Ok(capture_config) +} + +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +async fn set_gcp_trigger_config( + w_id: &str, + authed: ApiAuthed, + db: &DB, + mut capture_config: NewCaptureConfig, +) -> Result { + let Some(TriggerConfig::Gcp(mut gcp_config)) = capture_config.trigger_config else { + return Err(windmill_common::error::Error::BadRequest( + "Invalid GCP Pub/Sub config".to_string(), + )); + }; + + let config = manage_google_subscription( + authed, + db, + w_id, + &gcp_config.gcp_resource_path, + &capture_config.path, + &gcp_config.topic_id, + gcp_config.subscription_mode, + ) + .await?; + + gcp_config.subscription_mode = SubscriptionMode::CreateUpdate(config); + capture_config.trigger_config = Some(TriggerConfig::Gcp(gcp_config)); + + Ok(capture_config) +} + +#[inline] +#[cfg(not(all(feature = "enterprise", feature = "gcp_trigger")))] +async fn set_gcp_trigger_config( + _w_id: &str, + _authed: ApiAuthed, + _db: &DB, + capture_config: NewCaptureConfig, +) -> Result { + Ok(capture_config) +} + async fn set_config( authed: ApiAuthed, Extension(user_db): Extension, - #[cfg(feature = "postgres_trigger")] Extension(db): Extension, + Extension(db): Extension, Path(w_id): Path, Json(nc): Json, -) -> Result<()> { - #[cfg(feature = "postgres_trigger")] - let nc = if let TriggerKind::Postgres = nc.trigger_kind { - set_postgres_trigger_config(&w_id, authed.clone(), &db, user_db.clone(), nc).await? - } else { - nc +) -> JsonResult> { + let nc = match nc.trigger_kind { + TriggerKind::Postgres => { + set_postgres_trigger_config(&w_id, authed.clone(), &db, user_db.clone(), nc).await? + } + TriggerKind::Gcp => set_gcp_trigger_config(&w_id, authed.clone(), &db, nc).await?, + _ => nc, }; let mut tx = user_db.begin(&authed).await?; sqlx::query!( - "INSERT INTO capture_config - (workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email) - VALUES ($1, $2, $3, $4, $5, $6, $7) + r#" + INSERT INTO capture_config ( + workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email + ) + VALUES ( + $1, $2, $3, $4, $5, $6, $7 + ) ON CONFLICT (workspace_id, path, is_flow, trigger_kind) - DO UPDATE SET trigger_config = $5, owner = $6, email = $7, server_id = NULL, error = NULL", + DO UPDATE + SET + trigger_config = $5, + owner = $6, + email = $7, + server_id = NULL, + error = NULL + "#, &w_id, &nc.path, nc.is_flow, nc.trigger_kind as TriggerKind, - nc.trigger_config.map(|x| SqlxJson(to_raw_value(&x))) as Option>>, + nc.trigger_config + .as_ref() + .map(|x| SqlxJson(to_raw_value(&x))) as Option>>, &authed.username, &authed.email, ) @@ -313,7 +436,7 @@ async fn set_config( tx.commit().await?; - Ok(()) + Ok(Json(nc.trigger_config)) } async fn ping_config( @@ -327,8 +450,19 @@ async fn ping_config( )>, ) -> Result<()> { let mut tx = user_db.begin(&authed).await?; + sqlx::query!( - "UPDATE capture_config SET last_client_ping = now() WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4", + r#" + UPDATE + capture_config + SET + last_client_ping = NOW() + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 + AND trigger_kind = $4 + "#, &w_id, &path.to_path(), matches!(runnable_kind, RunnableKind::Flow), @@ -336,6 +470,7 @@ async fn ping_config( ) .execute(&mut *tx) .await?; + tx.commit().await?; Ok(()) } @@ -368,14 +503,28 @@ async fn list_captures( let captures = sqlx::query_as!( Capture, - r#"SELECT id, created_at, trigger_kind as "trigger_kind: _", CASE WHEN pg_column_size(payload) < 40000 THEN payload ELSE '"WINDMILL_TOO_BIG"'::jsonb END as "payload!: _", trigger_extra as "trigger_extra: _" - FROM capture - WHERE workspace_id = $1 - AND path = $2 AND is_flow = $3 + r#" + SELECT + id, + created_at, + trigger_kind AS "trigger_kind: _", + CASE + WHEN pg_column_size(payload) < 40000 THEN payload + ELSE '"WINDMILL_TOO_BIG"'::jsonb + END AS "payload!: _", + trigger_extra AS "trigger_extra: _" + FROM + capture + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 AND ($4::trigger_kind IS NULL OR trigger_kind = $4) - ORDER BY created_at DESC + ORDER BY + created_at DESC OFFSET $5 - LIMIT $6"#, + LIMIT $6 + "#, &w_id, &path.to_path(), matches!(runnable_kind, RunnableKind::Flow), @@ -397,14 +546,28 @@ async fn get_capture( Path((w_id, id)): Path<(String, i64)>, ) -> JsonResult { let mut tx = user_db.begin(&authed).await?; + let capture = sqlx::query_as!( Capture, - r#"SELECT id, created_at, trigger_kind as "trigger_kind: _", payload as "payload!: _", trigger_extra as "trigger_extra: _" FROM capture WHERE id = $1 AND workspace_id = $2"#, + r#" + SELECT + id, + created_at, + trigger_kind AS "trigger_kind: _", + payload AS "payload!: _", + trigger_extra AS "trigger_extra: _" + FROM + capture + WHERE + id = $1 + AND workspace_id = $2 + "#, id, &w_id, ) .fetch_one(&mut *tx) - .await?; + .await?; + tx.commit().await?; Ok(Json(capture)) } @@ -415,9 +578,17 @@ async fn delete_capture( Path((_, id)): Path<(String, i64)>, ) -> Result<()> { let mut tx = user_db.begin(&authed).await?; - sqlx::query!("DELETE FROM capture WHERE id = $1", id) - .execute(&mut *tx) - .await?; + sqlx::query!( + r#" + DELETE FROM + capture + WHERE + id = $1 + "#, + id + ) + .execute(&mut *tx) + .await?; tx.commit().await?; Ok(()) } @@ -435,8 +606,18 @@ async fn move_captures_and_configs( ) -> Result<()> { let mut tx = user_db.begin(&authed).await?; let old_path = old_path.to_path(); + sqlx::query!( - "UPDATE capture_config SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4", + r#" + UPDATE + capture_config + SET + path = $1 + WHERE + path = $2 + AND workspace_id = $3 + AND is_flow = $4 + "#, body.new_path, old_path, &w_id, @@ -444,8 +625,18 @@ async fn move_captures_and_configs( ) .execute(&mut *tx) .await?; + sqlx::query!( - "UPDATE capture SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4", + r#" + UPDATE + capture + SET + path = $1 + WHERE + path = $2 + AND workspace_id = $3 + AND is_flow = $4 + "#, body.new_path, old_path, &w_id, @@ -453,6 +644,7 @@ async fn move_captures_and_configs( ) .execute(&mut *tx) .await?; + tx.commit().await?; Ok(()) } @@ -472,9 +664,19 @@ pub async fn get_active_capture_owner_and_email( ) -> Result<(String, String)> { let capture_config = sqlx::query_as!( ActiveCaptureOwner, - "SELECT owner, email - FROM capture_config - WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'", + r#" + SELECT + owner, + email + FROM + capture_config + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 + AND trigger_kind = $4 + AND last_client_ping > NOW() - INTERVAL '10 seconds' + "#, &w_id, &path, is_flow, @@ -492,7 +694,10 @@ pub async fn get_active_capture_owner_and_email( Ok((capture_config.owner, capture_config.email)) } -#[cfg(feature = "http_trigger")] +#[cfg(any( + feature = "http_trigger", + all(feature = "enterprise", feature = "gcp_trigger") +))] async fn get_capture_trigger_config_and_owner( db: &DB, w_id: &str, @@ -506,16 +711,34 @@ async fn get_capture_trigger_config_and_owner( owner: String, email: String, } - let capture_config = sqlx::query_as!( CaptureTriggerConfigAndOwner, - r#"SELECT trigger_config as "trigger_config: _", owner, email - FROM capture_config - WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'"#, + r#" + SELECT + trigger_config AS "trigger_config: _", + owner, + email + FROM + capture_config + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 + AND trigger_kind = $4 + AND last_client_ping > NOW() - INTERVAL '10 seconds' + AND ( + $5::bool IS FALSE + OR ( + trigger_config IS NOT NULL + AND trigger_config ->> 'delivery_type' = 'push' + ) + ) + "#, &w_id, &path, is_flow, kind as &TriggerKind, + matches!(kind, TriggerKind::Gcp) ) .fetch_optional(db) .await?; @@ -548,17 +771,24 @@ async fn clear_captures_history(db: &DB, w_id: &str) -> Result<()> { if *CLOUD_HOSTED { /* Retain only KEEP_LAST most recent captures in this workspace. */ sqlx::query!( - "DELETE FROM capture - WHERE workspace_id = $1 - AND created_at <= - ( - SELECT created_at - FROM capture - WHERE workspace_id = $1 - ORDER BY created_at DESC - OFFSET $2 - LIMIT 1 - )", + r#" + DELETE FROM + capture + WHERE + workspace_id = $1 + AND created_at <= ( + SELECT + created_at + FROM + capture + WHERE + workspace_id = $1 + ORDER BY + created_at DESC + OFFSET $2 + LIMIT 1 + ) + "#, &w_id, KEEP_LAST, ) @@ -579,8 +809,15 @@ pub async fn insert_capture_payload( owner: &str, ) -> Result<()> { sqlx::query!( - "INSERT INTO capture (workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by) - VALUES ($1, $2, $3, $4, $5, $6, $7)", + r#" + INSERT INTO + capture ( + workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by + ) + VALUES ( + $1, $2, $3, $4, $5, $6, $7 + ) + "#, &w_id, path, is_flow, @@ -636,36 +873,94 @@ async fn webhook_payload( Ok(StatusCode::NO_CONTENT) } +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +async fn gcp_payload( + Extension(db): Extension, + Extension(user_db): Extension, + Path((w_id, runnable_kind, path)): Path<(String, RunnableKind, String)>, + headers: HeaderMap, + request: Request, +) -> Result { + let is_flow = matches!(runnable_kind, RunnableKind::Flow); + let (gcp_trigger_config, owner, email): (GcpTriggerConfig, _, _) = + get_capture_trigger_config_and_owner(&db, &w_id, &path, is_flow, &TriggerKind::Gcp).await?; + + let authed = fetch_api_authed(owner.clone(), email, &w_id, &db, None).await?; + + let SubscriptionMode::CreateUpdate(config) = &gcp_trigger_config.subscription_mode else { + return Err(Error::BadConfig("Bad config".to_string())); + }; + + validate_jwt_token( + &db, + user_db.clone(), + authed.clone(), + &headers, + &gcp_trigger_config.gcp_resource_path, + &w_id, + config.delivery_config.as_ref().unwrap(), + ) + .await?; + + let (args, extra) = process_google_push_request(headers, request).await?; + + let payload = PushArgsOwned { args, extra: None }; + + let _ = insert_capture_payload( + &db, + &w_id, + &path, + is_flow, + &TriggerKind::Gcp, + payload, + Some(to_raw_value(&extra)), + &owner, + ) + .await?; + + Ok(StatusCode::NO_CONTENT) +} + #[cfg(feature = "http_trigger")] async fn http_payload( Extension(db): Extension, - Path((w_id, kind, path, route_path)): Path<(String, RunnableKind, String, StripPath)>, + Path((w_id, runnable_kind, path, route_path)): Path<(String, RunnableKind, String, StripPath)>, Query(query): Query>, method: http::Method, headers: HeaderMap, - args: WebhookArgs, -) -> Result { - let route_path = route_path.to_path(); + request: Request, +) -> std::result::Result { let path = path.replace(".", "/"); - + let is_flow = matches!(runnable_kind, RunnableKind::Flow); + let route_path = route_path.to_path(); let (http_trigger_config, owner, email): (HttpTriggerConfig, _, _) = - get_capture_trigger_config_and_owner( - &db, - &w_id, - &path, - matches!(kind, RunnableKind::Flow), - &TriggerKind::Http, - ) - .await?; + get_capture_trigger_config_and_owner(&db, &w_id, &path, is_flow, &TriggerKind::Http) + .await + .map_err(|e| e.into_response())?; - let authed = fetch_api_authed(owner.clone(), email, &w_id, &db, None).await?; - let args = args.to_push_args_owned(&authed, &db, &w_id).await?; + let args = try_from_request_body( + request, + &(), + http_trigger_config.raw_string, + http_trigger_config.wrap_body, + ) + .await + .map_err(|e| e.into_response())?; + + let authed = fetch_api_authed(owner.clone(), email, &w_id, &db, None) + .await + .map_err(|e| e.into_response())?; + let mut args = args + .to_push_args_owned(&authed, &db, &w_id) + .await + .map_err(|e| e.into_response())?; let mut router = matchit::Router::new(); router.insert(&http_trigger_config.route_path, ()).ok(); let match_ = router.at(route_path).ok(); - let match_ = not_found_if_none(match_, "capture http trigger", &route_path)?; + let match_ = not_found_if_none(match_, "capture http trigger", &route_path) + .map_err(|e| e.into_response())?; let matchit::Match { params, .. } = match_; @@ -674,7 +969,9 @@ async fn http_payload( .map(|(k, v)| (k.to_string(), v.to_string())) .collect(); - let extra: HashMap> = HashMap::from_iter(vec![( + let extra = args.extra.get_or_insert_with(HashMap::new); + + extra.insert( "wm_trigger".to_string(), build_http_trigger_extra( &http_trigger_config.route_path, @@ -685,19 +982,22 @@ async fn http_payload( &headers, ) .await, - )]); + ); + let extra = Some(to_raw_value(&extra)); + args.extra = None; insert_capture_payload( &db, &w_id, &path, - matches!(kind, RunnableKind::Flow), + is_flow, &TriggerKind::Http, args, - Some(to_raw_value(&extra)), + extra, &owner, ) - .await?; + .await + .map_err(|e| e.into_response())?; Ok(StatusCode::NO_CONTENT) } diff --git a/backend/windmill-api/src/concurrency_groups.rs b/backend/windmill-api/src/concurrency_groups.rs index e59821c3e5..4135c3729c 100644 --- a/backend/windmill-api/src/concurrency_groups.rs +++ b/backend/windmill-api/src/concurrency_groups.rs @@ -215,6 +215,7 @@ async fn get_concurrent_intervals( is_flow_step: _, all_workspaces: _, concurrency_key: Some(_), + allow_wildcards: None, } => true, _ => false, }; diff --git a/backend/windmill-api/src/drafts.rs b/backend/windmill-api/src/drafts.rs index 6ba1f4452f..02d3b3c4fb 100644 --- a/backend/windmill-api/src/drafts.rs +++ b/backend/windmill-api/src/drafts.rs @@ -1,6 +1,6 @@ /* * Author: Ruben Fiszel - * Copyright: Windmill Labs, Inc 2042 + * Copyright: Windmill Labs, Inc 2024 * This file and its contents are licensed under the AGPLv3 License. * Please see the included NOTICE for copyright information and * LICENSE-AGPL for a copy of the license. diff --git a/backend/windmill-api/src/gcp_triggers_ee.rs b/backend/windmill-api/src/gcp_triggers_ee.rs new file mode 100644 index 0000000000..ec0a6ec115 --- /dev/null +++ b/backend/windmill-api/src/gcp_triggers_ee.rs @@ -0,0 +1,133 @@ +use crate::db::{ApiAuthed, DB}; +use axum::{extract::Request, Router}; +use http::HeaderMap; +use serde::{Deserialize, Serialize}; +use serde_json::value::RawValue; +use sqlx::prelude::FromRow; +use sqlx::types::Json as SqlxJson; +use std::collections::HashMap; +use windmill_common::db::UserDB; +use windmill_common::{ + error::{Error as WindmillError, Result as WindmillResult}, + utils::empty_string_as_none, +}; + +#[derive(sqlx::Type, Debug, Deserialize, Serialize)] +#[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))] +#[sqlx(type_name = "DELIVERY_MODE", rename_all = "lowercase")] +#[allow(unused)] +pub enum DeliveryType { + Pull, + Push, +} + +impl Default for DeliveryType { + fn default() -> Self { + Self::Pull + } +} + +#[derive(FromRow, Deserialize, Serialize, Debug)] +#[allow(unused)] +pub struct PushConfig { + #[serde(deserialize_with = "empty_string_as_none")] + route_path: Option, + #[serde(deserialize_with = "empty_string_as_none")] + audience: Option, + authenticate: bool, + base_endpoint: String, +} +#[derive(Default, Debug, Serialize, Deserialize)] +#[allow(unused)] +pub struct CreateUpdateConfig { + pub delivery_type: DeliveryType, + #[serde(default, deserialize_with = "empty_string_as_none")] + pub subscription_id: Option, + pub delivery_config: Option>, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct ExistingGcpSubscription { + pub subscription_id: String, + pub base_endpoint: String, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(tag = "subscription_mode", rename_all = "snake_case")] +pub enum SubscriptionMode { + Existing(ExistingGcpSubscription), + CreateUpdate(CreateUpdateConfig), +} + +pub fn workspaced_service() -> Router { + Router::new() +} + +pub fn start_consuming_gcp_pubsub_event( + _db: DB, + mut _killpill_rx: tokio::sync::broadcast::Receiver<()>, +) -> () { + // implementation is not open source +} + +pub async fn manage_google_subscription( + _authed: ApiAuthed, + _db: &DB, + _workspace_id: &str, + _gcp_resource_path: &str, + _path: &str, + _topic_id: &str, + _subscription_mode: SubscriptionMode, +) -> WindmillResult { + Ok(CreateUpdateConfig::default()) +} + +pub async fn process_google_push_request( + _headers: HeaderMap, + _request: Request, +) -> Result< + ( + HashMap>, + Option>>, + ), + WindmillError, +> { + Ok((HashMap::new(), None)) +} + +pub async fn validate_jwt_token( + _db: &DB, + _user_db: UserDB, + _authed: ApiAuthed, + _headers: &HeaderMap, + _gcp_resource_path: &str, + _workspace_id: &str, + _delivery_config: &PushConfig, +) -> Result<(), windmill_common::error::Error> { + Ok(()) +} + +pub fn gcp_push_route_handler() -> Router { + Router::new() +} + +#[derive(FromRow, Deserialize, Serialize, Debug)] +pub struct GcpTrigger { + pub gcp_resource_path: String, + pub subscription_id: String, + pub delivery_type: DeliveryType, + pub delivery_config: Option>, + pub topic_id: String, + pub path: String, + pub script_path: String, + pub is_flow: bool, + pub workspace_id: String, + pub edited_by: String, + pub email: String, + pub edited_at: chrono::DateTime, + pub extra_perms: Option, + pub error: Option, + pub server_id: Option, + pub last_server_ping: Option>, + pub enabled: bool, +} diff --git a/backend/windmill-api/src/git_sync_ee.rs b/backend/windmill-api/src/git_sync_ee.rs new file mode 100644 index 0000000000..b72afac189 --- /dev/null +++ b/backend/windmill-api/src/git_sync_ee.rs @@ -0,0 +1,9 @@ +use axum::routing::Router; + +pub fn workspaced_service() -> Router { + Router::new() +} + +pub fn global_service() -> Router { + Router::new() +} \ No newline at end of file diff --git a/backend/windmill-api/src/http_trigger_auth.rs b/backend/windmill-api/src/http_trigger_auth.rs new file mode 100644 index 0000000000..fd15927b69 --- /dev/null +++ b/backend/windmill-api/src/http_trigger_auth.rs @@ -0,0 +1,751 @@ +use axum::response::{IntoResponse, Response}; +use base64::{ + prelude::{BASE64_STANDARD, BASE64_URL_SAFE}, + Engine, +}; +use hmac::{Hmac, Mac}; +use http::{header, HeaderMap, HeaderValue, StatusCode}; +use itertools::Itertools; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use sha1::Sha1; +use sha2::{Sha256, Sha512}; +use std::{borrow::Cow, collections::HashMap}; + +pub type HmacSha256 = Hmac; +pub type HmacSha512 = Hmac; +pub type HmacSha1 = Hmac; + +mod github { + use super::*; + pub struct Github; + + impl WebhookHandler for Github { + fn handle_challenge_request<'header>( + &self, + _: &'header HeaderMap, + _: &SignatureConfigData, + _: &str, + ) -> Result, AuthenticationError> { + Ok(None) + } + + fn get_hmac_authentication_data<'payload, 'header, 'prefix>( + &self, + headers: &'header HeaderMap, + raw_payload: &'payload str, + ) -> Result, AuthenticationError> + { + let github_secret_header = headers.try_get_webhook_header("X-Hub-Signature-256")?; + + let authentication_data = SignatureAuthenticationData::new( + Cow::Borrowed(raw_payload), + github_secret_header, + Some("sha256="), + SignatureAuthenticationDetails::new(HmacAlgorithm::Sha256, Encoding::Hex), + ); + + Ok(authentication_data) + } + } +} + +mod slack { + use super::*; + pub struct Slack; + + impl WebhookHandler for Slack { + fn handle_challenge_request<'header>( + &self, + _: &'header HeaderMap, + _: &SignatureConfigData, + _: &str, + ) -> Result, AuthenticationError> { + Ok(None) + } + + fn get_hmac_authentication_data<'payload, 'header, 'prefix>( + &self, + headers: &'header HeaderMap, + raw_payload: &'payload str, + ) -> Result, AuthenticationError> + { + let slack_secret_signature = headers.try_get_webhook_header("X-Slack-Signature")?; + let slack_timestamp_header = + headers.try_get_webhook_header("X-Slack-Request-Timestamp")?; + let signed_payload = format!("v0:{}:{}", slack_timestamp_header, raw_payload); + + Ok(SignatureAuthenticationData::new( + Cow::Owned(signed_payload), + slack_secret_signature, + Some("v0="), + SignatureAuthenticationDetails::new(HmacAlgorithm::Sha256, Encoding::Hex), + )) + } + } +} + +mod stripe { + use super::*; + + pub struct Stripe; + + impl WebhookHandler for Stripe { + fn handle_challenge_request<'header>( + &self, + _: &'header HeaderMap, + _: &SignatureConfigData, + _: &str, + ) -> Result, AuthenticationError> { + Ok(None) + } + + fn get_hmac_authentication_data<'payload, 'header, 'prefix>( + &self, + headers: &'header HeaderMap, + raw_payload: &'payload str, + ) -> Result, AuthenticationError> + { + let stripe_signature_header = headers.try_get_webhook_header("STRIPE-SIGNATURE")?; + + let stripe_signature = parse_signature(stripe_signature_header, (",", "=")); + + let timestamp = *stripe_signature + .get("t") + .ok_or(AuthenticationError::InvalidTimestamp)?; + let v1 = *stripe_signature + .get("v1") + .ok_or(AuthenticationError::InvalidSignature)?; + + let signed_payload = format!("{}.{}", timestamp, raw_payload); + + Ok(SignatureAuthenticationData::new( + Cow::Owned(signed_payload), + v1, + None, + SignatureAuthenticationDetails::new(HmacAlgorithm::Sha256, Encoding::Hex), + )) + } + } +} + +mod tiktok { + use super::*; + + pub struct TikTok; + + impl WebhookHandler for TikTok { + fn handle_challenge_request<'header>( + &self, + _: &'header HeaderMap, + _: &SignatureConfigData, + _: &str, + ) -> Result, AuthenticationError> { + Ok(None) + } + + fn get_hmac_authentication_data<'payload, 'header, 'prefix>( + &self, + headers: &'header HeaderMap, + raw_payload: &'payload str, + ) -> Result, AuthenticationError> + { + let tiktok_secret_signature = headers.try_get_webhook_header("TikTok-Signature")?; + + let stripe_signature = parse_signature(tiktok_secret_signature, (",", "=")); + + let timestamp = *stripe_signature + .get("t") + .ok_or(AuthenticationError::InvalidTimestamp)?; + let s = *stripe_signature + .get("s") + .ok_or(AuthenticationError::InvalidSignature)?; + + let signed_payload = format!("{}.{}", timestamp, raw_payload); + + Ok(SignatureAuthenticationData::new( + Cow::Owned(signed_payload), + s, + None, + SignatureAuthenticationDetails::new(HmacAlgorithm::Sha256, Encoding::Hex), + )) + } + } +} + +mod twitch { + use super::*; + use http::header; + use serde_json::value::RawValue; + #[derive(Debug, Deserialize)] + struct TwitchCrcBody { + challenge: String, + #[allow(unused)] + subscription: Box, + } + + pub struct Twitch; + + impl WebhookHandler for Twitch { + fn get_hmac_authentication_data<'payload, 'header, 'prefix>( + &self, + headers: &'header HeaderMap, + raw_payload: &'payload str, + ) -> Result, AuthenticationError> + { + let twitch_secret_signature = + headers.try_get_webhook_header("Twitch-Eventsub-Message-Signature")?; + let twitch_message_id_header = + headers.try_get_webhook_header("Twitch-Eventsub-Message-Id")?; + let twitch_timestamp_header = + headers.try_get_webhook_header("Twitch-Eventsub-Message-Timestamp")?; + + let message = format!( + "{}{}{}", + twitch_message_id_header, twitch_timestamp_header, raw_payload + ); + + Ok(SignatureAuthenticationData::new( + Cow::Owned(message), + twitch_secret_signature, + Some("sha256="), + SignatureAuthenticationDetails::new(HmacAlgorithm::Sha256, Encoding::Hex), + )) + } + + fn handle_challenge_request<'header>( + &self, + headers: &'header HeaderMap, + signature_config_data: &SignatureConfigData, + raw_payload: &str, + ) -> Result, AuthenticationError> { + let authentication_data = self.get_hmac_authentication_data(headers, raw_payload)?; + verify_hmac_signature(authentication_data, &signature_config_data.secret_key)?; + + let twitch_eventsub_message_type = + headers.try_get_webhook_header("Twitch-Eventsub-Message-Type")?; + + if twitch_eventsub_message_type != "webhook_callback_verification" { + return Ok(None); + } + let twitch_crc_body = + serde_json::from_str::(raw_payload).map_err(|e| { + AuthenticationError::InvalidChallengeResponse(format!( + "Twitch :{}", + e.to_string() + )) + })?; + + let response = ( + StatusCode::OK, + [(header::CONTENT_TYPE, "text/plain")], + twitch_crc_body.challenge.to_string(), + ); + + Ok(Some(response.into_response())) + } + } +} + +mod zoom { + use axum::Json; + + use super::*; + + #[derive(Debug, Deserialize)] + #[serde(rename_all = "snake_case")] + struct ZoomPayload { + plain_token: String, + } + + #[derive(Debug, Deserialize)] + #[allow(unused)] + struct ZoomChallengeResponse { + payload: ZoomPayload, + event_ts: u64, + event: String, + } + + pub struct Zoom; + + impl WebhookHandler for Zoom { + fn handle_challenge_request<'header>( + &self, + _: &'header HeaderMap, + signature_config_data: &SignatureConfigData, + raw_payload: &str, + ) -> Result, AuthenticationError> { + let Ok(zoom_request_body) = serde_json::from_str::(raw_payload) + else { + return Ok(None); + }; + + if zoom_request_body.event != "endpoint.url_validation" { + return Ok(None); + } + + let hmac_signature = calculate_hmac_signature( + HmacAlgorithm::Sha256, + &signature_config_data.secret_key, + &zoom_request_body.payload.plain_token, + ); + + let encoded_hmac_signature = encode_hmac_signature(Encoding::Hex, &hmac_signature); + + let response = ( + StatusCode::OK, + Json(json!({ + "plainToken": zoom_request_body.payload.plain_token, + "encryptedToken": encoded_hmac_signature + })), + ); + + Ok(Some(response.into_response())) + } + + fn get_hmac_authentication_data<'payload, 'header, 'prefix>( + &self, + headers: &'header HeaderMap, + raw_payload: &'payload str, + ) -> Result, AuthenticationError> + { + let zoom_signature_header = headers.try_get_webhook_header("x-zm-signature")?; + let zoom_timestamp_header = headers.try_get_webhook_header("x-zm-request-timestamp")?; + + let message = format!("v0:{}:{}", zoom_timestamp_header, raw_payload); + + Ok(SignatureAuthenticationData::new( + Cow::Owned(message), + zoom_signature_header, + Some("v0="), + SignatureAuthenticationDetails::new(HmacAlgorithm::Sha256, Encoding::Hex), + )) + } + } +} + +use constant_time_eq::constant_time_eq; +use github::Github; +use slack::Slack; +use stripe::Stripe; +use tiktok::TikTok; +use twitch::Twitch; +use zoom::Zoom; + +#[derive(Debug)] +pub struct SignatureAuthenticationDetails { + pub algorithm_to_use: HmacAlgorithm, + pub header_key_encoding: Encoding, +} + +impl SignatureAuthenticationDetails { + #[inline] + fn new(algorithm_to_use: HmacAlgorithm, header_key_encoding: Encoding) -> Self { + Self { algorithm_to_use, header_key_encoding } + } +} + +fn parse_signature<'header>( + signature: &'header str, + splitters: (&str, &str), +) -> HashMap<&'header str, &'header str> { + let headers: HashMap<&str, &str> = signature + .split(splitters.0) + .map(|header| { + let mut key_and_value = header.split(splitters.1); + let key = key_and_value.next(); + let value = key_and_value.next(); + (key, value) + }) + .filter_map(|(key, value)| match (key, value) { + (Some(key), Some(value)) => Some((key, value)), + _ => None, + }) + .collect(); + headers +} + +#[derive(Debug)] +pub struct SignatureAuthenticationData<'payload, 'header, 'prefix> { + pub signed_payload: Cow<'payload, str>, + pub header_key_value: &'header str, + pub signature_prefix: Option<&'prefix str>, + pub config: SignatureAuthenticationDetails, +} + +impl<'payload, 'header, 'prefix> SignatureAuthenticationData<'payload, 'header, 'prefix> { + pub fn new( + signed_payload: Cow<'payload, str>, + header_key_value: &'header str, + signature_prefix: Option<&'prefix str>, + config: SignatureAuthenticationDetails, + ) -> Self { + Self { signed_payload, header_key_value, signature_prefix, config } + } +} + +pub trait WebhookHandler { + fn handle_challenge_request<'header>( + &self, + headers: &'header HeaderMap, + signature_config_data: &SignatureConfigData, + raw_payload: &str, + ) -> Result, AuthenticationError>; + + fn get_hmac_authentication_data<'payload, 'header, 'prefix>( + &self, + headers: &'header HeaderMap, + raw_payload: &'payload str, + ) -> Result, AuthenticationError>; +} + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum HmacAlgorithm { + Sha1, + Sha256, + Sha512, +} + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum Encoding { + Base64, + Base64Uri, + Hex, +} +#[derive(Debug, Serialize, Deserialize)] +pub struct SignatureAuthenticationMethod { + algorithm: HmacAlgorithm, + encoding: Encoding, + signature_header_name: String, + signature_prefix: Option, +} + +pub struct SignatureConfigData<'config> { + secret_key: &'config str, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SignatureAuthentication { + signature_provider: WebhookType, + secret_key: String, + authentication_config: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct BasicAuthAuthentication { + pub username: String, + pub password: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ApiKeyAuthentication { + api_key_header: String, + api_key_secret: String, +} + +#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, Serialize, Deserialize)] +#[non_exhaustive] +pub enum WebhookType { + Github, + Slack, + Stripe, + TikTok, + Twitch, + Zoom, + Custom, +} + +impl WebhookType { + pub fn get_webhook_handler(&self) -> Option<&'static dyn WebhookHandler> { + let handler: &'static dyn WebhookHandler = match *self { + WebhookType::Github => &Github, + WebhookType::Slack => &Slack, + WebhookType::Stripe => &Stripe, + WebhookType::TikTok => &TikTok, + WebhookType::Twitch => &Twitch, + WebhookType::Zoom => &Zoom, + WebhookType::Custom => return None, + }; + Some(handler) + } +} + +trait TryGetWebhookHeader { + fn try_get_webhook_header<'header>( + &'header self, + header_name: &str, + ) -> Result<&'header str, AuthenticationError>; +} + +impl TryGetWebhookHeader for HeaderMap { + fn try_get_webhook_header<'header>( + &'header self, + header_name: &str, + ) -> Result<&'header str, AuthenticationError> { + let Some(signature_header) = self.get(header_name) else { + return Err(AuthenticationError::MissingHeader(header_name.to_string())); + }; + let Some(signature_header) = signature_header.to_str().ok() else { + return Err(AuthenticationError::InvalidHeader(header_name.to_string())); + }; + + Ok(signature_header) + } +} + +pub fn calculate_hmac_signature(algorithm: HmacAlgorithm, secret: &str, payload: &str) -> Vec { + match algorithm { + HmacAlgorithm::Sha1 => { + let mut mac = + HmacSha1::new_from_slice(secret.as_bytes()).expect("HMAC can take key of any size"); + mac.update(payload.as_bytes()); + mac.finalize().into_bytes().to_vec() + } + HmacAlgorithm::Sha256 => { + let mut mac = HmacSha256::new_from_slice(secret.as_bytes()) + .expect("HMAC can take key of any size"); + mac.update(payload.as_bytes()); + mac.finalize().into_bytes().to_vec() + } + HmacAlgorithm::Sha512 => { + let mut mac = HmacSha512::new_from_slice(secret.as_bytes()) + .expect("HMAC can take key of any size"); + mac.update(payload.as_bytes()); + mac.finalize().into_bytes().to_vec() + } + } +} + +pub fn encode_hmac_signature(encoding: Encoding, hmac_signature: &[u8]) -> String { + match encoding { + Encoding::Hex => hex::encode(hmac_signature), + Encoding::Base64 => BASE64_STANDARD.encode(hmac_signature), + Encoding::Base64Uri => BASE64_URL_SAFE.encode(hmac_signature), + } +} + +pub fn verify_hmac_signature( + authentication_data: SignatureAuthenticationData, + webhook_signing_secret: &str, +) -> Result<(), AuthenticationError> { + let hmac_signature = calculate_hmac_signature( + authentication_data.config.algorithm_to_use, + &webhook_signing_secret, + &authentication_data.signed_payload, + ); + + let encoded_signature = encode_hmac_signature( + authentication_data.config.header_key_encoding, + &hmac_signature, + ); + + let final_expected_signature = + if let Some(signature_prefix) = authentication_data.signature_prefix { + format!("{}{}", signature_prefix, encoded_signature) + } else { + encoded_signature + }; + + if !constant_time_eq( + final_expected_signature.as_bytes(), + authentication_data.header_key_value.as_bytes(), + ) { + return Err(AuthenticationError::InvalidSignature); + } + + Ok(()) +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AuthenticationMethod { + Signature(SignatureAuthentication), + BasicAuth(BasicAuthAuthentication), + ApiKey(ApiKeyAuthentication), +} + +impl AuthenticationMethod { + pub fn authenticate_http_request( + &self, + headers: &HeaderMap, + raw_payload: Option<&String>, + ) -> Result, AuthenticationError> { + match self { + AuthenticationMethod::Signature(SignatureAuthentication { + secret_key, + authentication_config, + signature_provider, + }) => { + let raw_payload = raw_payload.ok_or(AuthenticationError::InvalidPayload)?; + let config_data = SignatureConfigData { secret_key: &secret_key }; + let handler = signature_provider.get_webhook_handler(); + let challenge_response = handler + .map(|handler| { + handler.handle_challenge_request(headers, &config_data, raw_payload) + }) + .transpose()? + .flatten(); + + if let Some(challenge_response) = challenge_response { + return Ok(Some(challenge_response)); + } + + let authentication_data = match handler { + Some(handler) => handler.get_hmac_authentication_data(headers, raw_payload)?, + None => { + let authentication_config = authentication_config + .as_ref() + .ok_or(AuthenticationError::InvalidCustomConfig)?; + let signature_header_value = headers + .try_get_webhook_header(&authentication_config.signature_header_name)?; + SignatureAuthenticationData::new( + Cow::Borrowed(raw_payload), + signature_header_value, + authentication_config.signature_prefix.as_deref(), + SignatureAuthenticationDetails::new( + authentication_config.algorithm, + authentication_config.encoding, + ), + ) + } + }; + + verify_hmac_signature(authentication_data, &secret_key)?; + } + AuthenticationMethod::ApiKey(ApiKeyAuthentication { + api_key_header, + api_key_secret, + }) => { + let api_key_to_cmp = headers + .try_get_webhook_header(&api_key_header) + .map_err(|_| AuthenticationError::InvalidApiKey)?; + if api_key_to_cmp != api_key_secret { + return Err(AuthenticationError::InvalidApiKey); + } + } + AuthenticationMethod::BasicAuth(BasicAuthAuthentication { username, password }) => { + let mut credentials_store = headers + .try_get_webhook_header("Authorization") + .map_err(|_| AuthenticationError::UnauthorizedBasicHttpAuth)? + .split(' '); + + let _ = credentials_store + .next() + .filter(|r#type| *r#type == "Basic") + .ok_or(AuthenticationError::UnauthorizedBasicHttpAuth)?; + + let credentials_as_base64 = credentials_store + .next() + .ok_or(AuthenticationError::UnauthorizedBasicHttpAuth)?; + + let credentials_from_base64_as_bytes = BASE64_STANDARD + .decode(credentials_as_base64.as_bytes()) + .map_err(|_| AuthenticationError::UnauthorizedBasicHttpAuth)?; + + let credentials_separated_with_colon = + String::from_utf8(credentials_from_base64_as_bytes) + .map_err(|_| AuthenticationError::UnauthorizedBasicHttpAuth)?; + + let credentials = credentials_separated_with_colon.split(':').collect_vec(); + + if credentials.len() != 2 { + return Err(AuthenticationError::UnauthorizedBasicHttpAuth); + } + + if credentials.get(0).unwrap() != username + || credentials.get(1).unwrap() != password + { + return Err(AuthenticationError::UnauthorizedBasicHttpAuth); + } + } + } + + Ok(None) + } +} + +#[derive(thiserror::Error, Debug)] +#[allow(unused)] +pub enum AuthenticationError { + #[error("failed to parse timestamp")] + InvalidTimestamp, + + #[error("invalid secret")] + InvalidSecret(#[from] base64::DecodeError), + + #[error("invalid header `{0}`")] + InvalidHeader(String), + + #[error("signature timestamp too old")] + TimestampTooOldError, + + #[error("signature timestamp too far in future")] + FutureTimestampError, + + #[error("missing header {0}")] + MissingHeader(String), + + #[error("signature invalid")] + InvalidSignature, + + #[error("payload invalid")] + InvalidPayload, + + #[error("invalid custom config")] + InvalidCustomConfig, + + #[error("invalid auth header: {0}")] + InvalidAuthHeader(String), + + #[error("invalid api key")] + InvalidApiKey, + + #[error("invalid challenge response: {0}")] + InvalidChallengeResponse(String), + + #[error("")] + UnauthorizedBasicHttpAuth, +} + +impl IntoResponse for AuthenticationError { + fn into_response(self) -> Response { + let (status, error_message) = match &self { + AuthenticationError::InvalidTimestamp + | AuthenticationError::InvalidPayload + | AuthenticationError::InvalidHeader(_) + | AuthenticationError::MissingHeader(_) + | AuthenticationError::TimestampTooOldError + | AuthenticationError::FutureTimestampError + | AuthenticationError::InvalidCustomConfig + | AuthenticationError::InvalidChallengeResponse(_) => { + (StatusCode::BAD_REQUEST, self.to_string()) + } + + AuthenticationError::InvalidSecret(_) + | AuthenticationError::InvalidSignature + | AuthenticationError::InvalidAuthHeader(_) => { + (StatusCode::UNAUTHORIZED, self.to_string()) + } + AuthenticationError::UnauthorizedBasicHttpAuth => { + return ( + StatusCode::UNAUTHORIZED, + [(header::WWW_AUTHENTICATE, r#"Basic realm="Restricted Area""#)], + "Unauthorized", + ) + .into_response() + } + AuthenticationError::InvalidApiKey => { + return (StatusCode::UNAUTHORIZED, "Unauthorized").into_response() + } + }; + + let body = json!({ "error": error_message }); + + let mut headers = HeaderMap::new(); + headers.insert("Content-Type", HeaderValue::from_static("application/json")); + + (status, headers, body.to_string()).into_response() + } +} diff --git a/backend/windmill-api/src/http_triggers.rs b/backend/windmill-api/src/http_triggers.rs index 9432fb0e7e..fa26406a13 100644 --- a/backend/windmill-api/src/http_triggers.rs +++ b/backend/windmill-api/src/http_triggers.rs @@ -1,5 +1,8 @@ +use crate::http_trigger_auth::{self}; #[cfg(feature = "parquet")] use crate::job_helpers_ee::get_workspace_s3_resource; +use crate::resources::try_get_resource_from_db_as; +use crate::utils::non_empty_str; use crate::{ args::try_from_request_body, auth::{AuthCache, OptTokened}, @@ -10,6 +13,7 @@ use crate::{ }, users::fetch_api_authed, }; +use axum::response::Response; use axum::{ extract::{Path, Query, Request}, response::IntoResponse, @@ -26,6 +30,7 @@ use std::borrow::Cow; use std::{collections::HashMap, sync::Arc}; use tower_http::cors::CorsLayer; use windmill_audit::{audit_ee::audit_log, ActionKind}; +use windmill_common::error::Error; #[cfg(feature = "parquet")] use windmill_common::s3_helpers::build_object_store_client; use windmill_common::{ @@ -101,6 +106,18 @@ impl TryFrom<&http::Method> for HttpMethod { } } +#[derive(sqlx::Type, Serialize, Deserialize, Debug, PartialEq, Clone, Copy)] +#[sqlx(type_name = "AUTHENTICATION_METHOD", rename_all = "snake_case")] +#[serde(rename_all(serialize = "snake_case", deserialize = "snake_case"))] +pub enum AuthenticationMethod { + None, + Windmill, + ApiKey, + BasicHttp, + CustomScript, + Signature, +} + #[derive(Debug, Deserialize)] struct NewTrigger { path: String, @@ -108,9 +125,10 @@ struct NewTrigger { script_path: String, is_flow: bool, is_async: bool, - requires_auth: bool, - http_method: HttpMethod, + authentication_resource_path: Option, + authentication_method: AuthenticationMethod, static_asset_config: Option>, + http_method: HttpMethod, workspaced_route: Option, is_static_website: bool, wrap_body: Option, @@ -130,11 +148,12 @@ pub struct HttpTrigger { pub edited_at: chrono::DateTime, pub extra_perms: serde_json::Value, pub is_async: bool, - pub requires_auth: bool, + pub authentication_method: AuthenticationMethod, pub http_method: HttpMethod, #[serde(skip_serializing_if = "Option::is_none")] pub static_asset_config: Option>, pub is_static_website: bool, + pub authentication_resource_path: Option, pub workspaced_route: bool, pub wrap_body: bool, pub raw_string: bool, @@ -147,7 +166,9 @@ struct EditTrigger { script_path: String, is_flow: bool, is_async: bool, - requires_auth: bool, + authentication_method: AuthenticationMethod, + #[serde(deserialize_with = "non_empty_str")] + authentication_resource_path: Option, http_method: HttpMethod, static_asset_config: Option>, workspaced_route: Option, @@ -190,9 +211,10 @@ async fn list_triggers( "edited_at", "extra_perms", "is_async", - "requires_auth", + "authentication_method", "static_asset_config", "is_static_website", + "authentication_resource_path", ]) .order_by("edited_at", true) .and_where("workspace_id = ?".bind(&w_id)) @@ -243,9 +265,10 @@ async fn get_trigger( edited_at, extra_perms, is_async, - requires_auth, + authentication_method as "authentication_method: _", static_asset_config as "static_asset_config: _", is_static_website, + authentication_resource_path, wrap_body, raw_string FROM @@ -266,6 +289,23 @@ async fn get_trigger( Ok(Json(trigger)) } +fn validate_authentication_method( + authentication_method: AuthenticationMethod, + raw_string: Option, +) -> error::Result<()> { + match (authentication_method, raw_string) { + (AuthenticationMethod::CustomScript, raw) if !raw.unwrap_or(false) == true => { + return Err(Error::BadRequest( + "To use custom script authentication, please enable the raw body option." + .to_string(), + )); + } + _ => {} + } + + Ok(()) +} + async fn create_trigger( authed: ApiAuthed, Extension(db): Extension, @@ -279,6 +319,8 @@ async fn create_trigger( return Err(error::Error::BadRequest("Invalid route path".to_string())); } + validate_authentication_method(ct.authentication_method, ct.raw_string)?; + // route path key is extracted from the route path to check for uniqueness // it replaces /?:{key} with :key // it will also remove the leading / if present, not an issue as we only allow : after slashes @@ -313,12 +355,13 @@ async fn create_trigger( route_path, route_path_key, workspaced_route, + authentication_resource_path, wrap_body, raw_string, script_path, is_flow, is_async, - requires_auth, + authentication_method, http_method, static_asset_config, edited_by, @@ -327,20 +370,21 @@ async fn create_trigger( is_static_website ) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, now(), $16 + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, now(), $17 ) "#, w_id, ct.path, ct.route_path, &route_path_key, - ct.workspaced_route.unwrap_or(false), + ct.workspaced_route, + ct.authentication_resource_path, ct.wrap_body.unwrap_or(false), ct.raw_string.unwrap_or(false), ct.script_path, ct.is_flow, ct.is_async, - ct.requires_auth, + ct.authentication_method as _, ct.http_method as _, ct.static_asset_config as _, &authed.username, @@ -380,6 +424,8 @@ async fn update_trigger( )); } + validate_authentication_method(ct.authentication_method, ct.raw_string)?; + let mut tx; if authed.is_admin { let Some(route_path) = ct.route_path else { @@ -417,29 +463,31 @@ async fn update_trigger( SET route_path = $1, route_path_key = $2, - workspaced_route = $3, + workspaced_route = $3, wrap_body = $4, raw_string = $5, - script_path = $6, - path = $7, - is_flow = $8, - http_method = $9, - static_asset_config = $10, - edited_by = $11, - email = $12, - is_async = $13, - requires_auth = $14, + authentication_resource_path = $6, + script_path = $7, + path = $8, + is_flow = $9, + http_method = $10, + static_asset_config = $11, + edited_by = $12, + email = $13, + is_async = $14, + authentication_method = $15, edited_at = now(), - is_static_website = $15 + is_static_website = $16 WHERE - workspace_id = $16 AND - path = $17 + workspace_id = $17 AND + path = $18 "#, route_path, &route_path_key, ct.workspaced_route, ct.wrap_body, ct.raw_string, + ct.authentication_resource_path, ct.script_path, ct.path, ct.is_flow, @@ -448,7 +496,7 @@ async fn update_trigger( &authed.username, &authed.email, ct.is_async, - ct.requires_auth, + ct.authentication_method as _, ct.is_static_website, w_id, path, @@ -462,21 +510,29 @@ async fn update_trigger( UPDATE http_trigger SET - script_path = $1, - path = $2, - is_flow = $3, - http_method = $4, - static_asset_config = $5, - edited_by = $6, - email = $7, - is_async = $8, - requires_auth = $9, + workspaced_route = $1, + wrap_body = $2, + raw_string = $3, + authentication_resource_path = $4, + script_path = $5, + path = $6, + is_flow = $7, + http_method = $8, + static_asset_config = $9, + edited_by = $10, + email = $11, + is_async = $12, + authentication_method = $13, edited_at = now(), - is_static_website = $10 + is_static_website = $14 WHERE - workspace_id = $11 AND - path = $12 + workspace_id = $15 AND + path = $16 "#, + ct.workspaced_route, + ct.wrap_body, + ct.raw_string, + ct.authentication_resource_path, ct.script_path, ct.path, ct.is_flow, @@ -485,7 +541,7 @@ async fn update_trigger( &authed.username, &authed.email, ct.is_async, - ct.requires_auth, + ct.authentication_method as _, ct.is_static_website, w_id, path, @@ -652,6 +708,7 @@ async fn exists_route( Ok(Json(exists)) } +#[derive(Debug, Deserialize)] struct TriggerRoute { path: String, script_path: String, @@ -659,11 +716,12 @@ struct TriggerRoute { route_path: String, workspace_id: String, is_async: bool, - requires_auth: bool, + authentication_method: AuthenticationMethod, edited_by: String, email: String, static_asset_config: Option>, is_static_website: bool, + authentication_resource_path: Option, workspaced_route: bool, wrap_body: bool, raw_string: bool, @@ -694,14 +752,15 @@ async fn get_http_route_trigger( route_path, workspace_id, is_async, - requires_auth, + authentication_method AS "authentication_method: _", edited_by, email, static_asset_config AS "static_asset_config: _", wrap_body, raw_string, workspaced_route, - is_static_website + is_static_website, + authentication_resource_path FROM http_trigger WHERE @@ -723,9 +782,10 @@ async fn get_http_route_trigger( script_path, is_flow, route_path, + authentication_resource_path, workspace_id, is_async, - requires_auth, + authentication_method AS "authentication_method: _", edited_by, email, static_asset_config AS "static_asset_config: _", @@ -787,7 +847,7 @@ async fn get_http_route_trigger( .map(|(k, v)| (k.to_string(), v.to_string())) .collect(); - let username_override = if trigger.requires_auth { + let username_override = if let AuthenticationMethod::Windmill = trigger.authentication_method { let opt_authed = if let Some(token) = token { auth_cache .get_authed(Some(trigger.workspace_id.clone()), token) @@ -878,9 +938,9 @@ async fn route_job( method: http::Method, headers: HeaderMap, request: Request, -) -> impl IntoResponse { +) -> Result { let route_path = route_path.to_path().trim_end_matches("/"); - let (trigger, called_path, params, authed) = match get_http_route_trigger( + let (trigger, called_path, params, authed) = get_http_route_trigger( route_path, &auth_cache, token.as_ref(), @@ -889,36 +949,82 @@ async fn route_job( &method, ) .await - { - Ok(trigger) => trigger, - Err(e) => return e.into_response(), - }; + .map_err(|e| e.into_response())?; - let result = try_from_request_body( + let args = try_from_request_body( request, - &db, - Some(trigger.raw_string), + &(), + Some(match trigger.authentication_method { + AuthenticationMethod::CustomScript | AuthenticationMethod::Signature => true, + _ => trigger.raw_string, + }), Some(trigger.wrap_body), ) - .await; + .await + .map_err(|e| e.into_response())?; - let mut args = match result { - Ok(args) => match args - .to_push_args_owned(&authed, &db, &trigger.workspace_id) - .await - { - Ok(args) => args, - Err(e) => return e.into_response(), - }, - Err(e) => return e.into_response(), - }; + let mut args = args + .to_push_args_owned(&authed, &db, &trigger.workspace_id) + .await + .map_err(|e| e.into_response())?; + + match trigger.authentication_method { + AuthenticationMethod::None + | AuthenticationMethod::Windmill + | AuthenticationMethod::CustomScript => {} + _ => { + let resource_path = match trigger.authentication_resource_path { + Some(resource_path) => resource_path, + None => { + return Err(Error::BadRequest( + "Missing authentication resource path".to_string(), + ) + .into_response()) + } + }; + + let authentication_method = + try_get_resource_from_db_as::( + authed.clone(), + Some(user_db.clone()), + &db, + &resource_path, + &trigger.workspace_id, + ) + .await + .map_err(|e| e.into_response())?; + + let raw_payload = args + .extra + .as_ref() + .and_then(|extra| { + extra + .get("raw_string") + .and_then(|value| Some(value.to_string())) + .and_then(|raw_payload| Some(serde_json::from_str::(&raw_payload))) + }) + .transpose() + .map_err(|e| { + windmill_common::error::Error::SerdeJson { location: e.to_string(), error: e } + .into_response() + })?; + + let response = authentication_method + .authenticate_http_request(&headers, raw_payload.as_ref()) + .map_err(|e| e.into_response())?; + + if let Some(response) = response { + return Ok(response); + } + } + } #[cfg(not(feature = "parquet"))] if trigger.static_asset_config.is_some() { - return error::Error::internal_err( + return Err(error::Error::internal_err( "Static asset configuration is not supported in this build".to_string(), ) - .into_response(); + .into_response()); } #[cfg(feature = "parquet")] @@ -1018,9 +1124,9 @@ async fn route_job( }; match build_static_response_f.await { Ok((status, headers, body_stream)) => { - return (status, headers, body_stream).into_response() + return Ok((status, headers, body_stream).into_response()) } - Err(e) => return e.into_response(), + Err(e) => return Err(e.into_response()), } } @@ -1041,7 +1147,7 @@ async fn route_job( let run_query = RunJobQuery::default(); - if trigger.is_flow { + let response = if trigger.is_flow { if trigger.is_async { run_flow_by_path_inner( authed, @@ -1097,5 +1203,7 @@ async fn route_job( .await .into_response() } - } + }; + + Ok(response) } diff --git a/backend/windmill-api/src/job_helpers_ee.rs b/backend/windmill-api/src/job_helpers_ee.rs index b35f40d661..4e14d16c5f 100644 --- a/backend/windmill-api/src/job_helpers_ee.rs +++ b/backend/windmill-api/src/job_helpers_ee.rs @@ -30,12 +30,20 @@ pub struct UploadFileResponse { #[derive(Deserialize)] pub struct LoadImagePreviewQuery { + #[allow(dead_code)] pub file_key: String, + #[allow(dead_code)] + pub storage: Option, } #[derive(Deserialize)] pub struct DownloadFileQuery { + #[allow(dead_code)] pub file_key: String, + #[allow(dead_code)] + pub storage: Option, + #[allow(dead_code)] + pub s3_resource_path: Option, } pub fn workspaced_service() -> Router { @@ -111,16 +119,3 @@ pub async fn download_s3_file_internal( "Not implemented in Windmill's Open Source repository".to_string(), )) } - -#[cfg(feature = "parquet")] -pub async fn load_image_preview_internal( - _authed: ApiAuthed, - _db: &DB, - _token: &str, - _w_id: &str, - _query: LoadImagePreviewQuery, -) -> error::Result { - Err(error::Error::internal_err( - "Not implemented in Windmill's Open Source repository".to_string(), - )) -} diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 15da4f29c8..be015f5929 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -8,7 +8,9 @@ use axum::body::Body; use axum::http::HeaderValue; -use futures::TryFutureExt; +#[cfg(feature = "deno_core")] +use deno_core::{op2, serde_v8, v8, JsRuntime, OpState}; +use futures::{StreamExt, TryFutureExt}; use http::{HeaderMap, HeaderName}; use itertools::Itertools; use quick_cache::sync::Cache; @@ -26,7 +28,7 @@ use tower::ServiceBuilder; use windmill_common::error::JsonResult; use windmill_common::flow_status::{JobResult, RestartedFrom}; use windmill_common::jobs::{format_completed_job_result, format_result, ENTRYPOINT_OVERRIDE}; -use windmill_common::worker::{CLOUD_HOSTED, TMP_DIR}; +use windmill_common::worker::{Connection, CLOUD_HOSTED, TMP_DIR}; use windmill_common::scripts::PREVIEW_IS_CODEBASE_HASH; use windmill_common::variables::get_workspace_key; @@ -140,6 +142,13 @@ pub fn workspaced_service() -> Router { .layer(cors.clone()) .layer(ce_headers.clone()), ) + .route( + "/run/batch_rerun_jobs", + post(batch_rerun_jobs) + .head(|| async { "" }) + .layer(cors.clone()) + .layer(ce_headers.clone()), + ) .route( "/run/workflow_as_code/:job_id/:entrypoint", post(run_workflow_as_code) @@ -203,6 +212,13 @@ pub fn workspaced_service() -> Router { "/list", get(list_jobs).layer(Extension(api_list_jobs_query_duration)), ) + .route( + "/list_selected_job_groups", + // We use post because sending a huge array as a query param can produce + // URLs that may be too long + post(list_selected_job_groups), + ) + .route("/list_filtered_uuids", get(list_filtered_job_uuids)) .route("/queue/list", get(list_queue_jobs)) .route("/queue/count", get(count_queue_jobs)) .route("/queue/list_filtered_uuids", get(list_filtered_uuids)) @@ -372,7 +388,6 @@ async fn cancel_job_api( email: "anonymous".to_string(), }, }; - let (mut tx, job_option) = tokio::time::timeout( std::time::Duration::from_secs(120), windmill_queue::cancel_job( @@ -587,7 +602,9 @@ async fn get_flow_job_debug_info( Extension(db): Extension, Path((w_id, id)): Path<(String, Uuid)>, ) -> error::Result { - let job = GetQuery::new().fetch_queued(&db, id, &w_id).await?; + let job = GetQuery::new() + .fetch_queued((&db).into(), id, &w_id) + .await?; if let Some(job) = job { let is_flow = job.is_flow(); if job.is_flow_step || !is_flow { @@ -644,6 +661,48 @@ async fn get_flow_job_debug_info( } } +async fn list_selected_job_groups( + authed: ApiAuthed, + Extension(user_db): Extension, + Path(w_id): Path, + Json(uuids): Json>, +) -> error::Result { + let mut tx = user_db.begin(&authed).await?; + + let results = sqlx::query_scalar!( + r#"SELECT jsonb_build_object( + 'kind', jb.kind, + 'script_path', jb.runnable_path, + 'latest_schema', COALESCE( + (SELECT DISTINCT ON (s.path) s.schema FROM script s WHERE s.path = jb.runnable_path AND jb.kind = 'script' ORDER BY s.path, s.created_at DESC), + (SELECT flow_version.schema FROM flow LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] WHERE flow.path = jb.runnable_path AND jb.kind = 'flow') + ), + 'schemas', ARRAY( + SELECT jsonb_build_object( + 'script_hash', LPAD(TO_HEX(COALESCE(s.hash, f.id)), 16, '0'), + 'job_ids', ARRAY_AGG(DISTINCT j.id), + 'schema', ANY_VALUE(COALESCE(s.schema, f.schema)) + ) FROM v2_job j + LEFT JOIN script s ON s.hash = j.runnable_id AND j.kind = 'script' + LEFT JOIN flow_version f ON f.id = j.runnable_id AND j.kind = 'flow' + WHERE j.id = ANY(ARRAY_AGG(jb.id)) + GROUP BY COALESCE(s.hash, f.id) + ) + ) FROM v2_job jb + WHERE (jb.kind = 'flow' OR jb.kind = 'script') + AND jb.workspace_id = $1 AND jb.id = ANY($2) + GROUP BY jb.kind, jb.runnable_path"#, + &w_id, + &uuids + ) + .fetch_all(&mut *tx) + .await?; + + tx.commit().await?; + + Ok(Json(results).into_response()) +} + #[derive(Deserialize)] struct GetJobQuery { pub no_logs: Option, @@ -926,8 +985,9 @@ impl<'a> GetQuery<'a> { // Try to fetch the code from the cache, fallback to the preview code. // NOTE: This could check for the job kinds instead of the `or_else` but it's not // necessary as `fetch_script` return early if the job kind is not a preview one. - cache::job::fetch_script(db, kind, hash) - .or_else(|_| cache::job::fetch_preview_script(db, &id, raw_lock, raw_code)) + let conn = Connection::from(db.clone()); + cache::job::fetch_script(db.clone(), kind, hash) + .or_else(|_| cache::job::fetch_preview_script(&conn, &id, raw_lock, raw_code)) .await .ok() .inspect(|data| { @@ -956,7 +1016,7 @@ impl<'a> GetQuery<'a> { self.check_auth(job.as_ref().map(|job| job.created_by.as_str()))?; if let Some(job) = job.as_mut() { - self.resolve_raw_values(db, job.id, job.job_kind, job.script_hash, job) + self.resolve_raw_values(&db, job.id, job.job_kind, job.script_hash, job) .await; } if self.with_flow { @@ -993,12 +1053,14 @@ impl<'a> GetQuery<'a> { self.resolve_raw_values(db, job.id, job.job_kind, job.script_hash, job) .await; } + if self.with_flow { cjob = resolve_maybe_value(db, workspace_id, self.with_code, cjob, |job| { job.raw_flow.as_mut() }) .await?; } + if let Some(mut cjob) = cjob { cjob.inner = format_completed_job_result(cjob.inner); return Ok(Some(cjob)); @@ -1008,7 +1070,7 @@ impl<'a> GetQuery<'a> { async fn fetch(self, db: &DB, job_id: Uuid, workspace_id: &str) -> error::Result { let cjob = self - .fetch_completed(db, job_id, workspace_id) + .fetch_completed(db.into(), job_id, workspace_id) .await? .map(Job::CompletedJob); @@ -1016,7 +1078,7 @@ impl<'a> GetQuery<'a> { Some(cjob) => Ok(cjob), None => { let job_maybe = self - .fetch_queued(db, job_id, workspace_id) + .fetch_queued(db.into(), job_id, workspace_id) .await? .map(Job::QueuedJob); // potential race condition here, if the job was in queue and completed right after the fetch completed, so we need to check one last time @@ -1024,7 +1086,7 @@ impl<'a> GetQuery<'a> { return Ok(job); } else { let cjob2 = self - .fetch_completed(db, job_id, workspace_id) + .fetch_completed(db.into(), job_id, workspace_id) .await? .map(Job::CompletedJob); not_found_if_none(cjob2, "Job", job_id.to_string()) @@ -1374,6 +1436,7 @@ pub struct ListQueueQuery { pub has_null_parent: Option, pub is_not_schedule: Option, pub concurrency_key: Option, + pub allow_wildcards: Option, } impl From for ListQueueQuery { @@ -1404,6 +1467,7 @@ impl From for ListQueueQuery { has_null_parent: lcq.has_null_parent, is_not_schedule: lcq.is_not_schedule, concurrency_key: lcq.concurrency_key, + allow_wildcards: lcq.allow_wildcards, } } } @@ -1427,7 +1491,11 @@ pub fn filter_list_queue_query( } if let Some(w) = &lq.worker { - sqlb.and_where_eq("v2_job_queue.worker", "?".bind(w)); + if lq.allow_wildcards.unwrap_or(false) { + sqlb.and_where_like_left("v2_job_queue.worker", w.replace("*", "%")); + } else { + sqlb.and_where_eq("v2_job_queue.worker", "?".bind(w)); + } } if let Some(ps) = &lq.script_path_start { @@ -1447,8 +1515,13 @@ pub fn filter_list_queue_query( sqlb.and_where_eq("created_by", "?".bind(cb)); } if let Some(t) = &lq.tag { - sqlb.and_where_eq("tag", "?".bind(t)); + if lq.allow_wildcards.unwrap_or(false) { + sqlb.and_where_like_left("v2_job.tag", t.replace("*", "%")); + } else { + sqlb.and_where_eq("v2_job.tag", "?".bind(t)); + } } + if let Some(r) = &lq.running { sqlb.and_where_eq("running", &r); } @@ -1539,7 +1612,10 @@ pub fn list_queue_jobs_query( .clone(); if let Some(tags) = tags { - sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::>()); + sqlb.and_where_in( + "v2_job.tag", + &tags.iter().map(|x| quote(x)).collect::>(), + ); } filter_list_queue_query(sqlb, lq, w_id, join_outstanding_wait_times) @@ -1727,6 +1803,37 @@ async fn cancel_selection( cancel_jobs(jobs_to_cancel, &db, authed.username.as_str(), w_id.as_str()).await } +async fn list_filtered_job_uuids( + authed: ApiAuthed, + Extension(db): Extension, + Path(w_id): Path, + Query(lq): Query, +) -> error::JsonResult> { + require_admin(authed.is_admin, &authed.username)?; + check_scopes(&authed, || format!("jobs:listjobs"))?; + + let mut sqlb = list_completed_jobs_query( + w_id.as_str(), + None, + 0, + &lq, + &["v2_job.id"], + false, + get_scope_tags(&authed), + ); + let sqlb2 = list_queue_jobs_query( + w_id.as_str(), + &lq.into(), + &["v2_job.id"], + Pagination { page: None, per_page: None }, + false, + get_scope_tags(&authed), + ); + let query = sqlb.union_all(sqlb2.subquery()?).subquery()?; + let ids = sqlx::query_scalar(query.as_str()).fetch_all(&db).await?; + Ok(Json(ids)) +} + async fn list_filtered_uuids( authed: ApiAuthed, Extension(db): Extension, @@ -1746,7 +1853,10 @@ async fn list_filtered_uuids( .or_where_is_null("v2_job.trigger_kind"); if let Some(tags) = get_scope_tags(&authed) { - sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::>()); + sqlb.and_where_in( + "v2_job.tag", + &tags.iter().map(|x| quote(x)).collect::>(), + ); } sqlb = filter_list_queue_query(sqlb, &lq, w_id.as_str(), false); @@ -1829,7 +1939,7 @@ async fn count_completed_jobs_detail( if let Some(tags) = query.tags { sqlb.and_where_in( - "tag", + "v2_job.tag", &tags .split(",") .map(|t| format!("'{}'", t)) @@ -1880,7 +1990,7 @@ async fn list_jobs( let sqlc = if lq.running.is_none() { Some(list_completed_jobs_query( &w_id, - per_page + offset, + Some(per_page + offset), 0, &ListCompletedQuery { order_desc: Some(true), ..lqc }, UnifiedJob::completed_job_fields(), @@ -1919,7 +2029,9 @@ async fn list_jobs( } else { if sqlc.is_none() { return Err(error::Error::BadRequest( - "cannot specify success, label, created_or_started_before, or started_before with running".to_string(), + "cannot specify success, label, created_or_started_before, or starte + d_before with running" + .to_string(), )); } sqlc.unwrap().limit(per_page).offset(offset).query()? @@ -3131,6 +3243,268 @@ pub async fn check_license_key_valid() -> error::Result<()> { Ok(()) } +use windmill_common::flows::InputTransform; + +#[derive(Deserialize)] +struct BatchReRunJobsBodyArgs { + job_ids: Vec, + script_options_by_path: HashMap, + flow_options_by_path: HashMap, +} + +#[derive(Deserialize)] +struct BatchReRunOptions { + input_transforms: Option>, + use_latest_version: Option, +} + +#[derive(sqlx::FromRow, Serialize, Clone)] +struct BatchReRunQueryReturnType { + id: Uuid, + kind: JobKind, + script_path: String, + script_hash: ScriptHash, + input: serde_json::Value, + scheduled_for: chrono::DateTime, + #[serde(skip_serializing_if = "Option::is_none")] + schema: Option, +} + +#[cfg(feature = "deno_core")] +#[op2] +#[string] +fn get_deno_core_job_value(state: &mut OpState) -> Option { + let obj = state.borrow::(); + let str = serde_json::to_string(&obj).ok()?; + Some(str) +} + +#[cfg(feature = "deno_core")] +async fn batch_rerun_compute_js_expression( + expr: String, + job: BatchReRunQueryReturnType, +) -> error::Result> { + let ext = deno_core::Extension { + name: "batch_rerun_arg_transform_ext", + ops: vec![get_deno_core_job_value()].into(), + ..Default::default() + }; + let mut isolate = + JsRuntime::new(deno_core::RuntimeOptions { extensions: vec![ext], ..Default::default() }); + + { + let op_state = isolate.op_state(); + let mut op_state = op_state.borrow_mut(); + op_state.put(BatchReRunQueryReturnType { schema: None, ..job }); + } + isolate + .execute_script( + "", + "let job = JSON.parse(Deno.core.ops.get_deno_core_job_value());", + ) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + + // Run user expr + let result = isolate + .execute_script("", expr) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + let mut scope = isolate.handle_scope(); + let result = v8::Local::new(&mut scope, result); + let result: serde_json::Value = + serde_v8::from_v8(&mut scope, result).map_err(|e| Error::ExecutionErr(e.to_string()))?; + let result = JsonRawValue::from_string(result.to_string())?; + Ok(result) +} + +async fn batch_rerun_jobs( + authed: ApiAuthed, + Extension(db): Extension, + Extension(user_db): Extension, + Path(w_id): Path, + Json(body): Json, +) -> Response { + let stream = batch_rerun_jobs_inner(authed, db, user_db, w_id, body); + + let body = axum::body::Body::from_stream(stream.map(Result::<_, std::convert::Infallible>::Ok)); + + Response::builder() + .status(201) + .header("Content-Type", "text/event-stream") + .header("Cache-Control", "no-cache") + .body(body) + .unwrap() +} + +fn batch_rerun_jobs_inner( + authed: ApiAuthed, + db: DB, + user_db: UserDB, + w_id: String, + body: BatchReRunJobsBodyArgs, +) -> impl futures::Stream { + let (tx, rx) = tokio::sync::mpsc::channel(10); + tokio::spawn(async move { + let mut job_stream = sqlx::query_as!( + BatchReRunQueryReturnType, + r#"SELECT + j.id, + j.kind AS "kind: _", + COALESCE(s.path, f.path) AS "script_path!", + COALESCE(s.hash, f.id) AS "script_hash!: _", + COALESCE(jc.started_at, jq.scheduled_for, make_date(1970, 1, 1)) AS "scheduled_for!: _", + args AS input, + COALESCE(s.schema, f.schema) AS "schema: _" + FROM v2_job j + LEFT JOIN script s ON j.runnable_id = s.hash AND j.kind = 'script' + LEFT JOIN flow_version f ON j.runnable_id = f.id AND j.runnable_path = f.path AND j.kind = 'flow' + LEFT JOIN v2_job_completed jc ON jc.id = j.id + LEFT JOIN v2_job_queue jq ON jq.id = j.id + WHERE j.id = ANY($1) + AND j.workspace_id = $2 + AND COALESCE(s.hash, f.id) IS NOT NULL + AND COALESCE(s.path, f.path) IS NOT NULL"#, + &body.job_ids, + w_id + ).fetch(&db); + while let Some(Ok(job)) = job_stream.next().await { + let job_result = + batch_rerun_handle_job(&job, &authed, &db, &user_db, &w_id, &body).await; + let send_to_stream_result = tx + .send(match job_result { + Ok(uuid) => format!("{}\n", uuid), + Err(err) => format!("Error: {}\n", err.to_string()), + }) + .await; + match send_to_stream_result { + Ok(_) => {} + Err(e) => tracing::error!("Couldn't re-run job {}: {}", job.id, e.to_string()), + } + } + }); + tokio_stream::wrappers::ReceiverStream::new(rx) +} + +async fn batch_rerun_handle_job( + job: &BatchReRunQueryReturnType, + authed: &ApiAuthed, + db: &DB, + user_db: &UserDB, + w_id: &String, + body: &BatchReRunJobsBodyArgs, +) -> error::Result { + let options = if matches!(job.kind, JobKind::Script) { + &body.script_options_by_path + } else { + &body.flow_options_by_path + } + .get(&job.script_path); + + let mut args: HashMap> = serde_json::from_value(job.input.clone())?; + let use_latest_version = options.and_then(|o| o.use_latest_version).unwrap_or(false); + let input_transforms = options + .and_then(|o| o.input_transforms.as_ref()) + .map(|t| t.iter()) + .into_iter() + .flatten(); + + let latest_schema; + let schema = if use_latest_version { + latest_schema = sqlx::query_scalar!( + r#"SELECT COALESCE( + (SELECT DISTINCT ON (s.path) s.schema FROM script s WHERE s.path = jb.runnable_path AND jb.kind = 'script' ORDER BY s.path, s.created_at DESC), + (SELECT flow_version.schema FROM flow LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] WHERE flow.path = jb.runnable_path AND jb.kind = 'flow') + ) FROM v2_job jb + WHERE jb.id = $1 AND jb.workspace_id = $2 + GROUP BY jb.kind, jb.runnable_path"#, + &job.id, + &w_id + ).fetch_optional(db).await?.flatten(); + latest_schema.as_ref() + } else { + job.schema.as_ref() + }; + let schema = schema + .and_then(serde_json::Value::as_object) + .and_then(|s| s.get("properties")) + .and_then(serde_json::Value::as_object); + for (property_name, transform) in input_transforms { + let schema_has_key = schema + .map(|s| s.contains_key(property_name)) + .unwrap_or(false); + if !schema_has_key { + continue; + } + match transform { + InputTransform::Static { value } => { + args.insert(property_name.clone(), value.clone()); + } + InputTransform::Javascript { expr } => { + #[cfg(not(feature = "deno_core"))] + tracing::error!("deno_core feature is not activated, cannot evaluate: {expr}"); + #[cfg(feature = "deno_core")] + args.insert( + property_name.clone(), + batch_rerun_compute_js_expression(expr.clone(), job.clone()).await?, + ); + } + } + } + + // Call appropriate function to push job to queue + match job.kind { + JobKind::Flow => { + let result = run_flow_by_path_inner( + authed.clone(), + db.clone(), + user_db.clone(), + w_id.clone(), + StripPath(job.script_path.clone()), + RunJobQuery { ..Default::default() }, + PushArgsOwned { extra: None, args }, + None, + ) + .await; + if let Ok((_, uuid)) = result { + return Ok(uuid); + } + } + JobKind::Script => { + let result = if use_latest_version { + run_script_by_path_inner( + authed.clone(), + db.clone(), + user_db.clone(), + w_id.clone(), + StripPath(job.script_path.clone()), + RunJobQuery { ..Default::default() }, + PushArgsOwned { extra: None, args }, + None, + ) + .await + } else { + run_job_by_hash_inner( + authed.clone(), + db.clone(), + user_db.clone(), + w_id.clone(), + job.script_hash, + RunJobQuery { ..Default::default() }, + PushArgsOwned { extra: None, args }, + None, + ) + .await + }; + if let Ok((_, uuid)) = result { + return Ok(uuid); + } + } + _ => {} + } + Err(error::Error::ExecutionErr( + format!("Couldn't re-run job {}", job.id).to_string(), + )) +} + pub async fn run_flow_by_path( authed: ApiAuthed, Extension(db): Extension, @@ -5074,6 +5448,21 @@ async fn add_batch_jobs( .execute(&mut *tx) .await?; + sqlx::query!( + "INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) + SELECT unnest($1::uuid[]), $2, $3, $4, $5, $6, $7, $8", + &uuids, + authed.email, + authed.username, + authed.is_admin, + authed.is_operator, + &[], + &[], + w_id, + ) + .execute(&mut *tx) + .await?; + if let Some(flow_status) = flow_status { sqlx::query!( "INSERT INTO v2_job_status (id, flow_status) @@ -5440,14 +5829,27 @@ pub fn filter_list_completed_query( } if let Some(label) = &lq.label { - let mut wh = format!("result->'wm_labels' ? "); - wh.push_str(&format!("'{}'", &label.replace("'", "''"))); - sqlb.and_where("result ? 'wm_labels'"); - sqlb.and_where(&wh); + if lq.allow_wildcards.unwrap_or(false) { + let wh = format!( + "EXISTS (SELECT 1 FROM jsonb_array_elements_text(result->'wm_labels') label WHERE label LIKE '{}')", + &label.replace("*", "%").replace("'", "''") + ); + sqlb.and_where("result ? 'wm_labels'"); + sqlb.and_where(&wh); + } else { + let mut wh = format!("result->'wm_labels' ? "); + wh.push_str(&format!("'{}'", &label.replace("'", "''"))); + sqlb.and_where("result ? 'wm_labels'"); + sqlb.and_where(&wh); + } } if let Some(worker) = &lq.worker { - sqlb.and_where_eq("v2_job_completed.worker", "?".bind(worker)); + if lq.allow_wildcards.unwrap_or(false) { + sqlb.and_where_like_left("v2_job_completed.worker", worker.replace("*", "%")); + } else { + sqlb.and_where_eq("v2_job_completed.worker", "?".bind(worker)); + } } if w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) { @@ -5469,8 +5871,13 @@ pub fn filter_list_completed_query( sqlb.and_where_eq("runnable_id", "?".bind(h)); } if let Some(t) = &lq.tag { - sqlb.and_where_eq("tag", "?".bind(t)); + if lq.allow_wildcards.unwrap_or(false) { + sqlb.and_where_like_left("v2_job.tag", t.replace("*", "%")); + } else { + sqlb.and_where_eq("v2_job.tag", "?".bind(t)); + } } + if let Some(cb) = &lq.created_by { sqlb.and_where_eq("created_by", "?".bind(cb)); } @@ -5555,7 +5962,7 @@ pub fn filter_list_completed_query( pub fn list_completed_jobs_query( w_id: &str, - per_page: usize, + per_page: Option, offset: usize, lq: &ListCompletedQuery, fields: &[&str], @@ -5566,11 +5973,16 @@ pub fn list_completed_jobs_query( .fields(fields) .order_by("v2_job.created_at", lq.order_desc.unwrap_or(true)) .offset(offset) - .limit(per_page) .clone(); + if let Some(per_page) = per_page { + sqlb.limit(per_page); + } if let Some(tags) = tags { - sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::>()); + sqlb.and_where_in( + "v2_job.tag", + &tags.iter().map(|x| quote(x)).collect::>(), + ); } filter_list_completed_query(sqlb, lq, w_id, join_outstanding_wait_times) @@ -5609,6 +6021,7 @@ pub struct ListCompletedQuery { pub is_not_schedule: Option, pub concurrency_key: Option, pub worker: Option, + pub allow_wildcards: Option, } async fn list_completed_jobs( @@ -5624,7 +6037,7 @@ async fn list_completed_jobs( let sql = list_completed_jobs_query( &w_id, - per_page, + Some(per_page), offset, &lq, &[ diff --git a/backend/windmill-api/src/lib.rs b/backend/windmill-api/src/lib.rs index 86a42aa8ba..ece80c64b1 100644 --- a/backend/windmill-api/src/lib.rs +++ b/backend/windmill-api/src/lib.rs @@ -25,6 +25,8 @@ use crate::{ webhook_util::WebhookShared, }; +#[cfg(feature = "agent_worker_server")] +use agent_workers_ee::AgentCache; use anyhow::Context; use argon2::Argon2; use axum::extract::DefaultBodyLimit; @@ -56,6 +58,8 @@ use windmill_common::{utils::GIT_VERSION, BASE_URL, INSTANCE_NAME}; use crate::scim_ee::has_scim_token; use windmill_common::error::AppError; +#[cfg(feature = "agent_worker_server")] +mod agent_workers_ee; mod ai; mod apps; pub mod args; @@ -74,6 +78,8 @@ mod folders; mod granular_acls; mod groups; #[cfg(feature = "http_trigger")] +mod http_trigger_auth; +#[cfg(feature = "http_trigger")] mod http_triggers; mod indexer_ee; mod inputs; @@ -83,6 +89,10 @@ mod postgres_triggers; #[cfg(feature = "enterprise")] mod apps_ee; +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +mod gcp_triggers_ee; +#[cfg(feature = "enterprise")] +mod git_sync_ee; #[cfg(feature = "parquet")] mod job_helpers_ee; pub mod job_metrics; @@ -109,7 +119,9 @@ mod slack_approvals; mod smtp_server_ee; #[cfg(all(feature = "enterprise", feature = "sqs_trigger"))] mod sqs_triggers_ee; + mod static_assets; +#[cfg(all(feature = "stripe", feature = "enterprise"))] mod stripe_ee; mod teams_ee; mod tracing_init; @@ -204,10 +216,10 @@ pub async fn run_server( job_index_reader: Option, log_index_reader: Option, addr: SocketAddr, - mut rx: tokio::sync::broadcast::Receiver<()>, + mut killpill_rx: tokio::sync::broadcast::Receiver<()>, port_tx: tokio::sync::oneshot::Sender, server_mode: bool, - #[cfg(feature = "smtp")] base_internal_url: String, + _base_internal_url: String, ) -> anyhow::Result<()> { let user_db = UserDB::new(db.clone()); @@ -241,7 +253,10 @@ pub async fn run_server( .layer(Extension(log_index_reader)) // .layer(Extension(index_writer)) .layer(CookieManagerLayer::new()) - .layer(Extension(WebhookShared::new(rx.resubscribe(), db.clone()))) + .layer(Extension(WebhookShared::new( + killpill_rx.resubscribe(), + db.clone(), + ))) .layer(DefaultBodyLimit::max( REQUEST_SIZE_LIMIT.read().await.clone(), )); @@ -274,7 +289,7 @@ pub async fn run_server( db: db.clone(), user_db: user_db, auth_cache: auth_cache.clone(), - base_internal_url: base_internal_url.clone(), + base_internal_url: _base_internal_url.clone(), }); if let Err(err) = smtp_server.start_listener_thread(addr).await { tracing::error!("Error starting SMTP server: {err:#}"); @@ -335,6 +350,18 @@ pub async fn run_server( } }; + let gcp_triggers_service = { + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + { + gcp_triggers_ee::workspaced_service() + } + + #[cfg(not(all(feature = "enterprise", feature = "gcp_trigger")))] + { + Router::new() + } + }; + let sqs_triggers_service = { #[cfg(all(feature = "enterprise", feature = "sqs_trigger"))] { @@ -380,41 +407,54 @@ pub async fn run_server( if !*CLOUD_HOSTED && server_mode { #[cfg(feature = "websocket")] { - let ws_killpill_rx = rx.resubscribe(); + let ws_killpill_rx = killpill_rx.resubscribe(); websocket_triggers::start_websockets(db.clone(), ws_killpill_rx); } #[cfg(all(feature = "enterprise", feature = "kafka"))] { - let kafka_killpill_rx = rx.resubscribe(); + let kafka_killpill_rx = killpill_rx.resubscribe(); kafka_triggers_ee::start_kafka_consumers(db.clone(), kafka_killpill_rx); } #[cfg(all(feature = "enterprise", feature = "nats"))] { - let nats_killpill_rx = rx.resubscribe(); + let nats_killpill_rx = killpill_rx.resubscribe(); nats_triggers_ee::start_nats_consumers(db.clone(), nats_killpill_rx); } #[cfg(feature = "postgres_trigger")] { - let db_killpill_rx = rx.resubscribe(); + let db_killpill_rx = killpill_rx.resubscribe(); postgres_triggers::start_database(db.clone(), db_killpill_rx); } #[cfg(feature = "mqtt_trigger")] { - let mqtt_killpill_rx = rx.resubscribe(); + let mqtt_killpill_rx = killpill_rx.resubscribe(); mqtt_triggers::start_mqtt_consumer(db.clone(), mqtt_killpill_rx); } #[cfg(all(feature = "enterprise", feature = "sqs_trigger"))] { - let sqs_killpill_rx = rx.resubscribe(); + let sqs_killpill_rx = killpill_rx.resubscribe(); sqs_triggers_ee::start_sqs(db.clone(), sqs_killpill_rx); } + + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + { + let gcp_killpill_rx = killpill_rx.resubscribe(); + gcp_triggers_ee::start_consuming_gcp_pubsub_event(db.clone(), gcp_killpill_rx); + } } + #[cfg(feature = "agent_worker_server")] + let (agent_workers_router, agent_workers_bg_processor, agent_workers_killpill_tx) = + agent_workers_ee::workspaced_service(db.clone(), _base_internal_url.clone()); + + #[cfg(feature = "agent_worker_server")] + let agent_cache = Arc::new(AgentCache::new()); + // build our application with a route let app = Router::new() .nest( @@ -469,6 +509,7 @@ pub async fn run_server( .nest("/nats_triggers", nats_triggers_service) .nest("/mqtt_triggers", mqtt_triggers_service) .nest("/sqs_triggers", sqs_triggers_service) + .nest("/gcp_triggers", gcp_triggers_service) .nest("/postgres_triggers", postgres_triggers_service), ) .nest("/workspaces", workspaces::global_service()) @@ -487,8 +528,29 @@ pub async fn run_server( .nest("/apps", apps::global_service().layer(cors.clone())) .nest("/schedules", schedule::global_service()) .nest("/embeddings", embeddings::global_service()) + .nest("/ai", ai::global_service()) .route_layer(from_extractor::()) .route_layer(from_extractor::()) + .nest("/agent_workers", { + #[cfg(feature = "agent_worker_server")] + { + agent_workers_ee::global_service().layer(Extension(agent_cache.clone())) + } + #[cfg(not(feature = "agent_worker_server"))] + { + Router::new() + } + }) + .nest("/w/:workspace_id/agent_workers", { + #[cfg(feature = "agent_worker_server")] + { + agent_workers_router.layer(Extension(agent_cache.clone())) + } + #[cfg(not(feature = "agent_worker_server"))] + { + Router::new() + } + }) .nest("/jobs", jobs::global_root_service()) .nest( "/srch/w/:workspace_id/index", @@ -544,6 +606,24 @@ pub async fn run_server( "/w/:workspace_id/jobs/slack_approval/:job_id", get(slack_approvals::request_slack_approval), ) + .nest("/w/:workspace_id/github_app", { + #[cfg(feature = "enterprise")] + { + git_sync_ee::workspaced_service() + } + + #[cfg(not(feature = "enterprise"))] + Router::new() + }) + .nest("/github_app", { + #[cfg(feature = "enterprise")] + { + git_sync_ee::global_service() + } + + #[cfg(not(feature = "enterprise"))] + Router::new() + }) .nest( "/w/:workspace_id/resources_u", resources::public_service().layer(cors.clone()), @@ -580,6 +660,20 @@ pub async fn run_server( } .layer(from_extractor::()), ) + .nest( + "/gcp/w/:workspace_id", + { + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + { + gcp_triggers_ee::gcp_push_route_handler() + } + #[cfg(not(all(feature = "enterprise", feature = "gcp_trigger")))] + { + Router::new() + } + } + .layer(from_extractor::()), + ) .route("/version", get(git_v)) .route("/uptodate", get(is_up_to_date)) .route("/ee_license", get(ee_license)) @@ -623,11 +717,22 @@ pub async fn run_server( .expect("Failed to send port"); let server = server.with_graceful_shutdown(async move { - rx.recv().await.ok(); + killpill_rx.recv().await.ok(); + #[cfg(feature = "agent_worker_server")] + if let Err(e) = agent_workers_killpill_tx.kill().await { + tracing::error!("Error killing agent workers: {e:#}"); + } tracing::info!("Graceful shutdown of server"); }); server.await?; + + #[cfg(feature = "agent_worker_server")] + for (i, bg_processor) in agent_workers_bg_processor.into_iter().enumerate() { + tracing::info!("server off. shutting down agent worker bg processor {i}"); + bg_processor.await?; + tracing::info!("agent worker bg processor {i} shut down"); + } Ok(()) } diff --git a/backend/windmill-api/src/postgres_triggers/handler.rs b/backend/windmill-api/src/postgres_triggers/handler.rs index 4c791eeb8b..69fe8604f2 100644 --- a/backend/windmill-api/src/postgres_triggers/handler.rs +++ b/backend/windmill-api/src/postgres_triggers/handler.rs @@ -6,6 +6,7 @@ use std::collections::{ use crate::{ db::{ApiAuthed, DB}, postgres_triggers::mapper::{Mapper, MappingInfo}, + resources::try_get_resource_from_db_as, }; use axum::{ extract::{Path, Query}, @@ -29,9 +30,9 @@ use windmill_common::{ }; use super::{ - create_logical_replication_slot_query, create_publication_query, - drop_logical_replication_slot_query, drop_publication_query, generate_random_string, - get_database_connection, ERROR_PUBLICATION_NAME_NOT_EXISTS, ERROR_REPLICATION_SLOT_NOT_EXISTS, + create_logical_replication_slot_query, create_publication_query, drop_publication_query, + generate_random_string, get_database_connection, get_raw_postgres_connection, + ERROR_PUBLICATION_NAME_NOT_EXISTS, ERROR_REPLICATION_SLOT_NOT_EXISTS, }; use lazy_static::lazy_static; @@ -394,7 +395,7 @@ pub async fn create_postgres_trigger( "Missing replication slot name".to_string(), )); } - (replication_slot_name.unwrap(), publication_name.unwrap()) + (publication_name.unwrap(), replication_slot_name.unwrap(), ) }; let mut tx = user_db.begin(&authed).await?; @@ -628,7 +629,7 @@ pub async fn create_slot( sqlx::query(&query).execute(&mut connection).await?; - Ok(format!("Slot {} created!", name)) + Ok(format!("Replication slot {} created!", name)) } pub async fn drop_slot_name( @@ -638,19 +639,43 @@ pub async fn drop_slot_name( Path((w_id, postgres_resource_path)): Path<(String, String)>, Json(Slot { name }): Json, ) -> Result { - let mut connection = get_database_connection( - authed.clone(), - Some(user_db.clone()), + let database = try_get_resource_from_db_as::( + authed, + Some(user_db), &db, &postgres_resource_path, &w_id, ) .await?; - let query = drop_logical_replication_slot_query(&name); - sqlx::query(&query).execute(&mut connection).await?; + let mut connection = get_raw_postgres_connection(&database).await?; - Ok(format!("Slot name {} deleted!", name)) + let active_pid = sqlx::query_scalar!( + r#"SELECT + active_pid + FROM + pg_replication_slots + WHERE + slot_name = $1 + "#, + &name + ) + .fetch_optional(&mut connection) + .await? + .flatten(); + + if let Some(pid) = active_pid { + sqlx::query("SELECT pg_terminate_backend($1)") + .bind(pid) + .execute(&mut connection) + .await?; + } + sqlx::query("SELECT pg_drop_replication_slot($1)") + .bind(&name) + .execute(&mut connection) + .await?; + + Ok(format!("Replication slot {} deleted!", name)) } #[derive(Debug, Serialize)] struct PublicationName { diff --git a/backend/windmill-api/src/postgres_triggers/mapper.rs b/backend/windmill-api/src/postgres_triggers/mapper.rs index ec3626c7f7..817a2e8cf6 100644 --- a/backend/windmill-api/src/postgres_triggers/mapper.rs +++ b/backend/windmill-api/src/postgres_triggers/mapper.rs @@ -26,8 +26,8 @@ fn postgres_to_typescript_type(postgres_type: Option) -> String { Type::DATE_ARRAY => "Array", Type::TIME => "string", Type::TIME_ARRAY => "Array", - Type::TIMESTAMPTZ | Type::TIMESTAMP => "Date", - Type::TIMESTAMPTZ_ARRAY | Type::TIMESTAMP_ARRAY => "Array", + Type::TIMESTAMPTZ | Type::TIMESTAMP => "string", + Type::TIMESTAMPTZ_ARRAY | Type::TIMESTAMP_ARRAY => "Array", Type::UUID => "string", Type::UUID_ARRAY => "Array", Type::JSON | Type::JSONB | Type::JSON_ARRAY | Type::JSONB_ARRAY => "unknown", diff --git a/backend/windmill-api/src/postgres_triggers/trigger.rs b/backend/windmill-api/src/postgres_triggers/trigger.rs index 2e6727704f..2ba161b268 100644 --- a/backend/windmill-api/src/postgres_triggers/trigger.rs +++ b/backend/windmill-api/src/postgres_triggers/trigger.rs @@ -467,6 +467,7 @@ impl PostgresConfig { let client = PostgresSimpleClient::new(&database).await?; + let publication = client .execute_query(&format!( "SELECT pubname FROM pg_publication WHERE pubname = {}", @@ -605,6 +606,7 @@ async fn listen_to_transactions( } }; + let message = match message { Ok(message) => message, Err(err) => { diff --git a/backend/windmill-api/src/resources.rs b/backend/windmill-api/src/resources.rs index a3f7ee3d20..8a2fab0434 100644 --- a/backend/windmill-api/src/resources.rs +++ b/backend/windmill-api/src/resources.rs @@ -570,7 +570,7 @@ pub async fn transform_json_value<'c>( }; let variables = variables::get_reserved_variables( - db, + &db.into(), workspace, token, &job.email, @@ -599,11 +599,10 @@ pub async fn transform_json_value<'c>( } Value::Object(mut m) => { for (a, b) in m.clone().into_iter() { - m.insert( - a.clone(), + let v = transform_json_value(authed, user_db.clone(), db, workspace, b, job_id, token) - .await?, - ); + .await?; + m.insert(a.clone(), v); } Ok(Value::Object(m)) } @@ -1209,9 +1208,13 @@ async fn update_resource_type( } #[cfg(any( + feature = "http_trigger", feature = "postgres_trigger", feature = "mqtt_trigger", - all(feature = "sqs_trigger", feature = "enterprise") + all( + feature = "enterprise", + any(feature = "sqs_trigger", feature = "gcp_trigger") + ) ))] pub async fn try_get_resource_from_db_as( authed: ApiAuthed, diff --git a/backend/windmill-api/src/schedule.rs b/backend/windmill-api/src/schedule.rs index a397eadf05..90d91c846c 100644 --- a/backend/windmill-api/src/schedule.rs +++ b/backend/windmill-api/src/schedule.rs @@ -29,6 +29,7 @@ use windmill_common::{ error::{Error, JsonResult, Result}, schedule::Schedule, utils::{not_found_if_none, paginate, Pagination, ScheduleType, StripPath}, + worker::to_raw_value, }; use windmill_git_sync::{handle_deployment_metadata, DeployedObject}; use windmill_queue::schedule::push_scheduled_job; @@ -57,6 +58,7 @@ pub struct NewSchedule { pub schedule: String, pub timezone: String, pub summary: Option, + pub description: Option, pub no_flow_overlap: Option, pub script_path: String, pub is_flow: bool, @@ -120,6 +122,12 @@ async fn check_path_conflict<'c>( return Ok(()); } +fn to_json_raw_opt( + value: Option<&serde_json::Value>, +) -> Option>> { + value.map(|v| sqlx::types::Json(to_raw_value(&v))) +} + async fn create_schedule( authed: ApiAuthed, Extension(db): Extension, @@ -159,41 +167,90 @@ async fn create_schedule( check_path_conflict(&mut tx, &w_id, &ns.path).await?; check_flow_conflict(&mut tx, &w_id, &ns.path, ns.is_flow, &ns.script_path).await?; - let schedule = sqlx::query_as::<_, Schedule>( - "INSERT INTO schedule (workspace_id, path, schedule, timezone, edited_by, script_path, \ - is_flow, args, enabled, email, on_failure, on_failure_times, on_failure_exact, \ - on_failure_extra_args, on_recovery, on_recovery_times, on_recovery_extra_args, \ - on_success, on_success_extra_args, \ - ws_error_handler_muted, retry, summary, no_flow_overlap, tag, paused_until, cron_version \ - ) VALUES ( \ - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26 \ - ) RETURNING *") - .bind(&w_id) - .bind(&ns.path) - .bind(&ns.schedule) - .bind(&ns.timezone) - .bind(&authed.username) - .bind(&ns.script_path) - .bind(&ns.is_flow) - .bind(&ns.args) - .bind(&ns.enabled.unwrap_or(false)) - .bind(&authed.email) - .bind(&ns.on_failure) - .bind(&ns.on_failure_times) - .bind(&ns.on_failure_exact) - .bind(&ns.on_failure_extra_args) - .bind(&ns.on_recovery) - .bind(&ns.on_recovery_times) - .bind(&ns.on_recovery_extra_args) - .bind(&ns.on_success) - .bind(&ns.on_success_extra_args) - .bind(&ns.ws_error_handler_muted.unwrap_or(false)) - .bind(&ns.retry) - .bind(&ns.summary) - .bind(&ns.no_flow_overlap.unwrap_or(false)) - .bind(&ns.tag) - .bind(&ns.paused_until) - .bind(&ns.cron_version.unwrap_or("v2".to_string())) + let schedule = sqlx::query_as!( + Schedule, + r#" + INSERT INTO schedule ( + workspace_id, path, schedule, timezone, edited_by, script_path, + is_flow, args, enabled, email, + on_failure, on_failure_times, on_failure_exact, on_failure_extra_args, + on_recovery, on_recovery_times, on_recovery_extra_args, + on_success, on_success_extra_args, + ws_error_handler_muted, retry, summary, no_flow_overlap, + tag, paused_until, cron_version, description + ) VALUES ( + $1, $2, $3, $4, $5, $6, + $7, $8, $9, $10, + $11, $12, $13, $14, + $15, $16, $17, + $18, $19, + $20, $21, $22, $23, + $24, $25, $26, $27 + ) + RETURNING + workspace_id, + path, + edited_by, + edited_at, + schedule, + timezone, + enabled, + script_path, + is_flow, + args AS "args: _", + extra_perms, + email, + error, + on_failure, + on_failure_times, + on_failure_exact, + on_failure_extra_args AS "on_failure_extra_args: _", + on_recovery, + on_recovery_times, + on_recovery_extra_args AS "on_recovery_extra_args: _", + on_success, + on_success_extra_args AS "on_success_extra_args: _", + ws_error_handler_muted, + retry, + no_flow_overlap, + summary, + description, + tag, + paused_until, + cron_version + "#, + w_id, + ns.path, + ns.schedule, + ns.timezone, + authed.username, + ns.script_path, + ns.is_flow, + to_json_raw_opt(ns.args.as_ref()) + as Option>>, + ns.enabled.unwrap_or(false), + authed.email, + ns.on_failure, + ns.on_failure_times, + ns.on_failure_exact, + to_json_raw_opt(ns.on_failure_extra_args.as_ref()) + as Option>>, + ns.on_recovery, + ns.on_recovery_times, + to_json_raw_opt(ns.on_recovery_extra_args.as_ref()) + as Option>>, + ns.on_success, + to_json_raw_opt(ns.on_success_extra_args.as_ref()) + as Option>>, + ns.ws_error_handler_muted.unwrap_or(false), + ns.retry, + ns.summary, + ns.no_flow_overlap.unwrap_or(false), + ns.tag, + ns.paused_until, + ns.cron_version.clone().unwrap_or_else(|| "v2".to_string()), + ns.description + ) .fetch_one(&mut *tx) .await .map_err(|e| Error::internal_err(format!("inserting schedule in {w_id}: {e:#}")))?; @@ -252,34 +309,92 @@ async fn edit_schedule( ScheduleType::from_str(&es.schedule, es.cron_version.as_deref(), true)?; clear_schedule(&mut tx, path, &w_id).await?; - let schedule = sqlx::query_as::<_, Schedule>( - "UPDATE schedule SET schedule = $1, timezone = $2, args = $3, on_failure = $4, on_failure_times = $5, \ - on_failure_exact = $6, on_failure_extra_args = $7, on_recovery = $8, on_recovery_times = $9, \ - on_recovery_extra_args = $10, on_success = $11, on_success_extra_args = $12, \ - ws_error_handler_muted = $13, retry = $14, summary = $15, \ - no_flow_overlap = $16, tag = $17, paused_until = $18, cron_version = COALESCE($21, cron_version) \ - WHERE path = $19 AND workspace_id = $20 RETURNING *") - .bind(&es.schedule) - .bind(&es.timezone) - .bind(&es.args) - .bind(&es.on_failure) - .bind(&es.on_failure_times) - .bind(&es.on_failure_exact) - .bind(&es.on_failure_extra_args) - .bind(&es.on_recovery) - .bind(&es.on_recovery_times) - .bind(&es.on_recovery_extra_args) - .bind(&es.on_success) - .bind(&es.on_success_extra_args) - .bind(&es.ws_error_handler_muted.unwrap_or(false)) - .bind(&es.retry) - .bind(&es.summary) - .bind(&es.no_flow_overlap.unwrap_or(false)) - .bind(&es.tag) - .bind(&es.paused_until) - .bind(&path) - .bind(&w_id) - .bind(&es.cron_version) + let schedule = sqlx::query_as!( + Schedule, + r#" + UPDATE schedule SET + schedule = $1, + timezone = $2, + args = $3, + on_failure = $4, + on_failure_times = $5, + on_failure_exact = $6, + on_failure_extra_args = $7, + on_recovery = $8, + on_recovery_times = $9, + on_recovery_extra_args = $10, + on_success = $11, + on_success_extra_args = $12, + ws_error_handler_muted = $13, + retry = $14, + summary = $15, + no_flow_overlap = $16, + tag = $17, + paused_until = $18, + path = $19, + workspace_id = $20, + cron_version = COALESCE($21, cron_version), + description = $22 + WHERE path = $19 AND workspace_id = $20 + RETURNING + workspace_id, + path, + edited_by, + edited_at, + schedule, + timezone, + enabled, + script_path, + is_flow, + args AS "args: _", + extra_perms, + email, + error, + on_failure, + on_failure_times, + on_failure_exact, + on_failure_extra_args AS "on_failure_extra_args: _", + on_recovery, + on_recovery_times, + on_recovery_extra_args AS "on_recovery_extra_args: _", + on_success, + on_success_extra_args AS "on_success_extra_args: _", + ws_error_handler_muted, + retry, + no_flow_overlap, + summary, + description, + tag, + paused_until, + cron_version + "#, + es.schedule, + es.timezone, + to_json_raw_opt(es.args.as_ref()) + as Option>>, + es.on_failure, + es.on_failure_times, + es.on_failure_exact, + to_json_raw_opt(es.on_failure_extra_args.as_ref()) + as Option>>, + es.on_recovery, + es.on_recovery_times, + to_json_raw_opt(es.on_recovery_extra_args.as_ref()) + as Option>>, + es.on_success, + to_json_raw_opt(es.on_success_extra_args.as_ref()) + as Option>>, + es.ws_error_handler_muted.unwrap_or(false), + es.retry, + es.summary, + es.no_flow_overlap.unwrap_or(false), + es.tag, + es.paused_until, + path, + w_id, + es.cron_version, + es.description + ) .fetch_one(&mut *tx) .await .map_err(|e| Error::internal_err(format!("updating schedule in {w_id}: {e:#}")))?; @@ -352,7 +467,19 @@ async fn list_schedule( let mut tx = user_db.begin(&authed).await?; let (per_page, offset) = paginate(Pagination { per_page: lsq.per_page, page: lsq.page }); let mut sqlb = SqlBuilder::select_from("schedule") - .field("workspace_id, path, edited_by, edited_at, schedule, timezone, enabled, script_path, is_flow, summary, extra_perms") + .fields(&[ + "workspace_id", + "path", + "edited_by", + "edited_at", + "schedule", + "timezone", + "enabled", + "script_path", + "is_flow", + "summary", + "extra_perms", + ]) .order_by("edited_at", true) .and_where("workspace_id = ?".bind(&w_id)) .offset(offset) @@ -488,12 +615,50 @@ pub async fn set_enabled( ) -> Result { let mut tx = user_db.begin(&authed).await?; let path = path.to_path(); - let schedule_o = sqlx::query_as::<_, Schedule>( - "UPDATE schedule SET enabled = $1, email = $2 WHERE path = $3 AND workspace_id = $4 RETURNING *") - .bind(&payload.enabled) - .bind(&authed.email) - .bind(&path) - .bind(&w_id) + let schedule_o = sqlx::query_as!( + Schedule, + r#" + UPDATE schedule SET + enabled = $1, + email = $2 + WHERE path = $3 AND workspace_id = $4 + RETURNING + workspace_id, + path, + edited_by, + edited_at, + schedule, + timezone, + enabled, + script_path, + is_flow, + args AS "args: _", + extra_perms, + email, + error, + on_failure, + on_failure_times, + on_failure_exact, + on_failure_extra_args AS "on_failure_extra_args: _", + on_recovery, + on_recovery_times, + on_recovery_extra_args AS "on_recovery_extra_args: _", + on_success, + on_success_extra_args AS "on_success_extra_args: _", + ws_error_handler_muted, + retry, + no_flow_overlap, + summary, + description, + tag, + paused_until, + cron_version + "#, + payload.enabled, + authed.email, + path, + w_id + ) .fetch_optional(&mut *tx) .await?; @@ -819,6 +984,7 @@ pub struct EditSchedule { pub timezone: String, pub args: Option, pub summary: Option, + pub description: Option, pub on_failure: Option, pub on_failure_times: Option, pub on_failure_exact: Option, diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index f370bf33fe..8e707a15d2 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -44,12 +44,21 @@ use windmill_audit::ActionKind; use windmill_common::error::to_anyhow; use windmill_common::{ - db::UserDB, error::{Error, JsonResult, Result}, jobs::JobPayload, schedule::Schedule, schema::should_validate_schema, scripts::{ + db::UserDB, + error::{Error, JsonResult, Result}, + jobs::JobPayload, + schedule::Schedule, + schema::should_validate_schema, + scripts::{ to_i64, HubScript, ListScriptQuery, ListableScript, NewScript, Schema, Script, ScriptHash, ScriptHistory, ScriptHistoryUpdate, ScriptKind, ScriptLang, ScriptWithStarred, - }, users::username_to_permissioned_as, utils::{ + }, + users::username_to_permissioned_as, + utils::{ not_found_if_none, paginate, query_elems_from_hub, require_admin, Pagination, StripPath, - }, worker::to_raw_value, HUB_BASE_URL + }, + worker::to_raw_value, + HUB_BASE_URL, }; use windmill_git_sync::{handle_deployment_metadata, DeployedObject}; use windmill_parser_ts::remove_pinned_imports; @@ -409,10 +418,10 @@ async fn create_snapshot_script( std::fs::create_dir_all( windmill_common::worker::ROOT_STANDALONE_BUNDLE_DIR.clone(), )?; - windmill_common::worker::write_file( + windmill_common::worker::write_file_bytes( &windmill_common::worker::ROOT_STANDALONE_BUNDLE_DIR, &hash, - &String::from_utf8_lossy(&data), + &data, )?; } else { #[cfg(not(all(feature = "enterprise", feature = "parquet")))] @@ -624,17 +633,20 @@ async fn create_script_internal<'c>( .unwrap_or(json!({})); let lock = if ns.codebase.is_some() { Some(String::new()) - } else if !(ns.language == ScriptLang::Python3 - || ns.language == ScriptLang::Go - || ns.language == ScriptLang::Bun - || ns.language == ScriptLang::Bunnative - || ns.language == ScriptLang::Deno - || ns.language == ScriptLang::Rust - || ns.language == ScriptLang::Ansible - || ns.language == ScriptLang::CSharp - || ns.language == ScriptLang::Nu - || ns.language == ScriptLang::Php) - { + } else if !( + ns.language == ScriptLang::Python3 + || ns.language == ScriptLang::Go + || ns.language == ScriptLang::Bun + || ns.language == ScriptLang::Bunnative + || ns.language == ScriptLang::Deno + || ns.language == ScriptLang::Rust + || ns.language == ScriptLang::Ansible + || ns.language == ScriptLang::CSharp + || ns.language == ScriptLang::Nu + || ns.language == ScriptLang::Php + || ns.language == ScriptLang::Java + // for related places search: ADD_NEW_LANG + ) { Some(String::new()) } else { ns.lock diff --git a/backend/windmill-api/src/settings.rs b/backend/windmill-api/src/settings.rs index 37a33ee81a..a270074cc0 100644 --- a/backend/windmill-api/src/settings.rs +++ b/backend/windmill-api/src/settings.rs @@ -34,8 +34,8 @@ use windmill_common::{ email_ee::send_email, error::{self, JsonResult, Result}, global_settings::{ - AUTOMATE_USERNAME_CREATION_SETTING, EMAIL_DOMAIN_SETTING, ENV_SETTINGS, - HUB_ACCESSIBLE_URL_SETTING, HUB_BASE_URL_SETTING, + AUTOMATE_USERNAME_CREATION_SETTING, CRITICAL_ALERT_MUTE_UI_SETTING, EMAIL_DOMAIN_SETTING, + ENV_SETTINGS, HUB_ACCESSIBLE_URL_SETTING, HUB_BASE_URL_SETTING, }, server::Smtp, }; @@ -239,6 +239,13 @@ pub async fn set_global_setting_internal( })?; } } + CRITICAL_ALERT_MUTE_UI_SETTING => { + if value.clone().as_bool().unwrap_or(false) { + sqlx::query!("UPDATE alerts SET acknowledged = true") + .execute(db) + .await?; + } + } _ => {} } diff --git a/backend/windmill-api/src/slack_approvals.rs b/backend/windmill-api/src/slack_approvals.rs index 652c7b1721..4f37b648a9 100644 --- a/backend/windmill-api/src/slack_approvals.rs +++ b/backend/windmill-api/src/slack_approvals.rs @@ -23,7 +23,7 @@ use windmill_common::{ error::{self, Error}, jobs::JobKind, scripts::ScriptHash, - variables::{build_crypt, decrypt}, + variables::get_secret_value_as_admin, }; #[derive(Deserialize, Debug)] @@ -838,26 +838,9 @@ fn process_non_datetime_inputs( } async fn get_slack_token(db: &DB, slack_resource_path: &str, w_id: &str) -> anyhow::Result { - let slack_token = match sqlx::query!( - "SELECT value, is_secret FROM variable WHERE path = $1", - slack_resource_path - ) - .fetch_optional(db) - .await? - { - Some(row) => row, - None => { - return Err(anyhow::anyhow!("No slack token found")); - } - }; - - if slack_token.is_secret { - let mc = build_crypt(&db, w_id).await?; - let bot_token = decrypt(&mc, slack_token.value)?; - Ok(bot_token) - } else { - Ok(slack_token.value) - } + get_secret_value_as_admin(db, w_id, slack_resource_path) + .await + .map_err(|e| anyhow::anyhow!(e.to_string())) } // Sends a Slack message with a button that opens a modal diff --git a/backend/windmill-api/src/stripe_ee.rs b/backend/windmill-api/src/stripe_ee.rs index 1aea2ecd2d..6934cad3bc 100644 --- a/backend/windmill-api/src/stripe_ee.rs +++ b/backend/windmill-api/src/stripe_ee.rs @@ -1,7 +1,5 @@ -#[cfg(feature = "stripe")] use axum::Router; -#[cfg(feature = "stripe")] pub fn add_stripe_routes(router: Router) -> Router { return router; } diff --git a/backend/windmill-api/src/utils.rs b/backend/windmill-api/src/utils.rs index 1da91ae448..8823dca33e 100644 --- a/backend/windmill-api/src/utils.rs +++ b/backend/windmill-api/src/utils.rs @@ -8,7 +8,7 @@ use axum::{body::Body, response::Response}; use regex::Regex; -use serde::Deserialize; +use serde::{Deserialize, Deserializer}; use sqlx::{Postgres, Transaction}; #[cfg(feature = "enterprise")] use windmill_common::worker::CLOUD_HOSTED; @@ -190,6 +190,15 @@ pub fn content_plain(body: Body) -> Response { .unwrap() } +#[allow(unused)] +pub fn non_empty_str<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let o: Option = Option::deserialize(deserializer)?; + Ok(o.filter(|s| !s.trim().is_empty())) +} + use serde::Serialize; #[derive(Serialize)] diff --git a/backend/windmill-api/src/variables.rs b/backend/windmill-api/src/variables.rs index 425c4d86fc..e810f95750 100644 --- a/backend/windmill-api/src/variables.rs +++ b/backend/windmill-api/src/variables.rs @@ -61,7 +61,7 @@ async fn list_contextual_variables( ) -> JsonResult> { Ok(Json( get_reserved_variables( - &db, + &db.into(), &w_id, "q1A0qcPuO00yxioll7iph76N9CJDqn", &email, @@ -691,14 +691,21 @@ pub async fn get_variable_or_self(path: String, db: &DB, w_id: &str) -> Result Router { .route("/critical_alerts/mute", post(mute_critical_alerts)) .route("/operator_settings", post(update_operator_settings)); - #[cfg(feature = "stripe")] + #[cfg(all(feature = "stripe", feature = "enterprise"))] { crate::stripe_ee::add_stripe_routes(router) } @@ -211,10 +211,7 @@ pub struct WorkspaceSettings { #[serde(skip_serializing_if = "Option::is_none")] pub deploy_to: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub ai_resource: Option, - pub ai_models: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - pub code_completion_model: Option, + pub ai_config: Option, #[serde(skip_serializing_if = "Option::is_none")] pub error_handler: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -229,7 +226,6 @@ pub struct WorkspaceSettings { pub deploy_ui: Option, // effectively: WorkspaceDeploymentUISettings #[serde(skip_serializing_if = "Option::is_none")] pub default_app: Option, - pub automatic_billing: bool, #[serde(skip_serializing_if = "Option::is_none")] pub default_scripts: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -238,6 +234,8 @@ pub struct WorkspaceSettings { pub color: Option, #[serde(skip_serializing_if = "Option::is_none")] pub operator_settings: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub git_app_installations: Option, } #[derive(FromRow, Serialize, Debug)] @@ -291,13 +289,6 @@ struct EditWebhook { webhook: Option, } -#[derive(Deserialize)] -struct EditCopilotConfig { - ai_resource: Option, - code_completion_model: Option, - ai_models: Vec, -} - #[derive(Deserialize, Serialize, Debug)] struct LargeFileStorageWithSecondary { #[serde(flatten)] @@ -449,7 +440,7 @@ async fn get_settings( let mut tx = user_db.begin(&authed).await?; let settings = sqlx::query_as!( WorkspaceSettings, - "SELECT workspace_id, slack_team_id, teams_team_id, teams_team_name, slack_name, slack_command_script, teams_command_script, slack_email, auto_invite_domain, auto_invite_operator, auto_add, customer_id, plan, webhook, deploy_to, ai_resource, ai_models, code_completion_model, error_handler, error_handler_extra_args, error_handler_muted_on_cancel, large_file_storage, git_sync, deploy_ui, default_app, automatic_billing, default_scripts, mute_critical_alerts, color, operator_settings FROM workspace_settings WHERE workspace_id = $1", + "SELECT workspace_id, slack_team_id, teams_team_id, teams_team_name, slack_name, slack_command_script, teams_command_script, slack_email, auto_invite_domain, auto_invite_operator, auto_add, customer_id, plan, webhook, deploy_to, ai_config, error_handler, error_handler_extra_args, error_handler_muted_on_cancel, large_file_storage, git_sync, deploy_ui, default_app, default_scripts, mute_critical_alerts, color, operator_settings, git_app_installations FROM workspace_settings WHERE workspace_id = $1", &w_id ) .fetch_one(&mut *tx) @@ -495,11 +486,11 @@ async fn edit_slack_command( if es.slack_command_script.is_some() { let exists_slack_command_with_team_id = sqlx::query_scalar!( r#" - SELECT EXISTS (SELECT 1 - FROM workspace_settings - WHERE workspace_id <> $1 + SELECT EXISTS (SELECT 1 + FROM workspace_settings + WHERE workspace_id <> $1 AND slack_command_script IS NOT NULL - AND slack_team_id IS NOT NULL + AND slack_team_id IS NOT NULL AND slack_team_id = (SELECT slack_team_id FROM workspace_settings WHERE workspace_id = $1)) "#, &w_id @@ -697,51 +688,26 @@ async fn edit_copilot_config( Extension(db): Extension, Path(w_id): Path, ApiAuthed { is_admin, username, .. }: ApiAuthed, - Json(eo): Json, + Json(ai_config): Json, ) -> Result { require_admin(is_admin, &username)?; let mut tx = db.begin().await?; - if let Some(ai_resource) = &eo.ai_resource { - let parsed_ai_resource = serde_json::from_value::(ai_resource.clone()) - .map_err(|e| Error::BadRequest(e.to_string()))?; + sqlx::query!( + "UPDATE workspace_settings SET ai_config = $1 WHERE workspace_id = $2", + sqlx::types::Json(&ai_config) as sqlx::types::Json<&AIConfig>, + &w_id + ) + .execute(&mut *tx) + .await?; - #[cfg(not(feature = "enterprise"))] - { - if matches!(parsed_ai_resource.provider, AIProvider::CustomAI) { - return Err(Error::BadRequest( - "Custom AI is only available on EE".to_string(), - )); - } + if let Some(ref providers) = ai_config.providers { + for provider in providers.keys() { + AI_REQUEST_CACHE.remove(&(w_id.clone(), provider.clone())); } - - sqlx::query!( - "UPDATE workspace_settings SET ai_resource = $1, code_completion_model = $2, ai_models = $3 WHERE workspace_id = $4", - ai_resource, - eo.code_completion_model, - eo.ai_models.as_slice(), - &w_id - ) - .execute(&mut *tx) - .await?; - - if let Some(cached) = AI_KEY_CACHE.get(&w_id) { - if parsed_ai_resource.path.is_none() || parsed_ai_resource.path.unwrap() != cached.path - { - AI_KEY_CACHE.remove(&w_id); - } - } - } else { - sqlx::query!( - "UPDATE workspace_settings SET ai_resource = NULL, code_completion_model = $1, ai_models = '{}' WHERE workspace_id = $2", - eo.code_completion_model, - &w_id, - ) - .execute(&mut *tx) - .await?; - AI_KEY_CACHE.remove(&w_id); } + audit_log( &mut *tx, &authed, @@ -749,16 +715,7 @@ async fn edit_copilot_config( ActionKind::Update, &w_id, Some(&authed.email), - Some( - [ - ("ai_resource", &format!("{:?}", eo.ai_resource)[..]), - ( - "code_completion_model", - &format!("{:?}", eo.code_completion_model)[..], - ), - ] - .into(), - ), + Some([("ai_config", &format!("{:?}", ai_config)[..])].into()), ) .await?; tx.commit().await?; @@ -766,42 +723,33 @@ async fn edit_copilot_config( Ok(format!("Edit copilot config for workspace {}", &w_id)) } -#[derive(Serialize)] -struct CopilotInfo { - #[serde(skip_serializing_if = "Option::is_none")] - pub ai_provider: Option, - pub exists_ai_resource: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub code_completion_model: Option, - pub ai_models: Vec, -} async fn get_copilot_info( Extension(db): Extension, Path(w_id): Path, -) -> JsonResult { +) -> JsonResult { let mut tx = db.begin().await?; - let record = sqlx::query!( - "SELECT ai_resource, code_completion_model, ai_models FROM workspace_settings WHERE workspace_id = $1", + let copilot_info = sqlx::query_scalar!( + "SELECT ai_config as \"ai_config: sqlx::types::Json\" FROM workspace_settings WHERE workspace_id = $1", &w_id ) .fetch_one(&mut *tx) .await - .map_err(|e| Error::internal_err(format!("getting ai_resource and code_completion_model: {e:#}")))?; + .map_err(|e| { + Error::internal_err(format!( + "getting ai config: {e:#}" + )) + })?; tx.commit().await?; - let (ai_provider, exists_ai_resource) = if let Some(ai_resource) = record.ai_resource { - let ai_resource = serde_json::from_value::(ai_resource)?; - (Some(ai_resource.provider), ai_resource.path.is_some()) + if let Some(sqlx::types::Json(copilot_info)) = copilot_info { + Ok(Json(copilot_info)) } else { - (None, false) - }; - - Ok(Json(CopilotInfo { - ai_provider, - exists_ai_resource, - code_completion_model: record.code_completion_model, - ai_models: record.ai_models, - })) + Ok(Json(AIConfig { + providers: None, + default_model: None, + code_completion_model: None, + })) + } } async fn edit_large_file_storage_config( @@ -1359,6 +1307,7 @@ struct UsedTriggers { pub postgres_used: bool, pub mqtt_used: bool, pub sqs_used: bool, + pub gcp_used: bool, } async fn get_used_triggers( @@ -1370,15 +1319,15 @@ async fn get_used_triggers( let websocket_used = sqlx::query_as!( UsedTriggers, r#" - SELECT - - EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS "websocket_used!", + SELECT + EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS "websocket_used!", EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS "http_routes_used!", EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as "kafka_used!", EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as "nats_used!", EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS "postgres_used!", EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS "mqtt_used!", - EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS "sqs_used!" + EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS "sqs_used!", + EXISTS(SELECT 1 FROM gcp_trigger WHERE workspace_id = $1) AS "gcp_used!" "#, w_id ) @@ -2100,8 +2049,8 @@ async fn change_workspace_color( async fn get_usage(Extension(db): Extension, Path(w_id): Path) -> Result { let usage = sqlx::query_scalar!( " - SELECT usage.usage FROM usage - WHERE is_workspace = true + SELECT usage.usage FROM usage + WHERE is_workspace = true AND month_ = EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date) AND id = $1", w_id diff --git a/backend/windmill-api/src/workspaces_export.rs b/backend/windmill-api/src/workspaces_export.rs index 003a01c002..ac98ae12ec 100644 --- a/backend/windmill-api/src/workspaces_export.rs +++ b/backend/windmill-api/src/workspaces_export.rs @@ -250,10 +250,7 @@ struct SimplifiedSettings { error_handler_extra_args: Option, error_handler_muted_on_cancel: bool, #[serde(skip_serializing_if = "Option::is_none")] - ai_resource: Option, - ai_models: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - code_completion_model: Option, + ai_config: Option, #[serde(skip_serializing_if = "Option::is_none")] large_file_storage: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -378,6 +375,8 @@ pub(crate) async fn tarball_workspace( ScriptLang::CSharp => "cs", ScriptLang::Nu => "nu", ScriptLang::OracleDB => "odb.sql", + ScriptLang::Java => "java", + // for related places search: ADD_NEW_LANG }; archive .write_to_archive(&script.content, &format!("{}.{}", script.path, ext)) @@ -500,8 +499,8 @@ pub(crate) async fn tarball_workspace( { let apps = sqlx::query_as::<_, AppWithLastVersion>( "SELECT app.id, app.path, app.summary, app.versions, app.policy, app.custom_path, - app.extra_perms, app_version.value, - app_version.created_at, app_version.created_by from app, app_version + app.extra_perms, app_version.value, + app_version.created_at, app_version.created_by from app, app_version WHERE app.workspace_id = $1 AND app_version.id = app.versions[array_upper(app.versions, 1)]", ) .bind(&w_id) @@ -545,6 +544,7 @@ pub(crate) async fn tarball_workspace( path, route_path, route_path_key, + authentication_resource_path, script_path, is_flow, edited_by, @@ -552,7 +552,7 @@ pub(crate) async fn tarball_workspace( email, extra_perms, is_async, - requires_auth, + authentication_method AS "authentication_method: _", http_method AS "http_method: _", static_asset_config AS "static_asset_config: _", is_static_website, @@ -637,6 +637,47 @@ pub(crate) async fn tarball_workspace( } } + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + { + let gcp_triggers = sqlx::query_as!( + crate::gcp_triggers_ee::GcpTrigger, + r#" + SELECT + gcp_resource_path, + subscription_id, + topic_id, + workspace_id, + delivery_type AS "delivery_type: _", + delivery_config AS "delivery_config: _", + path, + script_path, + is_flow, + edited_by, + email, + edited_at, + server_id, + last_server_ping, + extra_perms, + error, + enabled + FROM + gcp_trigger + WHERE + workspace_id = $1 + "#, + &w_id + ) + .fetch_all(&mut *tx) + .await?; + + for trigger in gcp_triggers { + let trigger_str = &to_string_without_metadata(&trigger, false, None).unwrap(); + archive + .write_to_archive(&trigger_str, &format!("{}.gcp_trigger.json", trigger.path)) + .await?; + } + } + #[cfg(all(feature = "enterprise", feature = "nats"))] { let nats_triggers = sqlx::query_as!( @@ -711,7 +752,7 @@ pub(crate) async fn tarball_workspace( if include_groups.unwrap_or(false) { let groups = sqlx::query!( - r#"SELECT g_.workspace_id, name, summary, extra_perms, array_agg(u2g.usr) filter (where u2g.usr is not null) as members + r#"SELECT g_.workspace_id, name, summary, extra_perms, array_agg(u2g.usr) filter (where u2g.usr is not null) as members FROM usr u JOIN usr_to_group u2g ON u2g.usr = u.username AND u2g.workspace_id = u.workspace_id RIGHT JOIN group_ g_ ON g_.workspace_id = u.workspace_id AND g_.name = u2g.group_ @@ -773,22 +814,20 @@ pub(crate) async fn tarball_workspace( let settings = sqlx::query_as!( SimplifiedSettings, r#"SELECT - -- slack_team_id, - -- slack_name, - -- slack_command_script, + -- slack_team_id, + -- slack_name, + -- slack_command_script, -- CASE WHEN slack_email = 'missing@email.xyz' THEN NULL ELSE slack_email END AS slack_email, auto_invite_domain IS NOT NULL AS "auto_invite_enabled!", - CASE WHEN auto_invite_operator IS TRUE THEN 'operator' ELSE 'developer' END AS "auto_invite_as!", - CASE WHEN auto_add IS TRUE THEN 'add' ELSE 'invite' END AS "auto_invite_mode!", - webhook, - deploy_to, - error_handler, - ai_resource, - ai_models, - code_completion_model, - error_handler_extra_args, - error_handler_muted_on_cancel, - large_file_storage, + CASE WHEN auto_invite_operator IS TRUE THEN 'operator' ELSE 'developer' END AS "auto_invite_as!", + CASE WHEN auto_add IS TRUE THEN 'add' ELSE 'invite' END AS "auto_invite_mode!", + webhook, + deploy_to, + error_handler, + ai_config, + error_handler_extra_args, + error_handler_muted_on_cancel, + large_file_storage, git_sync, default_app, default_scripts, diff --git a/backend/windmill-common/Cargo.toml b/backend/windmill-common/Cargo.toml index 7ff360b42b..140d3e2b74 100644 --- a/backend/windmill-common/Cargo.toml +++ b/backend/windmill-common/Cargo.toml @@ -24,6 +24,7 @@ name = "windmill_common" path = "src/lib.rs" [dependencies] +tar.workspace = true hmac.workspace = true sha2.workspace = true thiserror.workspace = true @@ -33,6 +34,8 @@ serde_json.workspace = true chrono.workspace = true chrono-tz.workspace = true hex.workspace = true +reqwest-middleware = { workspace = true } +reqwest-retry = { workspace = true } rand.workspace = true sqlx = { workspace = true, features = ["postgres"] } uuid.workspace = true diff --git a/backend/windmill-common/src/agent_workers.rs b/backend/windmill-common/src/agent_workers.rs new file mode 100644 index 0000000000..7c91ec2165 --- /dev/null +++ b/backend/windmill-common/src/agent_workers.rs @@ -0,0 +1,90 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +pub struct QueueInitJob { + pub content: String, +} + +use lazy_static::lazy_static; +use std::time::Duration; + +use reqwest_middleware::ClientBuilder; +use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware}; + +use crate::{jwt::decode_without_verify, worker::HttpClient}; + +lazy_static! { + pub static ref BASE_INTERNAL_URL: String = + std::env::var("BASE_INTERNAL_URL").unwrap_or("http://localhost:8080".to_string()); + pub static ref AGENT_TOKEN: String = std::env::var("AGENT_TOKEN").unwrap_or_default(); + pub static ref DECODED_AGENT_TOKEN: Option = { + if AGENT_TOKEN.is_empty() { + None + } else { + decode_without_verify::(AGENT_TOKEN.trim_start_matches(AGENT_JWT_PREFIX)) + .ok() + } + }; +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct AgentAuth { + pub worker_group: String, + pub suffix: Option, + pub tags: Vec, + pub exp: Option, +} + +pub const AGENT_JWT_PREFIX: &str = "jwt_agent_"; +pub fn build_agent_http_client(worker_suffix: &str) -> HttpClient { + let client = ClientBuilder::new( + reqwest::Client::builder() + .pool_max_idle_per_host(10) + .pool_idle_timeout(Duration::from_secs(60)) + .connect_timeout(Duration::from_secs(10)) + .timeout(Duration::from_secs(30)) + .default_headers({ + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert( + "User-Agent", // Replace with your desired header name + "Windmill-Agent/1.0".parse().unwrap(), // Replace with your desired header value + ); + let token = format!( + "{}{}_{}", + AGENT_JWT_PREFIX, + worker_suffix, + AGENT_TOKEN.trim_start_matches(AGENT_JWT_PREFIX), + ); + headers.insert( + "Authorization", + format!("Bearer {}", token).parse().unwrap(), + ); + headers + }) + .build() + .expect("Failed to create HTTP client"), + ) + .with(RetryTransientMiddleware::new_with_policy( + ExponentialBackoff::builder().build_with_max_retries(5), + )) + .build(); + HttpClient(client) +} + +#[derive(Deserialize, Serialize)] +pub struct PingJobStatus { + pub mem_peak: Option, + pub current_mem: Option, +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct PingJobStatusResponse { + pub canceled_by: Option, + pub canceled_reason: Option, + pub already_completed: bool, +} + +// #[derive(Serialize, Deserialize)] +// pub struct PullJobRequest { +// pub worker_name: String, +// } diff --git a/backend/windmill-common/src/auth.rs b/backend/windmill-common/src/auth.rs index d63fddc670..0266498773 100644 --- a/backend/windmill-common/src/auth.rs +++ b/backend/windmill-common/src/auth.rs @@ -1,8 +1,11 @@ +use anyhow::Context; use serde::{Deserialize, Serialize}; +use uuid::Uuid; use crate::{ db::Authed, error::{Error, Result}, + jwt, users::{SUPERADMIN_NOTIFICATION_EMAIL, SUPERADMIN_SECRET_EMAIL, SUPERADMIN_SYNC_EMAIL}, DB, }; @@ -22,7 +25,7 @@ pub struct JWTAuthClaims { pub scopes: Option>, } -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] pub struct JobPerms { pub email: String, pub username: String, @@ -205,3 +208,62 @@ pub async fn get_groups_for_user( .collect(); Ok(groups) } + +#[tracing::instrument(level = "trace", skip_all)] +pub async fn create_token_for_owner( + db: &DB, + w_id: &str, + owner: &str, + label: &str, + expires_in: u64, + email: &str, + job_id: &Uuid, + perms: Option, +) -> crate::error::Result { + let job_perms = if perms.is_some() { + Ok(perms) + } else { + sqlx::query_as!( + JobPerms, + "SELECT email, username, is_admin, is_operator, groups, folders FROM job_perms WHERE job_id = $1 AND workspace_id = $2", + job_id, + w_id + ) + .fetch_optional(db) + .await + }; + let job_authed = match job_perms { + Ok(Some(jp)) => jp.into(), + _ => { + tracing::warn!("Could not get permissions for job {job_id} from job_perms table, getting permissions directly..."); + fetch_authed_from_permissioned_as(owner.to_string(), email.to_string(), w_id, db) + .await + .map_err(|e| { + Error::internal_err(format!( + "Could not get permissions directly for job {job_id}: {e:#}" + )) + })? + } + }; + + let payload = JWTAuthClaims { + email: job_authed.email, + username: job_authed.username, + is_admin: job_authed.is_admin, + is_operator: job_authed.is_operator, + groups: job_authed.groups, + folders: job_authed.folders, + label: Some(label.to_string()), + workspace_id: w_id.to_string(), + exp: (chrono::Utc::now() + chrono::Duration::seconds(expires_in as i64)).timestamp() + as usize, + job_id: Some(job_id.to_string()), + scopes: None, + }; + + let token = jwt::encode_with_internal_secret(&payload) + .await + .with_context(|| format!("Could not encode JWT token for job {job_id}"))?; + + Ok(format!("jwt_{}", token)) +} diff --git a/backend/windmill-worker/src/bench.rs b/backend/windmill-common/src/bench.rs similarity index 98% rename from backend/windmill-worker/src/bench.rs rename to backend/windmill-common/src/bench.rs index 5006d5a34c..c851198b2a 100644 --- a/backend/windmill-worker/src/bench.rs +++ b/backend/windmill-common/src/bench.rs @@ -1,9 +1,9 @@ -use serde::Serialize; -use tokio::time::Instant; -use windmill_common::{ +use crate::{ worker::{write_file, TMP_DIR}, DB, }; +use serde::Serialize; +use tokio::time::Instant; #[derive(Serialize)] pub struct BenchmarkInfo { @@ -41,8 +41,8 @@ impl BenchmarkInfo { self.total_duration = Some(total_duration as u64); println!( - "Writing benchmark {path}, duration of benchmark: {total_duration}s and RPS: {}", - self.iters as f64 / total_duration as f64 + "Writing benchmark {path}, duration of benchmark: {total_duration}ms and RPS: {}", + self.iters as f64 / total_duration as f64 * 1000.0 ); write_file(TMP_DIR, path, &serde_json::to_string(&self).unwrap()).expect("write profiling"); Ok(()) @@ -79,7 +79,7 @@ impl BenchmarkIter { } pub async fn benchmark_init(benchmark_jobs: i32, db: &DB) { - use windmill_common::{jobs::JobKind, scripts::ScriptLang}; + use crate::{jobs::JobKind, scripts::ScriptLang}; let benchmark_kind = std::env::var("BENCHMARK_KIND").unwrap_or("noop".to_string()); diff --git a/backend/windmill-common/src/cache.rs b/backend/windmill-common/src/cache.rs index 9374445f22..aac1457f56 100644 --- a/backend/windmill-common/src/cache.rs +++ b/backend/windmill-common/src/cache.rs @@ -7,7 +7,6 @@ //! This shall only be used for testing, e.g. [`sqlx::test`] spawn a database per test, //! and there is only one test per thread, so using thread-local cache avoid unexpected results. -use anyhow::anyhow; use crate::{ apps::AppScriptId, error, @@ -15,6 +14,7 @@ use crate::{ schema::SchemaValidator, scripts::{ScriptHash, ScriptLang}, }; +use anyhow::anyhow; #[cfg(feature = "scoped_cache")] use std::thread::ThreadId; @@ -322,6 +322,25 @@ pub struct RawScript { pub meta: Option, } +#[derive(Debug, Deserialize, Serialize)] +pub struct RawScriptApi { + pub content: String, + pub lock: Option, + pub meta: Option, +} + +impl From for RawScriptApi { + fn from(value: RawScript) -> Self { + RawScriptApi { content: value.content, lock: value.lock, meta: value.meta } + } +} + +impl From for RawScript { + fn from(value: RawScriptApi) -> Self { + RawScript { content: value.content, lock: value.lock, meta: value.meta } + } +} + #[derive(Debug)] pub struct RawFlow { pub raw_flow: Box, @@ -334,6 +353,25 @@ pub struct RawNode { pub raw_flow: Option>, } +#[derive(Debug, Deserialize, Serialize)] +pub struct RawNodeApi { + pub raw_code: Option, + pub raw_lock: Option, + pub raw_flow: Option>, +} + +impl From for RawNodeApi { + fn from(value: RawNode) -> Self { + RawNodeApi { raw_code: value.raw_code, raw_lock: value.raw_lock, raw_flow: value.raw_flow } + } +} + +impl From for RawNode { + fn from(value: RawNodeApi) -> Self { + RawNode { raw_code: value.raw_code, raw_lock: value.raw_lock, raw_flow: value.raw_flow } + } +} + #[derive(Debug, Clone)] struct Entry(Arc); @@ -343,7 +381,7 @@ struct ScriptFull { pub meta: Arc, } -fn unwrap_or_error( +pub fn unwrap_or_error( at: &'static Location, entity: &'static str, key: Key, @@ -363,6 +401,11 @@ pub fn clear() { } pub mod flow { + use crate::{ + worker::{fetch_flow_node_query, Connection}, + DB, + }; + use super::*; make_static! { @@ -388,10 +431,10 @@ pub mod flow { /// This should be preferred over fetching the database directly. #[track_caller] pub fn fetch_script<'c>( - e: impl PgExecutor<'c>, + conn: &'c Connection, node: FlowNodeId, - ) -> impl Future>> { - let fetch_node = fetch_node(e, node); + ) -> impl Future>> + 'c { + let fetch_node = fetch_node(conn, node); async move { fetch_node.await.and_then(|data| match data { RawData::Script(data) => Ok(data), @@ -409,11 +452,12 @@ pub mod flow { /// This should be preferred over fetching the database directly. #[track_caller] pub fn fetch_flow<'c>( - e: impl PgExecutor<'c>, + db: &'c DB, node: FlowNodeId, - ) -> impl Future>> { - let fetch_node = fetch_node(e, node); + ) -> impl Future>> + 'c { async move { + let conn = Connection::Sql(db.clone()); + let fetch_node = fetch_node(&conn, node); fetch_node.await.and_then(|data| match data { RawData::Flow(data) => Ok(data), RawData::Script(_) => Err(error::Error::internal_err(format!( @@ -430,31 +474,23 @@ pub mod flow { /// This should be preferred over fetching the database directly. #[track_caller] pub(super) fn fetch_node<'c>( - e: impl PgExecutor<'c>, + conn: &'c Connection, node: FlowNodeId, - ) -> impl Future> { + ) -> impl Future> + 'c { let loc = Location::caller(); // If not present, `get_or_insert_async` will lock the key until the future completes, // so only one thread will be able to fetch the data from the database and write it to // the file system and cache, hence no race on the file system. NODES.get_or_insert_async(node, async move { - sqlx::query!( - "SELECT \ - code AS \"raw_code: String\", \ - lock AS \"raw_lock: String\", \ - flow AS \"raw_flow: Json>\" \ - FROM flow_node WHERE id = $1 LIMIT 1", - node.0, - ) - .fetch_optional(e) - .await - .map_err(Into::into) - .and_then(unwrap_or_error(&loc, "Flow node", node)) - .map(|r| RawNode { - raw_code: r.raw_code, - raw_lock: r.raw_lock, - raw_flow: r.raw_flow.map(|Json(raw_flow)| raw_flow), - }) + match conn { + Connection::Sql(db) => fetch_flow_node_query(db, node.0, loc).await, + Connection::Http(client) => { + let r = client + .get::(&format!("/api/agent_workers/flow_script/{}", node.0)) + .await?; + Ok(r.into()) + } + } }) } @@ -502,6 +538,8 @@ pub mod flow { } pub mod script { + use crate::{worker::Connection, DB}; + use super::*; make_static! { @@ -520,66 +558,80 @@ pub mod script { /// it to the file system and cache. /// This should be preferred over fetching the database directly. #[track_caller] - pub fn fetch<'c>( - e: impl PgExecutor<'c>, + pub fn fetch( + conn: &Connection, hash: ScriptHash, ) -> impl Future, Arc)>> { // If not present, `get_or_insert_async` will lock the key until the future completes, // so only one thread will be able to fetch the data from the database and write it to // the file system and cache, hence no race on the file system. let loc = Location::caller(); + let conn = conn.clone(); let fut = CACHE.get_or_insert_async(hash, async move { - sqlx::query!( - "SELECT \ - content AS \"content!: String\", - lock AS \"lock: String\", \ - language AS \"language: Option\", \ - envs AS \"envs: Vec\", \ - schema AS \"schema: String\", \ - schema_validation AS \"schema_validation: bool\", \ - codebase LIKE '%.tar' as use_tar \ - FROM script WHERE hash = $1 LIMIT 1", - hash.0 - ) - .fetch_optional(e) - .await - .map_err(Into::into) - .and_then(unwrap_or_error(&loc, "Script", hash)) - .and_then(|r| { - Ok(RawScript { - content: r.content, - lock: r.lock, - meta: Some(ScriptMetadata { - language: r.language, - envs: r.envs, - codebase: if let Some(use_tar) = r.use_tar { - let sh = hash.to_string(); - if use_tar { - Some(format!("{sh}.tar")) - } else { - Some(sh) - } - } else { - None - }, - schema_validator: if r.schema_validation { - r.schema - .as_ref() - .map(|schema_str| { - SchemaValidator::from_schema(schema_str).map_err(|e| anyhow!("Couldn't create schema validator for script requiring schema validation: {e}")) - }) - .transpose()? - } else { - None - }, - schema: r.schema, - }), - }) - }) + match conn { + Connection::Sql(db) => fetch_script_from_db(&db, hash, loc).await, + Connection::Http(_) => Err(error::Error::InternalErr(format!( + "Cannot fetch script in HTTP mode" + ))), + } }); fut.map_ok(|ScriptFull { data, meta }| (data, meta)) } + async fn fetch_script_from_db( + db: &DB, + hash: ScriptHash, + loc: &'static Location<'_>, + ) -> error::Result { + sqlx::query!( + "SELECT \ + content AS \"content!: String\", + lock AS \"lock: String\", \ + language AS \"language: Option\", \ + envs AS \"envs: Vec\", \ + schema AS \"schema: String\", \ + schema_validation AS \"schema_validation: bool\", \ + codebase LIKE '%.tar' as use_tar \ + FROM script WHERE hash = $1 LIMIT 1", + hash.0 + ) + .fetch_optional(db) + .await + .map_err(Into::into) + .and_then(unwrap_or_error(&loc, "Script", hash)) + .and_then(|r| { + Ok(RawScript { + content: r.content, + lock: r.lock, + meta: Some(ScriptMetadata { + language: r.language, + envs: r.envs, + codebase: if let Some(use_tar) = r.use_tar { + let sh = hash.to_string(); + if use_tar { + Some(format!("{sh}.tar")) + } else { + Some(sh) + } + } else { + None + }, + schema_validator: if r.schema_validation { + r.schema + .as_ref() + .map(|schema_str| { + SchemaValidator::from_schema(schema_str).map_err(|e| anyhow!("Couldn't create schema validator for script requiring schema validation: {e}")) + }) + .transpose()? + } else { + None + }, + schema: r.schema, + }), + }) + }) + } + /// Invalidate the script cache for the given `hash`. pub fn invalidate(hash: ScriptHash) { let _ = CACHE.remove(&hash); @@ -587,6 +639,8 @@ pub mod script { } pub mod app { + use crate::worker::{fetch_raw_script_from_app_query, Connection}; + use super::*; make_static! { @@ -605,23 +659,23 @@ pub mod app { /// This should be preferred over fetching the database directly. #[track_caller] pub fn fetch_script<'c>( - e: impl PgExecutor<'c>, + conn: &'c Connection, id: AppScriptId, - ) -> impl Future>> { + ) -> impl Future>> + 'c { // If not present, `get_or_insert_async` will lock the key until the future completes, // so only one thread will be able to fetch the data from the database and write it to // the file system and cache, hence no race on the file system. let loc = Location::caller(); let fut = CACHE.get_or_insert_async(id, async move { - sqlx::query!( - "SELECT lock, code FROM app_script WHERE id = $1 LIMIT 1", - id.0, - ) - .fetch_optional(e) - .await - .map_err(Into::into) - .and_then(unwrap_or_error(&loc, "Application script", id)) - .map(|r| RawScript { content: r.code, lock: r.lock, meta: None }) + match conn { + Connection::Sql(db) => fetch_raw_script_from_app_query(db, id.0, loc).await, + Connection::Http(client) => { + let r = client + .get::(&format!("/api/agent_workers/app_script/{}", id.0)) + .await?; + Ok(r.into()) + } + } }); fut.map_ok(|Entry(data)| data) } @@ -629,7 +683,7 @@ pub mod app { pub mod job { use super::*; - use crate::jobs::JobKind; + use crate::{jobs::JobKind, worker::Connection, DB}; #[cfg(not(feature = "scoped_cache"))] lazy_static! { @@ -649,15 +703,18 @@ pub mod job { } #[track_caller] - pub fn fetch_preview_flow<'a, 'c>( - e: impl PgExecutor<'c> + 'a, + pub fn fetch_preview_flow<'a>( + db: &'a DB, job: &'a Uuid, - // original raw values from `queue` or `completed_job` tables: - // kept for backward compatibility. raw_flow: Option>>, ) -> impl Future>> + 'a { - let fetch_preview = fetch_preview(e, job, None, None, raw_flow); + // Create the Connection first so it lives for the entire scope + async move { + let conn = Connection::from(db); + + let fetch_preview = fetch_preview(&conn, job, None, None, raw_flow); + fetch_preview.await.and_then(|data| match data { RawData::Flow(data) => Ok(data), RawData::Script(_) => Err(error::Error::internal_err(format!( @@ -669,7 +726,7 @@ pub mod job { #[track_caller] pub fn fetch_preview_script<'a, 'c>( - e: impl PgExecutor<'c> + 'a, + e: &'a Connection, job: &'a Uuid, // original raw values from `queue` or `completed_job` tables: // kept for backward compatibility. @@ -689,7 +746,7 @@ pub mod job { #[track_caller] pub fn fetch_preview<'a, 'c>( - e: impl PgExecutor<'c> + 'a, + e: &'a Connection, job: &'a Uuid, // original raw values from `queue` or `completed_job` tables: // kept for backward compatibility. @@ -700,16 +757,21 @@ pub mod job { let loc = Location::caller(); let fetch = async move { match (raw_lock, raw_code, raw_flow) { - (None, None, None) => sqlx::query!( - "SELECT raw_code, raw_lock, raw_flow AS \"raw_flow: Json>\" \ - FROM v2_job WHERE id = $1 LIMIT 1", - job - ) - .fetch_optional(e) - .await - .map_err(Into::into) - .and_then(unwrap_or_error(&loc, "Preview", job)) - .map(|r| (r.raw_lock, r.raw_code, r.raw_flow)), + (None, None, None) => match e { + Connection::Sql(pool) => sqlx::query!( + "SELECT raw_code, raw_lock, raw_flow AS \"raw_flow: Json>\" \ + FROM v2_job WHERE id = $1 LIMIT 1", + job + ) + .fetch_optional(pool) + .await + .map_err(Into::into) + .and_then(unwrap_or_error(&loc, "Preview", job)) + .map(|r| (r.raw_lock, r.raw_code, r.raw_flow)), + Connection::Http(_) => Err(error::Error::InternalErr(format!( + "Cannot fetch preview in HTTP mode" + ))), + }, (lock, code, flow) => Ok((lock, code, flow)), } .and_then(|(lock, code, flow)| match flow { @@ -730,8 +792,8 @@ pub mod job { } #[track_caller] - pub fn fetch_script<'c>( - e: impl PgExecutor<'c>, + pub fn fetch_script( + db: DB, kind: JobKind, hash: Option, ) -> impl Future>> { @@ -739,11 +801,15 @@ pub mod job { let loc = Location::caller(); async move { match (kind, hash.map(|ScriptHash(id)| id)) { - (FlowScript, Some(id)) => flow::fetch_script(e, FlowNodeId(id)).await, - (Script | Dependencies, Some(hash)) => script::fetch(e, ScriptHash(hash)) + (FlowScript, Some(id)) => { + flow::fetch_script(&Connection::Sql(db.clone()), FlowNodeId(id)).await + } + (Script | Dependencies, Some(hash)) => script::fetch(&db.into(), ScriptHash(hash)) .await .map(|(data, _meta)| data), - (AppScript, Some(id)) => app::fetch_script(e, AppScriptId(id)).await, + (AppScript, Some(id)) => { + app::fetch_script(&Connection::Sql(db.clone()), AppScriptId(id)).await + } _ => Err(error::Error::internal_err(format!( "Isn't a script job: {:?}", kind @@ -755,19 +821,19 @@ pub mod job { #[track_caller] pub fn fetch_flow<'c>( - e: impl PgExecutor<'c> + Copy, + db: &'c DB, kind: JobKind, hash: Option, - ) -> impl Future>> { + ) -> impl Future>> + 'c { use JobKind::*; let loc = Location::caller(); async move { match (kind, hash.map(|ScriptHash(id)| id)) { - (FlowDependencies, Some(id)) => flow::fetch_version(e, id).await, - (FlowNode, Some(id)) => flow::fetch_flow(e, FlowNodeId(id)).await, - (Flow, Some(id)) => match flow::fetch_version_lite(e, id).await { + (FlowDependencies, Some(id)) => flow::fetch_version(db, id).await, + (FlowNode, Some(id)) => flow::fetch_flow(db, FlowNodeId(id)).await, + (Flow, Some(id)) => match flow::fetch_version_lite(db, id).await { Ok(raw_flow) => Ok(raw_flow), - Err(_) => flow::fetch_version(e, id).await, + Err(_) => flow::fetch_version(db, id).await, }, _ => Err(error::Error::internal_err(format!( "Isn't a flow job {:?}", diff --git a/backend/windmill-common/src/db.rs b/backend/windmill-common/src/db.rs index 96be430e73..47c698b05c 100644 --- a/backend/windmill-common/src/db.rs +++ b/backend/windmill-common/src/db.rs @@ -72,12 +72,6 @@ impl UserDB { where T: Authable, { - let user = if authed.is_admin() { - "windmill_admin" - } else { - "windmill_user" - }; - let (folders_write, folders_read): &(Vec<_>, Vec<_>) = &authed.folders().into_iter().partition(|x| x.1); @@ -95,10 +89,6 @@ impl UserDB { let mut tx = self.db.begin().await?; - sqlx::query(&format!("SET LOCAL ROLE {}", user)) - .execute(&mut *tx) - .await?; - if let Some(schema) = PG_SCHEMA.as_ref() { sqlx::query(&format!("SET LOCAL search_path TO {}", schema)) .execute(&mut *tx) @@ -106,53 +96,86 @@ impl UserDB { } sqlx::query!( - "SELECT set_config('session.user', $1, true)", - authed.username() - ) - .fetch_optional(&mut *tx) - .await?; - - sqlx::query!( - "SELECT set_config('session.groups', $1, true)", - &authed.groups().join(",") - ) - .fetch_optional(&mut *tx) - .await?; - - sqlx::query!( - "SELECT set_config('session.pgroups', $1, true)", - &authed + "SELECT set_session_context($1, $2, $3, $4, $5, $6)", + authed.is_admin(), + authed.username(), + authed.groups().join(","), + authed .groups() .iter() .map(|x| format!("g/{}", x)) .collect::>() - .join(",") - ) - .fetch_optional(&mut *tx) - .await?; - - sqlx::query!( - "SELECT set_config('session.folders_read', $1, true)", + .join(","), folders_read .iter() .map(|x| x.0.clone()) .collect::>() - .join(",") - ) - .fetch_optional(&mut *tx) - .await?; - - sqlx::query!( - "SELECT set_config('session.folders_write', $1, true)", + .join(","), folders_write .iter() .map(|x| x.0.clone()) .collect::>() .join(",") ) - .fetch_optional(&mut *tx) + .execute(&mut *tx) .await?; + // set_session_context( + // username TEXT, + // groups TEXT, + // pgroups TEXT, + // folders_read TEXT, + // folders_write TEXT + // ) + + // sqlx::query!( + // "SELECT set_config('session.user', $1, true)", + // authed.username() + // ) + // .fetch_optional(&mut *tx) + // .await?; + + // sqlx::query!( + // "SELECT set_config('session.groups', $1, true)", + // &authed.groups().join(",") + // ) + // .fetch_optional(&mut *tx) + // .await?; + + // sqlx::query!( + // "SELECT set_config('session.pgroups', $1, true)", + // &authed + // .groups() + // .iter() + // .map(|x| format!("g/{}", x)) + // .collect::>() + // .join(",") + // ) + // .fetch_optional(&mut *tx) + // .await?; + + // sqlx::query!( + // "SELECT set_config('session.folders_read', $1, true)", + // folders_read + // .iter() + // .map(|x| x.0.clone()) + // .collect::>() + // .join(",") + // ) + // .fetch_optional(&mut *tx) + // .await?; + + // sqlx::query!( + // "SELECT set_config('session.folders_write', $1, true)", + // folders_write + // .iter() + // .map(|x| x.0.clone()) + // .collect::>() + // .join(",") + // ) + // .fetch_optional(&mut *tx) + // .await?; + Ok(tx) } } diff --git a/backend/windmill-common/src/error.rs b/backend/windmill-common/src/error.rs index 59c3ca6420..feced2b6d5 100644 --- a/backend/windmill-common/src/error.rs +++ b/backend/windmill-common/src/error.rs @@ -22,6 +22,8 @@ pub type JsonResult = std::result::Result, Error>; #[derive(Debug, Error)] pub enum Error { + #[error("Bad gateway: {0}")] + BadGateway(String), #[error("Bad config: {0}")] BadConfig(String), #[error("Connecting to database: {0}")] @@ -69,13 +71,15 @@ pub enum Error { #[error("Error: {0:#?}")] JsonErr(serde_json::Value), #[error("{0}")] - AiError(String), + AIError(String), #[error("{0}")] AlreadyCompleted(String), #[error("Find python error: {0}")] FindPythonError(String), #[error("Problem with arguments: {0}")] ArgumentErr(String), + #[error("{1}")] + Generic(StatusCode, String), } fn prettify_location(location: &'static Location<'static>) -> String { @@ -173,26 +177,29 @@ pub fn to_anyhow(e: T) -> anyhow:: impl IntoResponse for Error { fn into_response(self) -> axum::response::Response { - let e = &self; - let body = Body::from(e.to_string()); - let status = match self { Self::NotFound(_) => axum::http::StatusCode::NOT_FOUND, Self::NotAuthorized(_) => axum::http::StatusCode::UNAUTHORIZED, Self::RequireAdmin(_) => axum::http::StatusCode::FORBIDDEN, Self::SqlErr { .. } | Self::BadRequest(_) - | Self::AiError(_) + | Self::AIError(_) | Self::QuotaExceeded(_) => axum::http::StatusCode::BAD_REQUEST, + Self::BadGateway(_) => axum::http::StatusCode::BAD_GATEWAY, + Self::Generic(status_code, _) => status_code, _ => axum::http::StatusCode::INTERNAL_SERVER_ERROR, }; + let e = &self; + if matches!(status, axum::http::StatusCode::NOT_FOUND) { tracing::warn!(message = e.to_string()); } else { tracing::error!(message = e.to_string(), error = ?e); }; + let body = Body::from(e.to_string()); + axum::response::Response::builder() .header("Content-Type", "text/plain") .status(status) diff --git a/backend/windmill-common/src/flows.rs b/backend/windmill-common/src/flows.rs index ab0e714968..1f6c265e7d 100644 --- a/backend/windmill-common/src/flows.rs +++ b/backend/windmill-common/src/flows.rs @@ -22,7 +22,7 @@ use crate::{ error::Error, more_serde::{default_empty_string, default_id, default_null, default_true, is_default}, scripts::{Schema, ScriptHash, ScriptLang}, - worker::to_raw_value, + worker::{to_raw_value, Connection}, DB, }; #[derive(Serialize, Deserialize, sqlx::FromRow)] @@ -731,7 +731,7 @@ pub async fn resolve_maybe_value( } /// Resolve modules recursively. -pub async fn resolve_value( +async fn resolve_value( e: &sqlx::PgPool, workspace_id: &str, value: &mut Box, @@ -749,7 +749,7 @@ pub async fn resolve_value( /// Resolve module value recursively. pub async fn resolve_module( - e: &sqlx::PgPool, + db: &DB, workspace_id: &str, value: &mut Box, with_code: bool, @@ -783,7 +783,7 @@ pub async fn resolve_module( let (lock, content) = if !with_code { (Some("...".to_string()), "...".to_string()) } else { - cache::flow::fetch_script(e, id) + cache::flow::fetch_script(&Connection::Sql(db.clone()), id) .await .map(|data| (data.lock.clone(), data.code.clone()))? }; @@ -801,13 +801,13 @@ pub async fn resolve_module( }; } ForloopFlow { modules, modules_node, .. } | WhileloopFlow { modules, modules_node, .. } => { - resolve_modules(e, workspace_id, modules, modules_node.take(), with_code).await?; + resolve_modules(db, workspace_id, modules, modules_node.take(), with_code).await?; } BranchOne { branches, default, default_node } => { - resolve_modules(e, workspace_id, default, default_node.take(), with_code).await?; + resolve_modules(db, workspace_id, default, default_node.take(), with_code).await?; for branch in branches { resolve_modules( - e, + db, workspace_id, &mut branch.modules, branch.modules_node.take(), @@ -819,7 +819,7 @@ pub async fn resolve_module( BranchAll { branches, .. } => { for branch in branches { resolve_modules( - e, + db, workspace_id, &mut branch.modules, branch.modules_node.take(), diff --git a/backend/windmill-common/src/global_settings.rs b/backend/windmill-common/src/global_settings.rs index e0c091a0da..109a0f6056 100644 --- a/backend/windmill-common/src/global_settings.rs +++ b/backend/windmill-common/src/global_settings.rs @@ -11,6 +11,8 @@ pub const LICENSE_KEY_SETTING: &str = "license_key"; pub const NPM_CONFIG_REGISTRY_SETTING: &str = "npm_config_registry"; pub const BUNFIG_INSTALL_SCOPES_SETTING: &str = "bunfig_install_scopes"; pub const NUGET_CONFIG_SETTING: &str = "nuget_config"; +pub const MAVEN_REPOS_SETTING: &str = "maven_repos"; +pub const NO_DEFAULT_MAVEN_SETTING: &str = "no_default_maven"; pub const EXTRA_PIP_INDEX_URL_SETTING: &str = "pip_extra_index_url"; pub const PIP_INDEX_URL_SETTING: &str = "pip_index_url"; @@ -61,6 +63,8 @@ pub const ENV_SETTINGS: &[&str] = &[ "NU_PATH", "DENO_PATH", "GO_PATH", + "JAVA_PATH", + // for related places search: ADD_NEW_LANG "GOPRIVATE", "GOPROXY", "NETRC", diff --git a/backend/windmill-common/src/jobs.rs b/backend/windmill-common/src/jobs.rs index 49de1c2415..6cad6579fb 100644 --- a/backend/windmill-common/src/jobs.rs +++ b/backend/windmill-common/src/jobs.rs @@ -10,6 +10,7 @@ use tokio::io::AsyncReadExt; use uuid::Uuid; pub const ENTRYPOINT_OVERRIDE: &str = "_ENTRYPOINT_OVERRIDE"; +pub const LARGE_LOG_THRESHOLD_SIZE: usize = 9000; use crate::{ apps::AppScriptId, @@ -24,7 +25,7 @@ use crate::{ #[derive(sqlx::Type, Serialize, Deserialize, Debug, PartialEq, Copy, Clone)] #[sqlx(type_name = "JOB_KIND", rename_all = "lowercase")] -#[serde(rename_all(serialize = "lowercase"))] +#[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))] pub enum JobKind { Script, #[allow(non_camel_case_types)] @@ -51,6 +52,13 @@ impl JobKind { JobKind::Flow | JobKind::FlowPreview | JobKind::SingleScriptFlow | JobKind::FlowNode ) } + + pub fn is_dependency(&self) -> bool { + matches!( + self, + JobKind::FlowDependencies | JobKind::AppDependencies | JobKind::Dependencies + ) + } } #[derive(sqlx::FromRow, Debug, Serialize, Clone)] diff --git a/backend/windmill-common/src/jwt.rs b/backend/windmill-common/src/jwt.rs index be93ed6614..8ebdb8dacb 100644 --- a/backend/windmill-common/src/jwt.rs +++ b/backend/windmill-common/src/jwt.rs @@ -1,6 +1,6 @@ use crate::error::{self, to_anyhow, Error}; use serde::{de::DeserializeOwned, Serialize}; -use std::sync::Arc; +use std::{collections::HashSet, sync::Arc}; use tokio::sync::RwLock; lazy_static::lazy_static! { @@ -40,3 +40,20 @@ pub async fn decode_with_internal_secret(token: &str) -> er Ok(result.claims) } + +pub fn decode_without_verify(token: &str) -> anyhow::Result { + // Create a validation that skips all checks + let mut validation = jsonwebtoken::Validation::default(); + validation.insecure_disable_signature_validation(); + validation.validate_exp = false; + validation.validate_nbf = false; + validation.required_spec_claims = HashSet::new(); + + // Use an empty key since we're not verifying + let key = jsonwebtoken::DecodingKey::from_secret(&[]); + + // Decode the token + let token_data = jsonwebtoken::decode::(token, &key, &validation)?; + + Ok(token_data.claims) +} diff --git a/backend/windmill-common/src/lib.rs b/backend/windmill-common/src/lib.rs index ca00da879a..0d2c746d3e 100644 --- a/backend/windmill-common/src/lib.rs +++ b/backend/windmill-common/src/lib.rs @@ -22,8 +22,11 @@ use error::Error; use scripts::ScriptLang; use sqlx::{Pool, Postgres}; +pub mod agent_workers; pub mod apps; pub mod auth; +#[cfg(feature = "benchmark")] +pub mod bench; pub mod cache; pub mod db; pub mod ee; @@ -37,6 +40,7 @@ pub mod indexer; pub mod job_metrics; #[cfg(feature = "parquet")] pub mod job_s3_helpers_ee; + pub mod jobs; pub mod jwt; pub mod more_serde; @@ -45,6 +49,7 @@ pub mod otel_ee; pub mod queue; pub mod s3_helpers; pub mod schedule; +pub mod schema; pub mod scripts; pub mod server; pub mod stats_ee; @@ -55,7 +60,6 @@ pub mod utils; pub mod variables; pub mod worker; pub mod workspaces; -pub mod schema; pub const DEFAULT_MAX_CONNECTIONS_SERVER: u32 = 50; pub const DEFAULT_MAX_CONNECTIONS_WORKER: u32 = 5; diff --git a/backend/windmill-common/src/s3_helpers.rs b/backend/windmill-common/src/s3_helpers.rs index 2c5a76a2e1..e3dff5350c 100644 --- a/backend/windmill-common/src/s3_helpers.rs +++ b/backend/windmill-common/src/s3_helpers.rs @@ -111,13 +111,15 @@ pub struct S3AwsOidcResource { pub audience: Option, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Default)] pub struct S3Object { pub s3: String, #[serde(skip_serializing_if = "Option::is_none")] pub storage: Option, #[serde(skip_serializing_if = "Option::is_none")] pub filename: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub presigned: Option, } #[cfg(feature = "parquet")] diff --git a/backend/windmill-common/src/schedule.rs b/backend/windmill-common/src/schedule.rs index b655f35c76..e78d3a211c 100644 --- a/backend/windmill-common/src/schedule.rs +++ b/backend/windmill-common/src/schedule.rs @@ -53,6 +53,8 @@ pub struct Schedule { #[serde(skip_serializing_if = "Option::is_none")] pub summary: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub tag: Option, #[serde(skip_serializing_if = "Option::is_none")] pub paused_until: Option>, diff --git a/backend/windmill-common/src/schema.rs b/backend/windmill-common/src/schema.rs index 4b97f761ae..2b24ead0d3 100644 --- a/backend/windmill-common/src/schema.rs +++ b/backend/windmill-common/src/schema.rs @@ -345,27 +345,15 @@ fn find_annotation(comm_lit: &str, annotation: &str, code: &str) -> bool { pub fn should_validate_schema(code: &str, lang: &ScriptLang) -> bool { let annotation = "schema_validation"; - match lang { - ScriptLang::Nativets | ScriptLang::Bun | ScriptLang::Bunnative | ScriptLang::Deno => { - find_annotation("//", annotation, code) - } - ScriptLang::Python3 => find_annotation("#", annotation, code), - ScriptLang::Go => find_annotation("#", annotation, code), - ScriptLang::Bash => find_annotation("#", annotation, code), - ScriptLang::Powershell => find_annotation("#", annotation, code), - ScriptLang::Postgresql => find_annotation("--", annotation, code), - ScriptLang::Mysql => find_annotation("--", annotation, code), - ScriptLang::Bigquery => find_annotation("--", annotation, code), - ScriptLang::Snowflake => find_annotation("--", annotation, code), - ScriptLang::Graphql => find_annotation("#", annotation, code), - ScriptLang::Mssql => find_annotation("--", annotation, code), - ScriptLang::OracleDB => find_annotation("--", annotation, code), - ScriptLang::Php => find_annotation("//", annotation, code), - ScriptLang::Rust => find_annotation("//!", annotation, code), - ScriptLang::Ansible => find_annotation("#", annotation, code), - ScriptLang::CSharp => find_annotation("//", annotation, code), - ScriptLang::Nu => find_annotation("#", annotation, code), - } + use ScriptLang::*; + let comment = match lang { + Nativets | Bun | Bunnative | Deno | Php | CSharp | Java => "//", + Python3 | Go | Bash | Powershell | Graphql | Ansible | Nu => "#", + Postgresql | Mysql | Bigquery | Snowflake | Mssql | OracleDB => "--", + Rust => "//!", + // for related places search: ADD_NEW_LANG + }; + find_annotation(comment, annotation, code) } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/backend/windmill-common/src/scripts.rs b/backend/windmill-common/src/scripts.rs index b38598f0b8..82491a52a4 100644 --- a/backend/windmill-common/src/scripts.rs +++ b/backend/windmill-common/src/scripts.rs @@ -51,6 +51,8 @@ pub enum ScriptLang { Ansible, CSharp, Nu, + Java, + // for related places search: ADD_NEW_LANG } impl ScriptLang { @@ -76,6 +78,8 @@ impl ScriptLang { ScriptLang::Ansible => "ansible", ScriptLang::CSharp => "csharp", ScriptLang::Nu => "nu", + ScriptLang::Java => "java", + // for related places search: ADD_NEW_LANG } } } diff --git a/backend/windmill-common/src/tracing_init.rs b/backend/windmill-common/src/tracing_init.rs index 5e6ef6940e..5ed5cec752 100644 --- a/backend/windmill-common/src/tracing_init.rs +++ b/backend/windmill-common/src/tracing_init.rs @@ -60,8 +60,11 @@ pub fn initialize_tracing( "RUST_LOG", &format!("windmill={}", rust_log_env.as_ref().unwrap()), ) - } - let default_env_filter = if rust_log_env.is_ok_and(|x| x == "debug") { + } else if rust_log_env.as_ref().is_ok_and(|x| x == "sqlxdebug") { + std::env::set_var("RUST_LOG", "windmill=debug,sqlx=debug"); + }; + + let default_env_filter = if rust_log_env.is_ok_and(|x| x == "debug" || x == "sqlxdebug") { LevelFilter::DEBUG } else { LevelFilter::INFO diff --git a/backend/windmill-common/src/utils.rs b/backend/windmill-common/src/utils.rs index 539064fcf1..5018591072 100644 --- a/backend/windmill-common/src/utils.rs +++ b/backend/windmill-common/src/utils.rs @@ -23,7 +23,7 @@ use rand::distr::Alphanumeric; use rand::{rng, Rng}; use reqwest::Client; use semver::Version; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use sha2::{Digest, Sha256}; use sqlx::{Pool, Postgres}; use std::str::FromStr; @@ -75,8 +75,8 @@ lazy_static::lazy_static! { if std::env::var("BASE_INTERNAL_URL").is_err() { panic!("BASE_INTERNAL_URL is required in agent mode") } - if std::env::var("JOB_TOKEN").is_err() { - println!("JOB_TOKEN is not passed, hence workers will still need to create permissions for each job and the DATABASE_URL needs to be of a role that can INSERT into the job_perms table") + if std::env::var("AGENT_TOKEN").is_err() { + println!("AGENT_TOKEN is not passed. This is required for the agent to work and contains the JWT to authenticate with the server.") } #[cfg(not(feature = "enterprise"))] @@ -175,6 +175,28 @@ pub fn hostname() -> String { }) } +fn instance_name(hostname: &str) -> String { + hostname + .replace(" ", "") + .split("-") + .last() + .unwrap() + .to_ascii_lowercase() + .to_string() +} + +pub fn worker_suffix(hostname: &str, rd_string: &str) -> String { + format!("{}-{}", instance_name(hostname), rd_string) +} + +pub fn worker_name_with_suffix(is_agent: bool, worker_group: &str, suffix: &str) -> String { + if is_agent { + format!("ag-{}-{}", worker_group, suffix) + } else { + format!("wk-{}-{}", worker_group, suffix) + } +} + pub fn paginate(pagination: Pagination) -> (usize, usize) { let per_page = pagination .per_page @@ -446,6 +468,16 @@ pub async fn report_recovered_critical_error( } } +pub fn empty_string_as_none<'de, D>( + deserializer: D, +) -> std::result::Result, D::Error> +where + D: Deserializer<'de>, +{ + let option = as serde::Deserialize>::deserialize(deserializer)?; + Ok(option.filter(|s| !s.is_empty())) +} + pub async fn fetch_mute_workspace(_db: &DB, workspace_id: &str) -> Result { match sqlx::query!( "SELECT mute_critical_alerts FROM workspace_settings WHERE workspace_id = $1", diff --git a/backend/windmill-common/src/variables.rs b/backend/windmill-common/src/variables.rs index 90baec78a5..3fd2e0513b 100644 --- a/backend/windmill-common/src/variables.rs +++ b/backend/windmill-common/src/variables.rs @@ -7,6 +7,7 @@ */ use crate::error; +use crate::worker::Connection; use crate::{worker::WORKER_GROUP, BASE_URL, DB}; use chrono::{SecondsFormat, Utc}; use magic_crypt::{MagicCrypt256, MagicCryptError, MagicCryptTrait}; @@ -166,7 +167,7 @@ lazy_static::lazy_static! { } pub async fn get_reserved_variables( - db: &DB, + conn: &Connection, w_id: &str, token: &str, email: &str, @@ -206,7 +207,7 @@ pub async fn get_reserved_variables( } }; - let custom_envs = get_cached_workspace_envs(db, w_id).await; + let custom_envs = get_cached_workspace_envs(conn, w_id).await; let joined_schedule_path = schedule_path .clone() @@ -354,10 +355,7 @@ pub async fn get_reserved_variables( ).collect() } -async fn get_cached_workspace_envs( - db: &sqlx::Pool, - w_id: &str, -) -> Vec<(String, String)> { +async fn get_cached_workspace_envs(conn: &Connection, w_id: &str) -> Vec<(String, String)> { let cached_envs_o = CUSTOM_ENVS_CACHE.get(w_id).and_then(|(ts, envs)| { if ts > chrono::Utc::now().timestamp() - (60 * 15) { Some(envs) @@ -369,13 +367,19 @@ async fn get_cached_workspace_envs( let custom_envs = if let Some(cached_envs) = cached_envs_o { cached_envs } else { - let custom_envs = sqlx::query_as::<_, (String, String)>( - "SELECT name, value FROM workspace_env WHERE workspace_id = $1", - ) - .bind(w_id) - .fetch_all(db) - .await - .unwrap_or_default(); + let custom_envs = match conn { + Connection::Sql(db) => sqlx::query_as::<_, (String, String)>( + "SELECT name, value FROM workspace_env WHERE workspace_id = $1", + ) + .bind(w_id) + .fetch_all(db) + .await + .unwrap_or_default(), + Connection::Http(client) => client + .get(&format!("/api/w/{w_id}/agent_workers/custom_envs")) + .await + .unwrap_or_default(), + }; CUSTOM_ENVS_CACHE.insert( w_id.to_string(), (chrono::Utc::now().timestamp(), custom_envs.clone()), diff --git a/backend/windmill-common/src/worker.rs b/backend/windmill-common/src/worker.rs index d432ce6a49..b65b50a33a 100644 --- a/backend/windmill-common/src/worker.rs +++ b/backend/windmill-common/src/worker.rs @@ -3,28 +3,55 @@ use bytes::Bytes; use const_format::concatcp; use itertools::Itertools; use regex::Regex; +use reqwest_middleware::ClientWithMiddleware; use semver::Version; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::value::RawValue; +use sqlx::{types::Json, Pool, Postgres}; use std::{ cmp::Reverse, collections::{HashMap, HashSet}, - fs::File, + fs::{self, File}, io::Write, + panic::Location, path::{Component, Path, PathBuf}, str::FromStr, sync::{atomic::AtomicBool, Arc}, }; use tokio::sync::RwLock; +use uuid::Uuid; use windmill_macros::annotations; use crate::{ - error, global_settings::CUSTOM_TAGS_SETTING, indexer::TantivyIndexerSettings, server::Smtp, + agent_workers::{PingJobStatusResponse, BASE_INTERNAL_URL}, + cache::{unwrap_or_error, RawNode, RawScript}, + error::{self, to_anyhow}, + global_settings::CUSTOM_TAGS_SETTING, + indexer::TantivyIndexerSettings, + server::Smtp, KillpillSender, DB, }; +pub const DEFAULT_CLOUD_TIMEOUT: u64 = 900; +pub const DEFAULT_SELFHOSTED_TIMEOUT: u64 = 604800; // 7 days + lazy_static::lazy_static! { - pub static ref WORKER_GROUP: String = std::env::var("WORKER_GROUP").unwrap_or_else(|_| "default".to_string()); + pub static ref WORKER_GROUP: String = std::env::var("WORKER_GROUP").unwrap_or_else(|_| { + #[cfg(not(feature = "enterprise"))] + { + "default".to_string() + } + + #[cfg(feature = "enterprise")] + { + if let Some(token) = crate::agent_workers::DECODED_AGENT_TOKEN.as_ref() { + token.worker_group.clone() + } else { + "default".to_string() + } + } + }); + pub static ref NO_LOGS: bool = std::env::var("NO_LOGS").ok().is_some_and(|x| x == "1" || x == "true"); pub static ref CGROUP_V2_PATH_RE: Regex = Regex::new(r#"(?m)^0::(/.*)$"#).unwrap(); @@ -51,6 +78,8 @@ lazy_static::lazy_static! { "ansible".to_string(), "csharp".to_string(), "nu".to_string(), + "java".to_string(), + // for related places search: ADD_NEW_LANG "dependency".to_string(), "flow".to_string(), "other".to_string() @@ -59,6 +88,15 @@ lazy_static::lazy_static! { pub static ref DEFAULT_TAGS_PER_WORKSPACE: AtomicBool = AtomicBool::new(false); pub static ref DEFAULT_TAGS_WORKSPACES: Arc>>> = Arc::new(RwLock::new(None)); + pub static ref MAX_TIMEOUT: u64 = std::env::var("TIMEOUT") + .ok() + .and_then(|x| x.parse::().ok()) + .unwrap_or_else(|| if *CLOUD_HOSTED { DEFAULT_CLOUD_TIMEOUT } else { DEFAULT_SELFHOSTED_TIMEOUT }); + + pub static ref SCRIPT_TOKEN_EXPIRY: u64 = std::env::var("SCRIPT_TOKEN_EXPIRY") + .ok() + .and_then(|x| x.parse::().ok()) + .unwrap_or(*MAX_TIMEOUT); pub static ref WORKER_CONFIG: Arc> = Arc::new(RwLock::new(WorkerConfig { worker_tags: Default::default(), @@ -113,6 +151,90 @@ pub const ROOT_CACHE_NOMOUNT_DIR: &str = concatcp!(TMP_DIR, "/cache_nomount/"); pub static MIN_VERSION_IS_LATEST: AtomicBool = AtomicBool::new(false); +#[derive(Clone)] +pub struct HttpClient(pub ClientWithMiddleware); + +impl HttpClient { + pub async fn post( + &self, + url: &str, + body: &T, + ) -> anyhow::Result { + let response = self + .0 + .post(format!("{}{}", *BASE_INTERNAL_URL, url)) + .json(body) + .send() + .await + .map_err(|e| anyhow::anyhow!(e))?; + let status = response.status(); + if status.is_success() { + Ok(response.json().await?) + } else { + Err(anyhow::anyhow!(format!( + "HTTP agent request POST {} failed {}", + url, + response.status() + ))) + } + } + + pub async fn get(&self, url: &str) -> anyhow::Result { + let response = self + .0 + .get(format!("{}{}", *BASE_INTERNAL_URL, url)) + .send() + .await + .map_err(|e| anyhow::anyhow!(e))?; + let status = response.status(); + if status.is_success() { + Ok(response.json().await?) + } else { + Err(anyhow::anyhow!(format!( + "HTTP agent request GET {} failed {}", + url, + response.status() + ))) + } + } +} + +#[derive(Clone)] +pub enum Connection { + Sql(Pool), + Http(HttpClient), +} + +impl std::fmt::Debug for Connection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Connection::Sql(_) => write!(f, "Sql"), + Connection::Http(_) => write!(f, "Http"), + } + } +} + +impl Connection { + pub fn as_sql(&self) -> Option<&Pool> { + match self { + Connection::Sql(db) => Some(db), + Connection::Http(_) => None, + } + } +} + +impl From> for Connection { + fn from(value: Pool) -> Self { + Connection::Sql(value) + } +} + +impl From<&Pool> for Connection { + fn from(value: &Pool) -> Self { + Connection::Sql(value.clone()) + } +} + fn format_pull_query(peek: String) -> String { let r = format!( "WITH peek AS ( @@ -144,13 +266,13 @@ fn format_pull_query(peek: String) -> String { WHERE id = (SELECT id FROM peek) ) SELECT j.id, j.workspace_id, j.parent_job, j.created_by, started_at, scheduled_for, j.runnable_id, j.runnable_path, j.args, canceled_by, - canceled_reason, j.kind, j.trigger, j.trigger_kind, j.permissioned_as, j.permissioned_as_email, + canceled_reason, j.kind, j.trigger, j.trigger_kind, j.permissioned_as, flow_status, j.script_lang, j.same_worker, j.pre_run_error, j.visible_to_owner, j.tag, j.concurrent_limit, j.concurrency_time_window_s, j.flow_innermost_root_job, j.timeout, j.flow_step_id, j.cache_ttl, j.priority, j.raw_code, j.raw_lock, j.raw_flow, j.script_entrypoint_override, j.preprocessed, pj.runnable_path as parent_runnable_path, - p.email as permissioned_as_email, p.username as permissioned_as_username, p.is_admin as permissioned_as_is_admin, + COALESCE(p.email, j.permissioned_as_email) as permissioned_as_email, p.username as permissioned_as_username, p.is_admin as permissioned_as_is_admin, p.is_operator as permissioned_as_is_operator, p.groups as permissioned_as_groups, p.folders as permissioned_as_folders FROM q, j LEFT JOIN v2_job_status f USING (id) @@ -162,40 +284,48 @@ fn format_pull_query(peek: String) -> String { r } -pub async fn make_suspended_pull_query(wc: &WorkerConfig) { - if wc.worker_tags.len() == 0 { - tracing::error!("Empty tags in worker tags, skipping"); - return; - } - let query = format_pull_query(format!( +pub fn make_suspended_pull_query(tags: &[String]) -> String { + format_pull_query(format!( "SELECT id FROM v2_job_queue WHERE suspend_until IS NOT NULL AND (suspend <= 0 OR suspend_until <= now()) AND tag IN ({}) ORDER BY priority DESC NULLS LAST, created_at FOR UPDATE SKIP LOCKED LIMIT 1", - wc.worker_tags.iter().map(|x| format!("'{x}'")).join(", ") - )); + tags.iter().map(|x| format!("'{x}'")).join(", ") + )) +} +// pub async fn make_suspended +pub async fn store_suspended_pull_query(wc: &WorkerConfig) { + if wc.worker_tags.len() == 0 { + tracing::error!("Empty tags in worker tags, skipping"); + return; + } + let query = make_suspended_pull_query(&wc.worker_tags); let mut l = WORKER_SUSPENDED_PULL_QUERY.write().await; *l = query; } -pub async fn make_pull_query(wc: &WorkerConfig) { +pub fn make_pull_query(tags: &[String]) -> String { + format_pull_query(format!( + "SELECT id + FROM v2_job_queue + WHERE running = false AND tag IN ({}) AND scheduled_for <= now() + ORDER BY priority DESC NULLS LAST, scheduled_for + FOR UPDATE SKIP LOCKED + LIMIT 1", + tags.iter().map(|x| format!("'{x}'")).join(", ") + )) +} + +pub async fn store_pull_query(wc: &WorkerConfig) { let mut queries = vec![]; for tags in wc.priority_tags_sorted.iter() { if tags.tags.len() == 0 { tracing::error!("Empty tags in priority tags, skipping"); continue; } - let query = format_pull_query(format!( - "SELECT id - FROM v2_job_queue - WHERE running = false AND tag IN ({}) AND scheduled_for <= now() - ORDER BY priority DESC NULLS LAST, scheduled_for - FOR UPDATE SKIP LOCKED - LIMIT 1", - tags.tags.iter().map(|x| format!("'{x}'")).join(", ") - )); + let query = make_pull_query(&tags.tags); queries.push(query); } let mut l = WORKER_PULL_QUERIES.write().await; @@ -412,8 +542,43 @@ pub struct SqlAnnotations { pub struct BashAnnotations { pub docker: bool, } +/// length = 5 +/// value = "foo" +/// output = "foo " +/// 12345 +pub fn pad_string(value: &str, total_length: usize) -> String { + if value.len() >= total_length { + value.to_string() // Return the original string if it's already long enough + } else { + let padding_needed = total_length - value.len(); + format!("{value}{}", " ".repeat(padding_needed)) // Pad with spaces + } +} +pub fn copy_dir_recursively(src: &Path, dst: &Path) -> error::Result<()> { + if !dst.exists() { + fs::create_dir_all(dst)?; + } -pub async fn load_cache(bin_path: &str, _remote_path: &str) -> (bool, String) { + tracing::debug!("Copying recursively from {:?} to {:?}", src, dst); + + for entry in fs::read_dir(src)? { + let entry = entry?; + let src_path = entry.path(); + let dst_path = dst.join(entry.file_name()); + + if src_path.is_dir() && !src_path.is_symlink() { + copy_dir_recursively(&src_path, &dst_path)?; + } else { + fs::copy(&src_path, &dst_path)?; + } + } + + tracing::debug!("Finished copying recursively from {:?} to {:?}", src, dst); + + Ok(()) +} + +pub async fn load_cache(bin_path: &str, _remote_path: &str, is_dir: bool) -> (bool, String) { if tokio::fs::metadata(&bin_path).await.is_ok() { (true, format!("loaded from local cache: {}\n", bin_path)) } else { @@ -427,12 +592,22 @@ pub async fn load_cache(bin_path: &str, _remote_path: &str) -> (bool, String) { use crate::s3_helpers::attempt_fetch_bytes; if let Ok(mut x) = attempt_fetch_bytes(os, _remote_path).await { - if let Err(e) = write_binary_file(bin_path, &mut x) { - tracing::error!("could not write bundle/bin file locally: {e:?}"); - return ( - false, - "error writing bundle/bin file from object store".to_string(), - ); + if is_dir { + if let Err(e) = extract_tar(x, bin_path).await { + tracing::error!("could not write tar archive locally: {e:?}"); + return ( + false, + "error writing tar archive from object store".to_string(), + ); + } + } else { + if let Err(e) = write_binary_file(bin_path, &mut x) { + tracing::error!("could not write bundle/bin file locally: {e:?}"); + return ( + false, + "error writing bundle/bin file from object store".to_string(), + ); + } } tracing::info!("loaded from object store {}", bin_path); return ( @@ -445,6 +620,7 @@ pub async fn load_cache(bin_path: &str, _remote_path: &str) -> (bool, String) { ); } } + let _ = is_dir; (false, "".to_string()) } } @@ -472,6 +648,7 @@ pub async fn save_cache( local_cache_path: &str, _remote_cache_path: &str, origin: &str, + is_dir: bool, ) -> crate::error::Result { let mut _cached_to_s3 = false; #[cfg(all(feature = "enterprise", feature = "parquet"))] @@ -481,11 +658,33 @@ pub async fn save_cache( .clone() { use object_store::path::Path; + let file_to_cache = if is_dir { + let tar_path = format!( + "{ROOT_CACHE_DIR}/tar/{}_tar.tar", + local_cache_path + .split("/") + .last() + .unwrap_or(&uuid::Uuid::new_v4().to_string()) + ); + let tar_file = std::fs::File::create(&tar_path)?; + let mut tar = tar::Builder::new(tar_file); + tar.append_dir_all(".", &origin)?; + let tar_metadata = tokio::fs::metadata(&tar_path).await; + if tar_metadata.is_err() || tar_metadata.as_ref().unwrap().len() == 0 { + tracing::info!("Failed to tar cache: {origin}"); + return Err(error::Error::ExecutionErr(format!( + "Failed to tar cache: {origin}" + ))); + } + tar_path + } else { + origin.to_owned() + }; if let Err(e) = os .put( &Path::from(_remote_cache_path), - std::fs::read(origin)?.into(), + std::fs::read(&file_to_cache)?.into(), ) .await { @@ -495,12 +694,19 @@ pub async fn save_cache( ); } else { _cached_to_s3 = true; + if is_dir { + tokio::fs::remove_dir_all(&file_to_cache).await?; + } } } // if !*CLOUD_HOSTED { if true { - std::fs::copy(origin, local_cache_path)?; + if is_dir { + copy_dir_recursively(&PathBuf::from(origin), &PathBuf::from(local_cache_path))?; + } else { + std::fs::copy(origin, local_cache_path)?; + } Ok(format!( "\nwrote cached binary: {} (backed by EE distributed object store: {_cached_to_s3})\n", local_cache_path @@ -515,6 +721,31 @@ pub async fn save_cache( } } +#[cfg(all(feature = "enterprise", feature = "parquet"))] +pub async fn extract_tar(tar: bytes::Bytes, folder: &str) -> error::Result<()> { + use std::time::Instant; + + use bytes::Buf; + use tokio::fs::{self}; + + let start: Instant = Instant::now(); + fs::create_dir_all(&folder).await?; + + let mut ar = tar::Archive::new(tar.reader()); + + if let Err(e) = ar.unpack(folder) { + tracing::info!("Failed to untar to {folder}. Error: {:?}", e); + fs::remove_dir_all(&folder).await?; + return Err(error::Error::ExecutionErr(format!( + "Failed to untar tar {folder}" + ))); + } + tracing::info!( + "Finished extracting tar to {folder}. Took {}ms", + start.elapsed().as_millis(), + ); + Ok(()) +} #[cfg(all(feature = "enterprise", feature = "parquet"))] fn write_binary_file(main_path: &str, byts: &mut bytes::Bytes) -> error::Result<()> { use std::fs::{File, Permissions}; @@ -665,24 +896,33 @@ pub fn get_windmill_memory_usage() -> Option { } } -pub async fn update_min_version<'c, E: sqlx::Executor<'c, Database = sqlx::Postgres>>( - executor: E, -) -> bool { +pub async fn update_min_version(conn: &Connection) -> bool { use crate::utils::{GIT_SEM_VERSION, GIT_VERSION}; - // fetch all pings with a different version than self from the last 5 minutes. - let pings = sqlx::query_scalar!( - "SELECT wm_version FROM worker_ping WHERE wm_version != $1 AND ping_at > now() - interval '5 minutes'", - GIT_VERSION - ).fetch_all(executor).await.unwrap_or_default(); - let cur_version = GIT_SEM_VERSION.clone(); - let min_version = pings - .iter() - .filter(|x| !x.is_empty()) - .filter_map(|x| semver::Version::parse(if x.starts_with('v') { &x[1..] } else { x }).ok()) - .min() - .unwrap_or_else(|| cur_version.clone()); + + let min_version = match conn { + Connection::Sql(pool) => { + // fetch all pings with a different version than self from the last 5 minutes. + let pings = sqlx::query_scalar!( + "SELECT wm_version FROM worker_ping WHERE wm_version != $1 AND ping_at > now() - interval '5 minutes'", + GIT_VERSION + ).fetch_all(pool).await.unwrap_or_default(); + + pings + .iter() + .filter(|x| !x.is_empty()) + .filter_map(|x| { + semver::Version::parse(if x.starts_with('v') { &x[1..] } else { x }).ok() + }) + .min() + .unwrap_or_else(|| cur_version.clone()) + } + Connection::Http(_) => { + // TODO: get min version from server, for now we use the current version. Min version should be of no interest for http mode workers + cur_version.clone() + } + }; if min_version != cur_version { tracing::info!("Minimal worker version: {min_version}"); @@ -697,37 +937,330 @@ pub async fn update_min_version<'c, E: sqlx::Executor<'c, Database = sqlx::Postg min_version >= cur_version } -pub async fn update_ping(worker_instance: &str, worker_name: &str, ip: &str, db: &DB) { - let (tags, dw) = { - let wc = WORKER_CONFIG.read().await.clone(); - ( - wc.worker_tags, - wc.dedicated_worker - .as_ref() - .map(|x| format!("{}:{}", x.workspace_id, x.path)), - ) - }; +#[derive(Serialize, Deserialize)] +pub enum PingType { + Initial, + MainLoop, + Job, + InitScript, +} +#[derive(Serialize, Deserialize)] +pub struct Ping { + pub last_job_executed: Option, + pub last_job_workspace_id: Option, + pub worker_instance: Option, + pub ip: Option, + pub tags: Option>, + pub dw: Option, + pub version: Option, + pub vcpus: Option, + pub memory: Option, + pub memory_usage: Option, + pub wm_memory_usage: Option, + pub jobs_executed: Option, + pub occupancy_rate: Option, + pub occupancy_rate_15s: Option, + pub occupancy_rate_5m: Option, + pub occupancy_rate_30m: Option, + pub ping_type: PingType, +} +pub async fn update_ping_http( + insert_ping: Ping, + worker_name: &str, + worker_group: &str, + db: &DB, +) -> anyhow::Result<()> { + // tracing::info!("update ping: {}", insert_ping.tags.join(",")); + match insert_ping.ping_type { + PingType::MainLoop => { + update_worker_ping_main_loop_query( + worker_name, + insert_ping.tags.unwrap_or_default().as_slice(), + insert_ping.vcpus, + insert_ping.memory, + insert_ping.jobs_executed, + insert_ping.occupancy_rate, + insert_ping.memory_usage, + insert_ping.wm_memory_usage, + insert_ping.occupancy_rate_15s, + insert_ping.occupancy_rate_5m, + insert_ping.occupancy_rate_30m, + db, + ) + .await? + } + PingType::Initial => { + if insert_ping.worker_instance.is_none() + || insert_ping.version.is_none() + || insert_ping.ip.is_none() + { + return Err(anyhow::anyhow!( + "Worker instance, version and ip are required" + )); + } - let vcpus = get_vcpus(); - let memory = get_memory(); + insert_ping_query( + &insert_ping.worker_instance.unwrap(), + &worker_name, + worker_group, + &insert_ping.ip.unwrap(), + insert_ping.tags.unwrap_or_default().as_slice(), + insert_ping.dw, + &insert_ping.version.unwrap(), + insert_ping.vcpus, + insert_ping.memory, + db, + ) + .await?; + } + PingType::Job => { + update_worker_ping_from_job_query( + &insert_ping.last_job_executed.unwrap_or_default(), + &insert_ping.last_job_workspace_id.unwrap_or_default(), + worker_name, + insert_ping.memory_usage, + insert_ping.wm_memory_usage, + insert_ping.occupancy_rate, + insert_ping.occupancy_rate_15s, + insert_ping.occupancy_rate_5m, + insert_ping.occupancy_rate_30m, + db, + ) + .await?; + } + PingType::InitScript => { + update_ping_for_failed_init_script_query( + worker_name, + insert_ping.last_job_executed.unwrap_or_default(), + db, + ) + .await? + } + } + Ok(()) +} +#[derive(Serialize, Deserialize)] +pub struct JobCancelled { + pub canceled_by: String, + pub reason: String, +} + +pub async fn set_job_cancelled_query( + job_id: Uuid, + db: &DB, + canceled_by: &str, + reason: &str, +) -> anyhow::Result<()> { + sqlx::query!( + "UPDATE v2_job_queue + SET canceled_by = $1 + , canceled_reason = $2 +WHERE id = $3", + canceled_by, + reason, + job_id + ) + .execute(db) + .await?; + Ok(()) +} + +pub async fn update_ping_for_failed_init_script_query( + worker_name: &str, + last_job_id: Uuid, + db: &DB, +) -> anyhow::Result<()> { + sqlx::query!( + "UPDATE worker_ping SET +ping_at = now(), +jobs_executed = 1, +current_job_id = $1, +current_job_workspace_id = 'admins' +WHERE worker = $2", + last_job_id, + worker_name + ) + .execute(db) + .await?; + Ok(()) +} + +pub async fn fetch_flow_node_query( + db: &DB, + id: i64, + loc: &'static Location<'_>, +) -> error::Result { + let r = sqlx::query!( + "SELECT \ + code AS \"raw_code: String\", \ + lock AS \"raw_lock: String\", \ + flow AS \"raw_flow: Json>\" \ + FROM flow_node WHERE id = $1 LIMIT 1", + id, + ) + .fetch_optional(db) + .await + .map_err(Into::into) + .and_then(unwrap_or_error(loc, "Flow node", id)) + .map(|r| RawNode { + raw_code: r.raw_code, + raw_lock: r.raw_lock, + raw_flow: r.raw_flow.map(|Json(raw_flow)| raw_flow), + })?; + Ok(r) +} + +pub async fn fetch_raw_script_from_app_query( + db: &DB, + id: i64, + loc: &'static Location<'_>, +) -> error::Result { + sqlx::query!( + "SELECT lock, code FROM app_script WHERE id = $1 LIMIT 1", + id, + ) + .fetch_optional(db) + .await + .map_err(Into::into) + .and_then(unwrap_or_error(&loc, "Application script", id)) + .map(|r| RawScript { content: r.code, lock: r.lock, meta: None }) +} + +pub async fn insert_ping_query( + worker_instance: &str, + worker_name: &str, + worker_group: &str, + ip: &str, + tags: &[String], + dw: Option, + version: &str, + vcpus: Option, + memory: Option, + db: &DB, +) -> anyhow::Result<()> { sqlx::query!( "INSERT INTO worker_ping (worker_instance, worker, ip, custom_tags, worker_group, dedicated_worker, wm_version, vcpus, memory) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (worker) DO UPDATE set ip = $3, custom_tags = $4, worker_group = $5", worker_instance, worker_name, ip, - tags.as_slice(), - *WORKER_GROUP, + tags, + worker_group, dw, - crate::utils::GIT_VERSION, + version, vcpus, memory + ) + .execute(db) + .await?; + Ok(()) +} + +pub async fn update_worker_ping_from_job_query( + job_id: &Uuid, + w_id: &str, + worker_name: &str, + memory_usage: Option, + wm_memory_usage: Option, + occupancy_rate: Option, + occupancy_rate_15s: Option, + occupancy_rate_5m: Option, + occupancy_rate_30m: Option, + db: &DB, +) -> anyhow::Result<()> { + sqlx::query!( + "UPDATE worker_ping SET ping_at = now(), current_job_id = $1, current_job_workspace_id = $2, memory_usage = $3, wm_memory_usage = $4, + occupancy_rate = $6, occupancy_rate_15s = $7, occupancy_rate_5m = $8, occupancy_rate_30m = $9 WHERE worker = $5", + job_id, + w_id, + memory_usage, + wm_memory_usage, + worker_name, + occupancy_rate, + occupancy_rate_15s, + occupancy_rate_5m, + occupancy_rate_30m, ) .execute(db) - .await - .expect("insert worker_ping initial value"); + .await?; + Ok(()) } +pub async fn update_job_ping_query( + job_id: &Uuid, + db: &DB, + mem_peak: Option, +) -> anyhow::Result { + let ro = sqlx::query!( + "UPDATE v2_job_runtime r SET + memory_peak = $1, + ping = now() + FROM v2_job_queue q + WHERE r.id = $2 AND q.id = r.id + RETURNING canceled_by, canceled_reason", + mem_peak, + job_id + ) + .map(|x| PingJobStatusResponse { + canceled_by: x.canceled_by, + canceled_reason: x.canceled_reason, + already_completed: false, + }) + .fetch_optional(db) + .await; + + // TODO: add memory metrics to memory time series + + if let Ok(r) = ro { + if let Some(i) = r { + Ok(i) + } else { + Err(anyhow::anyhow!("Job not found")) + } + } else { + Err(to_anyhow(ro.unwrap_err())) + } +} + +pub async fn update_worker_ping_main_loop_query( + worker_name: &str, + tags: &[String], + vcpus: Option, + memory: Option, + jobs_executed: Option, + occupancy_rate: Option, + memory_usage: Option, + wm_memory_usage: Option, + occupancy_rate_15s: Option, + occupancy_rate_5m: Option, + occupancy_rate_30m: Option, + db: &DB, +) -> anyhow::Result<()> { + sqlx::query!( + "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2, + occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, vcpus = COALESCE($7, vcpus), + memory = COALESCE($8, memory), occupancy_rate_15s = $9, occupancy_rate_5m = $10, occupancy_rate_30m = $11 WHERE worker = $6", + jobs_executed, + tags, + occupancy_rate, + memory_usage, + wm_memory_usage, + worker_name, + vcpus, + memory, + occupancy_rate_15s, + occupancy_rate_5m, + occupancy_rate_30m, + ) + .execute(db) + .await?; + Ok(()) +} + +// "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2, +// occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, vcpus = COALESCE($7, vcpus), +// memory = COALESCE($8, memory), occupancy_rate_15s = $9, occupancy_rate_5m = $10, occupancy_rate_30m = $11 WHERE worker = $6", + pub async fn load_worker_config( db: &DB, killpill_tx: KillpillSender, @@ -925,7 +1458,7 @@ pub struct WorkspacedPath { pub path: String, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct WorkerConfigOpt { pub worker_tags: Option>, pub priority_tags: Option>, diff --git a/backend/windmill-queue/src/flow_status.rs b/backend/windmill-queue/src/flow_status.rs new file mode 100644 index 0000000000..3bc6b3c815 --- /dev/null +++ b/backend/windmill-queue/src/flow_status.rs @@ -0,0 +1,135 @@ +use uuid::Uuid; +use windmill_common::{ + error::{self, Error}, + utils::WarnAfterExt, + DB, +}; + +#[derive(Debug, Copy, Clone)] +pub enum Step { + Step(usize), + PreprocessorStep, + FailureStep, +} + +impl Step { + pub fn from_i32_and_len(step: i32, len: usize) -> Self { + if step < 0 { + Step::PreprocessorStep + } else if (step as usize) < len { + Step::Step(step as usize) + } else { + Step::FailureStep + } + } +} + +pub async fn update_flow_status_in_progress( + db: &DB, + _w_id: &str, + flow: Uuid, + job_in_progress: Uuid, +) -> error::Result { + let step = get_step_of_flow_status(db, flow).await?; + match step { + Step::Step(step) => { + sqlx::query!( + "UPDATE v2_job_status SET + flow_status = jsonb_set( + jsonb_set(flow_status, ARRAY['modules', $3::INTEGER::TEXT, 'job'], to_jsonb($1::UUID::TEXT)), + ARRAY['modules', $3::INTEGER::TEXT, 'type'], + to_jsonb('InProgress'::text) + ) + WHERE id = $2", + job_in_progress, + flow, + step as i32 + ) + .execute(db) + .await?; + } + Step::PreprocessorStep => { + sqlx::query!( + "UPDATE v2_job_status SET + flow_status = jsonb_set( + jsonb_set(flow_status, ARRAY['preprocessor_module', 'job'], to_jsonb($1::UUID::TEXT)), + ARRAY['preprocessor_module', 'type'], + to_jsonb('InProgress'::text) + ) + WHERE id = $2", + job_in_progress, + flow + ) + .execute(db) + .await?; + } + Step::FailureStep => { + sqlx::query!( + "UPDATE v2_job_status SET + flow_status = jsonb_set( + jsonb_set(flow_status, ARRAY['failure_module', 'job'], to_jsonb($1::UUID::TEXT)), + ARRAY['failure_module', 'type'], + to_jsonb('InProgress'::text) + ) + WHERE id = $2", + job_in_progress, + flow + ) + .execute(db) + .await?; + } + } + + Ok(step) +} + +pub async fn update_workflow_as_code_status( + db: &DB, + id: &Uuid, + parent_job: &Uuid, +) -> error::Result<()> { + let _ = sqlx::query_scalar!( + "UPDATE v2_job_status SET + workflow_as_code_status = jsonb_set( + jsonb_set( + COALESCE(workflow_as_code_status, '{}'::jsonb), + array[$1], + COALESCE(workflow_as_code_status->$1, '{}'::jsonb) + ), + array[$1, 'started_at'], + to_jsonb(now()::text) + ) + WHERE id = $2", + id.to_string(), + parent_job + ) + .execute(db) + .warn_after_seconds(5) + .await + .inspect_err(|e| { + tracing::error!( + "Could not update parent job `started_at` in workflow as code status: {}", + e + ) + }); + Ok(()) +} + +// TODO: merge as a CTE +#[tracing::instrument(level = "trace", skip_all)] +async fn get_step_of_flow_status(db: &DB, id: Uuid) -> error::Result { + let r = sqlx::query!( + "SELECT (flow_status->'step')::integer as step, jsonb_array_length(flow_status->'modules') as len + FROM v2_job_status WHERE id = $1", + id + ) + .fetch_one(db) + .await + .map_err(|e| Error::internal_err(format!("fetching step flow status: {e:#}")))?; + + if let Some(step) = r.step { + Ok(Step::from_i32_and_len(step, r.len.unwrap_or(0) as usize)) + } else { + Err(Error::internal_err("step is null".to_string())) + } +} diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index f62984942d..9c7dd8a4fc 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -7,7 +7,7 @@ */ use std::fmt; -use std::{borrow::Borrow, collections::HashMap, sync::Arc, vec}; +use std::{collections::HashMap, sync::Arc, vec}; use anyhow::Context; use async_recursion::async_recursion; @@ -29,7 +29,13 @@ use uuid::Uuid; use windmill_audit::audit_ee::{audit_log, AuditAuthor}; use windmill_audit::ActionKind; +#[cfg(feature = "benchmark")] +use windmill_common::add_time; +use windmill_common::auth::JobPerms; +#[cfg(feature = "benchmark")] +use windmill_common::bench::BenchmarkIter; use windmill_common::utils::now_from_db; +use windmill_common::worker::{Connection, SCRIPT_TOKEN_EXPIRY}; use windmill_common::{ auth::{fetch_authed_from_permissioned_as, permissioned_as_to_username}, cache::{self, FlowData}, @@ -49,7 +55,7 @@ use windmill_common::{ users::{SUPERADMIN_NOTIFICATION_EMAIL, SUPERADMIN_SECRET_EMAIL}, utils::{not_found_if_none, report_critical_error, StripPath, WarnAfterExt}, worker::{ - to_raw_value, CLOUD_HOSTED, DEFAULT_TAGS_PER_WORKSPACE, DEFAULT_TAGS_WORKSPACES, + to_raw_value, CLOUD_HOSTED, DISABLE_FLOW_SCRIPT, MIN_VERSION_IS_AT_LEAST_1_432, MIN_VERSION_IS_AT_LEAST_1_440, NO_LOGS, WORKER_PULL_QUERIES, WORKER_SUSPENDED_PULL_QUERY, }, @@ -65,8 +71,10 @@ use windmill_common::BASE_URL; #[cfg(feature = "cloud")] use windmill_common::users::SUPERADMIN_SYNC_EMAIL; +use crate::flow_status::{update_flow_status_in_progress, update_workflow_as_code_status}; use crate::jobs_ee::update_concurrency_counter; use crate::schedule::{get_schedule_opt, push_scheduled_job}; +use crate::tags::per_workspace_tag; #[cfg(feature = "prometheus")] lazy_static::lazy_static! { @@ -102,8 +110,6 @@ lazy_static::lazy_static! { .build().unwrap(); - pub static ref JOB_TOKEN: Option = std::env::var("JOB_TOKEN").ok(); - static ref JOB_ARGS_AUDIT_LOGS: bool = std::env::var("JOB_ARGS_AUDIT_LOGS") .ok() .and_then(|x| x.parse().ok()) @@ -125,12 +131,26 @@ const SCHEDULE_ERROR_HANDLER_USER_EMAIL: &str = "schedule_error_handler@windmill #[cfg(any(feature = "enterprise", feature = "cloud"))] const SCHEDULE_RECOVERY_HANDLER_USER_EMAIL: &str = "schedule_recovery_handler@windmill.dev"; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct CanceledBy { pub username: Option, pub reason: Option, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct JobCompleted { + pub job: Arc, + pub result: Arc>, + pub result_columns: Option>, + pub mem_peak: i32, + pub success: bool, + pub cached_res_path: Option, + pub token: String, + pub canceled_by: Option, + pub duration: Option, +} + + pub async fn cancel_single_job<'c>( username: &str, reason: Option, @@ -144,17 +164,19 @@ pub async fn cancel_single_job<'c>( let username = username.to_string(); let w_id = w_id.to_string(); let db = db.clone(); + tracing::info!("cancelling job {:?}", db); let job_running = job_running.clone(); tokio::task::spawn(async move { let reason: String = reason .clone() .unwrap_or_else(|| "unexplicited reasons".to_string()); let e = serde_json::json!({"message": format!("Job canceled: {reason} by {username}"), "name": "Canceled", "reason": reason, "canceler": username}); + append_logs( &job_running.id, w_id.to_string(), format!("canceled by {username}: (force cancel: {force_cancel})"), - &db, + &Connection::from(db.clone()), ) .await; let add_job = add_completed_job_error( @@ -335,7 +357,7 @@ pub async fn append_logs( job_id: &uuid::Uuid, workspace: impl AsRef, logs: impl AsRef, - db: impl Borrow>, + conn: &Connection, ) { if logs.as_ref().is_empty() { return; @@ -350,20 +372,81 @@ pub async fn append_logs( tracing::info!("NO LOGS [{job_id}]: {}", logs.as_ref()); return; } - if let Err(err) = sqlx::query!( - "INSERT INTO job_logs (logs, job_id, workspace_id) VALUES ($1, $2, $3) ON CONFLICT (job_id) DO UPDATE SET logs = concat(job_logs.logs, $1::text)", - logs.as_ref(), - job_id, - workspace.as_ref(), - ) - .execute(db.borrow()) - .warn_after_seconds(1) - .await - { - tracing::error!(%job_id, %err, "error updating logs for large_log job {job_id}: {err}"); + match conn { + Connection::Sql(pool) => { + if let Err(err) = sqlx::query!( + "INSERT INTO job_logs (logs, job_id, workspace_id) VALUES ($1, $2, $3) ON CONFLICT (job_id) DO UPDATE SET logs = concat(job_logs.logs, $1::text)", + logs.as_ref(), + job_id, + workspace.as_ref(), + ) + .execute(pool) + .warn_after_seconds(1) + .await + { + tracing::error!(%job_id, %err, "error updating logs for job {job_id}: {err}"); + } + } + Connection::Http(client) => { + if let Err(e) = client + .post::<_, String>( + &format!("/api/w/{}/agent_workers/push_logs/{}", workspace.as_ref(), job_id), + &logs.as_ref(), + ) + .await { + tracing::error!(%job_id, %e, "error sending logs for job {job_id}: {e}"); + }; + } } } +pub async fn push_init_job<'c>( + db: &Pool, + content: String, + worker_name: &str, +) -> error::Result { + let tx = PushIsolationLevel::IsolatedRoot(db.clone()); + let ehm = HashMap::new(); + let (uuid, inner_tx) = push( + &db, + tx, + "admins", + windmill_common::jobs::JobPayload::Code(windmill_common::jobs::RawCode { + hash: None, + content, + path: Some(format!("init_script_{worker_name}")), + language: ScriptLang::Bash, + lock: None, + custom_concurrency_key: None, + concurrent_limit: None, + concurrency_time_window_s: None, + cache_ttl: None, + dedicated_worker: None, + }), + PushArgs::from(&ehm), + worker_name, + "worker@windmill.dev", + SUPERADMIN_SECRET_EMAIL.to_string(), + None, + None, + None, + None, + None, + false, + true, + None, + true, + Some("init_script".to_string()), + None, + None, + None, + None, + ) + .await?; + inner_tx.commit().await?; + Ok(uuid) +} + pub async fn cancel_persistent_script_jobs<'c>( username: &str, reason: Option, @@ -877,11 +960,10 @@ pub async fn add_completed_job( tracing::debug!("decremented concurrency counter"); } - if JOB_TOKEN.is_none() { sqlx::query!("DELETE FROM job_perms WHERE job_id = $1", job_id) .execute(&mut *tx) .await?; - } + tx.commit().await?; @@ -897,6 +979,7 @@ pub async fn add_completed_job( created_by = queued_job.created_by, is_flow_step = queued_job.is_flow_step(), language = ?queued_job.script_lang, + scheduled_for = ?queued_job.scheduled_for, success, "inserted completed job: {} (success: {success})", queued_job.id @@ -1873,6 +1956,7 @@ pub enum TriggerKind { Mqtt, Sqs, Postgres, + Gcp } #[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone)] @@ -1889,6 +1973,7 @@ pub enum JobTriggerKind { Sqs, Postgres, Schedule, + Gcp } impl fmt::Display for TriggerKind { @@ -1903,12 +1988,13 @@ impl fmt::Display for TriggerKind { TriggerKind::Mqtt => "mqtt", TriggerKind::Sqs => "sqs", TriggerKind::Postgres => "postgres", + TriggerKind::Gcp => "gcp", }; write!(f, "{}", s) } } -#[derive(sqlx::FromRow, Debug, Clone)] +#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize)] pub struct MiniPulledJob { pub workspace_id: String, pub id: Uuid, @@ -2010,6 +2096,10 @@ impl MiniPulledJob { self.kind.is_flow() } + pub fn is_dependency(&self) -> bool { + self.kind.is_dependency() + } + pub fn schedule_path(&self) -> Option { if self .trigger_kind @@ -2021,9 +2111,35 @@ impl MiniPulledJob { None } } + + + pub async fn mark_as_started_if_step(&self, db: &DB) -> Result<(), Error> { + if self.is_flow_step() { + let _ = update_flow_status_in_progress( + db, + &self.workspace_id, + self.parent_job + .ok_or_else(|| Error::internal_err(format!("expected parent job")))?, + self.id, + ) + .warn_after_seconds(5) + .await?; + } else if let Some(parent_job) = self.parent_job { + let _ = update_workflow_as_code_status( + db, + &self.id, + &parent_job, + ) + .await?; + } + Ok(()) + } + } -#[derive(sqlx::FromRow, Debug, Clone)] + + +#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize)] pub struct PulledJob { #[sqlx(flatten)] pub job: MiniPulledJob, @@ -2039,6 +2155,95 @@ pub struct PulledJob { pub permissioned_as_folders: Option>, } +#[derive(Serialize, Deserialize)] +pub enum PrecomputedAgentInfo { + Bun { local: String, remote: String }, + Python { py_version: Option, requirements: Option }, +} + +#[derive(Serialize, Deserialize)] +pub struct JobAndPerms { + pub job: MiniPulledJob, + pub raw_code: Option, + pub raw_flow: Option>>, + pub raw_lock: Option, + pub parent_runnable_path: Option, + pub token: String, + pub precomputed_agent_info: Option, +} +impl PulledJob { + pub async fn get_job_and_perms(self, db: &DB) -> JobAndPerms { + let job_perms = match ( + self.permissioned_as_email, + self.permissioned_as_username, + self.permissioned_as_is_admin, + self.permissioned_as_is_operator, + self.permissioned_as_groups, + self.permissioned_as_folders, + ) { + ( + Some(email), + Some(username), + Some(is_admin), + Some(is_operator), + Some(groups), + Some(folders), + ) => Some(JobPerms { + email, + username, + is_admin, + is_operator, + groups, + folders, + }), + _ => None, + }; + + let token = create_token(&db, &self.job, job_perms).await; + JobAndPerms { + job: self.job, + raw_code: self.raw_code, + raw_flow: self.raw_flow, + raw_lock: self.raw_lock, + parent_runnable_path: self.parent_runnable_path, + token, + precomputed_agent_info: None, + } + } +} + +// struct Permission +pub async fn create_token(db: &DB, job: &MiniPulledJob, perms: Option) -> String { + // skipping test runs + if job.workspace_id != "" { + let label = if job.permissioned_as != format!("u/{}", job.created_by) + && job.permissioned_as != job.created_by + { + format!("ephemeral-script-end-user-{}", job.created_by) + } else { + "ephemeral-script".to_string() + }; + windmill_common::auth::create_token_for_owner( + db, + &job.workspace_id, + &job.permissioned_as, + &label, + *SCRIPT_TOKEN_EXPIRY, + &job.permissioned_as_email, + &job.id, + perms, + ) + .warn_after_seconds(5) + .await + .expect("could not create job token") + } else { + return "".to_string(); + } +} + + + + impl std::ops::Deref for PulledJob { type Target = MiniPulledJob; fn deref(&self) -> &Self::Target { @@ -2096,23 +2301,70 @@ pub async fn get_mini_pulled_job<'c>( Ok(job) } +#[derive(Serialize, Deserialize, Debug)] +pub struct PulledJobResult { + pub job: Option, + pub suspended: bool, +} + + + pub async fn pull( db: &Pool, suspend_first: bool, worker_name: &str, -) -> windmill_common::error::Result<(Option, bool)> { + query_o: Option<(String, String)>, + #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, +) -> windmill_common::error::Result { loop { + if let Some((query_suspended, query_no_suspend)) = query_o.as_ref() { + let njob = { + let job = sqlx::query_as::<_, PulledJob>(query_suspended) + .bind(worker_name) + .fetch_optional(db) + .await?; + if let Some(job) = job { + PulledJobResult { job: Some(job), suspended: true } + } else { + let job = sqlx::query_as::<_, PulledJob>(query_no_suspend) + .bind(worker_name) + .fetch_optional(db) + .await?; + PulledJobResult { job, suspended: false } + } + }; + if let Some(job) = njob.job.as_ref() { + if job.is_flow() || job.is_dependency() { + let per_workspace = per_workspace_tag(&job.workspace_id).await; + let base_tag = if job.is_flow() { + "flow".to_string() + } else { + "dependency".to_string() + }; + let tag = if per_workspace { + format!("{}-{}", base_tag, job.workspace_id) + } else { + base_tag + }; + sqlx::query!("UPDATE v2_job_queue SET tag = $1, running = false WHERE id = $2", tag, job.id).execute(db).await?; + continue; + } + } + return Ok(njob); + }; let (job, suspended) = pull_single_job_and_mark_as_running_no_concurrency_limit( - db, - suspend_first, - worker_name, - ) - .await?; + db, + suspend_first, + worker_name, + #[cfg(feature = "benchmark")] bench, + ) + .await?; let Some(job) = job else { - return Ok((None, suspended)); + return Ok(PulledJobResult { job: None, suspended }); }; + let has_concurent_limit = job.concurrent_limit.is_some(); #[cfg(not(feature = "enterprise"))] @@ -2133,7 +2385,7 @@ pub async fn pull( if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) { QUEUE_PULL_COUNT.inc(); } - return Ok((Option::Some(pulled_job), suspended)); + return Ok(PulledJobResult { job: Some(pulled_job), suspended }); } let job_concurrency_key = match concurrency_key(db, &pulled_job.id).await { @@ -2183,7 +2435,7 @@ pub async fn pull( if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) { QUEUE_PULL_COUNT.inc(); } - return Ok((Option::Some(pulled_job), suspended)); + return Ok(PulledJobResult { job: Some(pulled_job), suspended }); } let job_script_path = pulled_job.runnable_path.clone().unwrap_or_default(); @@ -2272,7 +2524,13 @@ pub async fn pull( "\nRe-scheduled job to {estimated_next_schedule_timestamp} due to concurrency limits with key {job_concurrency_key} and limit {job_custom_concurrent_limit} in the last {job_custom_concurrency_time_window_s} seconds (min_started_at: {min_started_at_or_now}, avg script duration: {:?}, number of time windows full: {})\n", avg_script_duration, i ); - let _ = append_logs(&job_uuid, &pulled_job.workspace_id, job_log_event, db).await; + let _ = append_logs( + &job_uuid, + &pulled_job.workspace_id, + job_log_event, + &Connection::from(db.clone()), + ) + .await; sqlx::query!( " @@ -2297,6 +2555,7 @@ async fn pull_single_job_and_mark_as_running_no_concurrency_limit<'c>( db: &Pool, suspend_first: bool, worker_name: &str, + #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> windmill_common::error::Result<(Option, bool)> { let job_and_suspended: (Option, bool) = { /* Jobs can be started if they: @@ -2337,11 +2596,18 @@ async fn pull_single_job_and_mark_as_running_no_concurrency_limit<'c>( for query in queries.iter() { // tracing::info!("Pulling job with query: {}", query); // let instant = std::time::Instant::now(); + + #[cfg(feature = "benchmark")] + add_time!(bench, "pre pull"); + let r = sqlx::query_as::<_, PulledJob>(query) .bind(worker_name) .fetch_optional(db) .await?; + #[cfg(feature = "benchmark")] + add_time!(bench, "post pull"); + if let Some(pulled_job) = r { // tracing::info!("pulled job: {:?}", instant.elapsed().as_micros()); @@ -3076,7 +3342,7 @@ pub async fn push<'c, 'd>( .await? .unwrap_or(0); - if in_queue > MAX_FREE_EXECS.into() { + if in_queue > MAX_FREE_EXECS as i64 { return Err(error::Error::QuotaExceeded(format!( "User {email} has exceeded the jobs in queue limit of {MAX_FREE_EXECS} that applies outside of premium workspaces." ))); @@ -3090,7 +3356,7 @@ pub async fn push<'c, 'd>( .await? .unwrap_or(0); - if concurrent_runs > MAX_FREE_CONCURRENT_RUNS.into() { + if concurrent_runs > MAX_FREE_CONCURRENT_RUNS as i64 { return Err(error::Error::QuotaExceeded(format!( "User {email} has exceeded the concurrent runs limit of {MAX_FREE_CONCURRENT_RUNS} that applies outside of premium workspaces." ))); @@ -3132,7 +3398,7 @@ pub async fn push<'c, 'd>( .await? .unwrap_or(0); - if in_queue_workspace > MAX_FREE_EXECS.into() { + if in_queue_workspace > MAX_FREE_EXECS as i64 { return Err(error::Error::QuotaExceeded(format!( "Workspace {workspace_id} has exceeded the jobs in queue limit of {MAX_FREE_EXECS} that applies outside of premium workspaces." ))); @@ -3146,7 +3412,7 @@ pub async fn push<'c, 'd>( .await? .unwrap_or(0); - if concurrent_runs_workspace > MAX_FREE_CONCURRENT_RUNS.into() { + if concurrent_runs_workspace > MAX_FREE_CONCURRENT_RUNS as i64 { return Err(error::Error::QuotaExceeded(format!( "Workspace {workspace_id} has exceeded the concurrent runs limit of {MAX_FREE_CONCURRENT_RUNS} that applies outside of premium workspaces." ))); @@ -3284,7 +3550,9 @@ pub async fn push<'c, 'd>( None, ), JobPayload::ScriptHub { path } => { - if path == "hub/7771/slack" || path == "hub/7836/slack" { + if path == "hub/7771/slack" || path == "hub/7836/slack" || path == "hub/9084/slack" { + // these scripts send app reports to slack + // they use the slack bot token and should therefore be run with permissions to access it permissioned_as = SUPERADMIN_NOTIFICATION_EMAIL.to_string(); email = SUPERADMIN_NOTIFICATION_EMAIL; } @@ -3587,18 +3855,16 @@ pub async fn push<'c, 'd>( }?; tx = PushIsolationLevel::Transaction(ntx); - let value = data.value().clone(); + let mut value = data.value().clone(); let priority = value.priority; let cache_ttl = value.cache_ttl.map(|x| x as i32); let custom_concurrency_key = value.concurrency_key.clone(); let concurrency_time_window_s = value.concurrency_time_window_s; let concurrent_limit = value.concurrent_limit; - // this is a new flow being pushed, status is set to `value`. - let mut status = FlowStatus::new(&value); let extra = args.extra.get_or_insert_with(HashMap::new); if !apply_preprocessor { - status.preprocessor_module = None; + value.preprocessor_module = None; extra.remove("wm_trigger"); } else { preprocessed = Some(false); @@ -3608,6 +3874,10 @@ pub async fn push<'c, 'd>( })) }); } + + // this is a new flow being pushed, status is set to `value`. + let status = FlowStatus::new(&value); + // Keep inserting `value` if not all workers are updated. // Starting at `v1.440`, the value is fetched on pull from the version id. let value_o = if !*MIN_VERSION_IS_AT_LEAST_1_440.read().await { @@ -3616,9 +3886,6 @@ pub async fn push<'c, 'd>( if same_worker { value.same_worker = true; } - if !apply_preprocessor { - value.preprocessor_module = None; - } Some(value) } else { // `raw_flow` is fetched on pull, the mutations from the other branch are replaced @@ -3809,14 +4076,6 @@ pub async fn push<'c, 'd>( .map(|e| (Some(e.0), e.1)) .unwrap_or_else(|| (None, None)); - let per_workspace_workspaces = DEFAULT_TAGS_WORKSPACES.read().await; - let per_workspace = DEFAULT_TAGS_PER_WORKSPACE.load(std::sync::atomic::Ordering::Relaxed) - && (per_workspace_workspaces.is_none() - || per_workspace_workspaces - .as_ref() - .unwrap() - .contains(&workspace_id.to_string())); - let tag = if dedicated_worker.is_some_and(|x| x) { format!( "{}:{}{}", @@ -3834,6 +4093,7 @@ pub async fn push<'c, 'd>( } let interpolated_tag = tag.map(|x| interpolate_args(x, &args, workspace_id)); + let per_workspace = per_workspace_tag(&workspace_id).await; let default = || { let ntag = if job_kind.is_flow() || job_kind == JobKind::Identity { @@ -3930,16 +4190,77 @@ pub async fn push<'c, 'd>( _ => None, }); + let job_authed = match authed { + Some(authed) + if authed.email == email + && authed.username == permissioned_as_to_username(&permissioned_as) => + { + authed.clone() + } + _ => { + if authed.is_some() { + tracing::warn!("Authed passed to push is not the same as permissioned_as, refetching direclty permissions for job {job_id}...") + } + fetch_authed_from_permissioned_as( + permissioned_as.clone(), + email.to_string(), + workspace_id, + _db, + ) + .await + .map_err(|e| { + Error::internal_err(format!( + "Could not get permissions directly for job {job_id}: {e:#}" + )) + })? + } + }; + + let folders = job_authed + .folders + .iter() + .filter_map(|x| serde_json::to_value(x).ok()) + .collect::>(); + + // if let Err(err) = sqlx::query!("INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) + // values ($1, $2, $3, $4, $5, $6, $7, $8) + // ON CONFLICT (job_id) DO UPDATE SET email = $2, username = $3, is_admin = $4, is_operator = $5, folders = $6, groups = $7, workspace_id = $8", + // job_id, + // job_authed.email, + // job_authed.username, + // job_authed.is_admin, + // job_authed.is_operator, + // folders.as_slice(), + // job_authed.groups.as_slice(), + // workspace_id, + // ).execute(&mut *tx).await { + // tracing::error!("Could not insert job_perms for job {job_id}: {err:#}"); + // } + + sqlx::query!( - "INSERT INTO v2_job (id, workspace_id, raw_code, raw_lock, raw_flow, tag, parent_job, - created_by, permissioned_as, runnable_id, runnable_path, args, kind, trigger, + "WITH inserted_job AS ( + INSERT INTO v2_job (id, workspace_id, raw_code, raw_lock, raw_flow, tag, parent_job, + created_by, permissioned_as, runnable_id, runnable_path, args, kind, trigger, script_lang, same_worker, pre_run_error, permissioned_as_email, visible_to_owner, flow_innermost_root_job, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id, cache_ttl, priority, trigger_kind, script_entrypoint_override, preprocessed) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, CASE WHEN $14::VARCHAR IS NOT NULL THEN 'schedule'::job_trigger_kind END, - ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27)", + ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27) + ), + inserted_runtime AS ( + INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null) + ), + inserted_job_perms AS ( + INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) + values ($1, $32, $33, $34, $35, $36, $37, $2) + ON CONFLICT (job_id) DO UPDATE SET email = $32, username = $33, is_admin = $34, is_operator = $35, folders = $36, groups = $37, workspace_id = $2 + ) + INSERT INTO v2_job_queue + (workspace_id, id, running, scheduled_for, started_at, tag, priority) + VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 THEN now() END, $30, $31)", job_id, workspace_id, raw_code, @@ -3971,35 +4292,42 @@ pub async fn push<'c, 'd>( cache_ttl, final_priority, preprocessed, - ) - .execute(&mut *tx) - .warn_after_seconds(1) - .await?; - - tracing::debug!("Pushing job {job_id} with tag {tag}, schedule_path {schedule_path:?}, script_path: {script_path:?}, email {email}, workspace_id {workspace_id}"); - let uuid = sqlx::query_scalar!( - "INSERT INTO v2_job_queue - (workspace_id, id, running, scheduled_for, started_at, tag, priority) - VALUES ($1, $2, $3, COALESCE($4, now()), CASE WHEN $3 THEN now() END, $5, $6) \ - RETURNING id AS \"id!\"", - workspace_id, - job_id, is_running, scheduled_for_o, tag, final_priority, - ) - .fetch_one(&mut *tx) - .warn_after_seconds(1) - .await - .map_err(|e| Error::internal_err(format!("Could not insert into queue {job_id} with tag {tag}, schedule_path {schedule_path:?}, script_path: {script_path:?}, email {email}, workspace_id {workspace_id}: {e:#}")))?; - - sqlx::query!( - "INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)", - job_id + job_authed.email, + job_authed.username, + job_authed.is_admin, + job_authed.is_operator, + folders.as_slice(), + job_authed.groups.as_slice(), ) .execute(&mut *tx) + .warn_after_seconds(1) .await?; + +// tracing::debug!("Pushing job {job_id} with tag {tag}, schedule_path {schedule_path:?}, script_path: {script_path:?}, email {email}, workspace_id {workspace_id}"); +// let uuid = sqlx::query_scalar!( +// "INSERT INTO v2_job_queue +// (workspace_id, id, running, scheduled_for, started_at, tag, priority) +// VALUES ($1, $2, $3, COALESCE($4, now()), CASE WHEN $3 THEN now() END, $5, $6) \ +// RETURNING id AS \"id!\"", +// workspace_id, +// job_id, +// , +// ) +// .fetch_one(&mut *tx) +// .warn_after_seconds(1) +// .await +// .map_err(|e| Error::internal_err(format!("Could not insert into queue {job_id} with tag {tag}, schedule_path {schedule_path:?}, script_path: {script_path:?}, email {email}, workspace_id {workspace_id}: {e:#}")))?; + + // sqlx::query!( + // "INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)", + // job_id + // ) + // .execute(&mut *tx) + // .await?; if let Some(flow_status) = flow_status { sqlx::query!( "INSERT INTO v2_job_status (id, flow_status) VALUES ($1, $2)", @@ -4017,54 +4345,7 @@ pub async fn push<'c, 'd>( QUEUE_PUSH_COUNT.inc(); } - if JOB_TOKEN.is_none() { - let job_authed = match authed { - Some(authed) - if authed.email == email - && authed.username == permissioned_as_to_username(&permissioned_as) => - { - authed.clone() - } - _ => { - if authed.is_some() { - tracing::warn!("Authed passed to push is not the same as permissioned_as, refetching direclty permissions for job {job_id}...") - } - fetch_authed_from_permissioned_as( - permissioned_as.clone(), - email.to_string(), - workspace_id, - _db, - ) - .await - .map_err(|e| { - Error::internal_err(format!( - "Could not get permissions directly for job {job_id}: {e:#}" - )) - })? - } - }; - let folders = job_authed - .folders - .iter() - .filter_map(|x| serde_json::to_value(x).ok()) - .collect::>(); - - if let Err(err) = sqlx::query!("INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) - values ($1, $2, $3, $4, $5, $6, $7, $8) - ON CONFLICT (job_id) DO UPDATE SET email = $2, username = $3, is_admin = $4, is_operator = $5, folders = $6, groups = $7, workspace_id = $8", - job_id, - job_authed.email, - job_authed.username, - job_authed.is_admin, - job_authed.is_operator, - folders.as_slice(), - job_authed.groups.as_slice(), - workspace_id, - ).execute(&mut *tx).await { - tracing::error!("Could not insert job_perms for job {job_id}: {err:#}"); - } - } { let uuid_string = job_id.to_string(); @@ -4125,7 +4406,7 @@ pub async fn push<'c, 'd>( .await?; } - Ok((uuid, tx)) + Ok((job_id, tx)) } pub fn canceled_job_to_result(job: &MiniPulledJob) -> serde_json::Value { @@ -4175,7 +4456,7 @@ async fn restarted_flows_resolution( })?; let flow_data = cache::job::fetch_flow(db, row.job_kind, row.script_hash) - .or_else(|_| cache::job::fetch_preview_flow(db, &completed_flow_id, row.raw_flow)) + .or_else(|_| cache::job::fetch_preview_flow(db.into(), &completed_flow_id, row.raw_flow)) .await?; let flow_value = flow_data.value(); let flow_status = row @@ -4328,3 +4609,78 @@ async fn restarted_flows_resolution( flow_status.cleanup_module, )) } + + +#[derive(Serialize, Deserialize)] +pub struct SameWorkerPayload { + pub job_id: Uuid, + pub recoverable: bool, +} + +pub async fn get_same_worker_job( + db: &DB, + same_worker_job: &SameWorkerPayload, +) -> windmill_common::error::Result> { + sqlx::query_as::<_, PulledJob>( + "WITH ping AS ( + UPDATE v2_job_runtime SET ping = NOW() WHERE id = $1 + ), + started_at AS ( + UPDATE v2_job_queue SET started_at = NOW() WHERE id = $1 + ) + SELECT + v2_job_queue.workspace_id, + v2_job_queue.id, + v2_job.args, + v2_job.parent_job, + v2_job.created_by, + v2_job_queue.started_at, + scheduled_for, + v2_job.runnable_path, + v2_job.kind, + v2_job.runnable_id, + v2_job_queue.canceled_reason, + v2_job_queue.canceled_by, + v2_job.permissioned_as, + v2_job.permissioned_as_email, + v2_job_status.flow_status, + v2_job.tag, + v2_job.script_lang, + v2_job.same_worker, + v2_job.pre_run_error, + v2_job.concurrent_limit, + v2_job.concurrency_time_window_s, + v2_job.flow_innermost_root_job, + v2_job.timeout, + v2_job.flow_step_id, + v2_job.cache_ttl, + v2_job_queue.priority, + v2_job.preprocessed, + v2_job.script_entrypoint_override, + v2_job.trigger, + v2_job.trigger_kind, + v2_job.visible_to_owner, + v2_job.raw_code, + v2_job.raw_lock, + v2_job.raw_flow, + pj.runnable_path as parent_runnable_path, + p.email as permissioned_as_email, p.username as permissioned_as_username, p.is_admin as permissioned_as_is_admin, + p.is_operator as permissioned_as_is_operator, p.groups as permissioned_as_groups, p.folders as permissioned_as_folders + FROM v2_job_queue + INNER JOIN v2_job ON v2_job.id = v2_job_queue.id + LEFT JOIN v2_job_status ON v2_job_status.id = v2_job_queue.id + LEFT JOIN job_perms p ON p.job_id = v2_job.id + LEFT JOIN v2_job pj ON v2_job.parent_job = pj.id + WHERE v2_job_queue.id = $1 +", + ) + .bind(same_worker_job.job_id) + .fetch_optional(db) + .await + .map_err(|e| { + Error::internal_err(format!( + "Impossible to fetch same_worker job {}: {}", + same_worker_job.job_id, e + )) + }) +} \ No newline at end of file diff --git a/backend/windmill-queue/src/lib.rs b/backend/windmill-queue/src/lib.rs index c2d022d16a..2496bdf818 100644 --- a/backend/windmill-queue/src/lib.rs +++ b/backend/windmill-queue/src/lib.rs @@ -10,3 +10,5 @@ mod jobs; pub mod jobs_ee; pub mod schedule; pub use jobs::*; +pub mod flow_status; +pub mod tags; diff --git a/backend/windmill-queue/src/tags.rs b/backend/windmill-queue/src/tags.rs new file mode 100644 index 0000000000..6cf6620039 --- /dev/null +++ b/backend/windmill-queue/src/tags.rs @@ -0,0 +1,11 @@ +use windmill_common::worker::{DEFAULT_TAGS_PER_WORKSPACE, DEFAULT_TAGS_WORKSPACES}; + +pub async fn per_workspace_tag(workspace_id: &str) -> bool { + let per_workspace_workspaces = DEFAULT_TAGS_WORKSPACES.read().await; + DEFAULT_TAGS_PER_WORKSPACE.load(std::sync::atomic::Ordering::Relaxed) + && (per_workspace_workspaces.is_none() + || per_workspace_workspaces + .as_ref() + .unwrap() + .contains(&workspace_id.to_string())) +} diff --git a/backend/windmill-worker/Cargo.toml b/backend/windmill-worker/Cargo.toml index 291e92c2df..e4de400d84 100644 --- a/backend/windmill-worker/Cargo.toml +++ b/backend/windmill-worker/Cargo.toml @@ -30,17 +30,20 @@ python = ["dep:windmill-parser-py", "dep:windmill-parser-py-imports"] csharp = ["dep:windmill-parser-csharp"] rust = ["dep:windmill-parser-rust"] nu = ["dep:windmill-parser-nu"] +java = ["dep:windmill-parser-java"] [dependencies] windmill-queue.workspace = true windmill-audit.workspace = true # there isn't really a reason for audit-worth actions to happen in the worker. windmill-common = { workspace = true, default-features = false } +windmill-macros.workspace = true windmill-parser.workspace = true windmill-parser-ts.workspace = true windmill-parser-go.workspace = true windmill-parser-rust = { workspace = true, optional = true } windmill-parser-csharp = { workspace = true, optional = true } windmill-parser-nu = { workspace = true, optional = true } +windmill-parser-java = { workspace = true, optional = true } windmill-parser-py = { workspace = true, optional = true } windmill-parser-yaml.workspace = true windmill-parser-py-imports = { workspace = true, optional = true } @@ -49,6 +52,7 @@ windmill-parser-sql.workspace = true windmill-parser-graphql.workspace = true windmill-parser-php = { workspace = true, optional = true } windmill-git-sync.workspace = true +flume.workspace = true sqlx.workspace = true uuid.workspace = true tracing.workspace = true @@ -72,6 +76,7 @@ dyn-iter.workspace = true once_cell.workspace = true tokio-postgres.workspace = true bit-vec.workspace = true +url.workspace = true deno_telemetry = { workspace = true, optional = true } deno_fetch = { workspace = true, optional = true } deno_webidl = { workspace = true, optional = true } @@ -99,6 +104,7 @@ urlencoding.workspace = true nix.workspace = true bytes.workspace = true reqwest.workspace = true +reqwest-middleware.workspace = true hex.workspace = true tiberius = { workspace = true, optional = true } tokio-util = { workspace = true, optional = true } @@ -127,4 +133,4 @@ deno_permissions = { workspace = true, optional = true } deno_io = { workspace = true, optional = true } deno_runtime = { workspace = true, optional = true } deno_telemetry = { workspace = true, optional = true } -winapi = { workspace = true, optional = true } \ No newline at end of file +winapi = { workspace = true, optional = true } diff --git a/backend/windmill-worker/nsjail/run.java.config.proto b/backend/windmill-worker/nsjail/run.java.config.proto new file mode 100644 index 0000000000..032072fb7c --- /dev/null +++ b/backend/windmill-worker/nsjail/run.java.config.proto @@ -0,0 +1,107 @@ +name: "java run script" + +mode: ONCE +hostname: "java" +log_level: ERROR + +disable_rl: true + +cwd: "/tmp" + +clone_newnet: false +clone_newuser: {CLONE_NEWUSER} + +keep_caps: false +keep_env: true +mount_proc: true + +mount { + src: "/bin" + dst: "/bin" + is_bind: true +} + +mount { + src: "/lib" + dst: "/lib" + is_bind: true +} + + +mount { + src: "/lib64" + dst: "/lib64" + is_bind: true + mandatory: false +} + + +mount { + src: "/usr" + dst: "/usr" + is_bind: true +} + +mount { + src: "/dev/null" + dst: "/dev/null" + is_bind: true + rw: true +} + +mount { + dst: "/tmp" + fstype: "tmpfs" + rw: true + options: "size=500000000" +} + + +mount { + src: "{JOB_DIR}/target" + dst: "/tmp/target" + is_bind: true + mandatory: false +} + +mount { + src: "{JOB_DIR}/args.json" + dst: "/tmp/args.json" + is_bind: true +} + +mount { + src: "{JOB_DIR}/result.json" + dst: "/tmp/result.json" + rw: true + is_bind: true +} + +mount { + src: "{CACHE_DIR}" + dst: "{CACHE_DIR}" + is_bind: true + mandatory: false +} + +mount { + src: "/etc" + dst: "/etc" + is_bind: true +} + +mount { + src: "/dev/random" + dst: "/dev/random" + is_bind: true +} + +mount { + src: "/dev/urandom" + dst: "/dev/urandom" + is_bind: true +} + +iface_no_lo: true + +{SHARED_MOUNT} diff --git a/backend/windmill-worker/src/agent_workers.rs b/backend/windmill-worker/src/agent_workers.rs new file mode 100644 index 0000000000..192ae7ae37 --- /dev/null +++ b/backend/windmill-worker/src/agent_workers.rs @@ -0,0 +1,31 @@ +use uuid::Uuid; +use windmill_common::{agent_workers::QueueInitJob, worker::HttpClient}; +use windmill_queue::{JobAndPerms, JobCompleted}; + +pub async fn queue_init_job(client: &HttpClient, content: &str) -> anyhow::Result { + client + .post( + "/api/agent_workers/queue_init_job", + &QueueInitJob { content: content.to_string() }, + ) + .await + .and_then(|x: String| Uuid::parse_str(&x).map_err(|e| anyhow::anyhow!(e))) +} + +pub async fn pull_job(client: &HttpClient) -> anyhow::Result> { + client.post("/api/agent_workers/pull_job", &()).await +} + +pub async fn send_result(client: &HttpClient, jc: JobCompleted) -> anyhow::Result { + client + .post( + &format!( + "/api/w/{}/agent_workers/send_result/{}", + jc.job.workspace_id, jc.job.id + ), + &jc, + ) + .await +} + +pub const UPDATE_PING_URL: &str = "/api/agent_workers/update_ping"; diff --git a/backend/windmill-worker/src/ansible_executor.rs b/backend/windmill-worker/src/ansible_executor.rs index 99612fbf26..2048ac0cd7 100644 --- a/backend/windmill-worker/src/ansible_executor.rs +++ b/backend/windmill-worker/src/ansible_executor.rs @@ -11,7 +11,9 @@ use tokio::process::Command; use uuid::Uuid; use windmill_common::{ error, - worker::{is_allowed_file_location, to_raw_value, write_file, write_file_at_user_defined_location, WORKER_CONFIG}, + worker::{ + is_allowed_file_location, to_raw_value, write_file, write_file_at_user_defined_location, Connection, WORKER_CONFIG, + }, }; use windmill_queue::MiniPulledJob; @@ -124,7 +126,7 @@ async fn handle_ansible_python_deps( ansible_reqs: Option<&AnsibleRequirements>, w_id: &str, job_id: &Uuid, - db: &sqlx::Pool, + conn: &Connection, worker_name: &str, worker_dir: &str, mem_peak: &mut i32, @@ -155,7 +157,7 @@ async fn handle_ansible_python_deps( mem_peak, canceled_by, job_dir, - db, + conn, worker_name, w_id, &mut Some(occupancy_metrics), @@ -181,7 +183,7 @@ async fn handle_ansible_python_deps( w_id, mem_peak, canceled_by, - db, + conn, worker_name, job_dir, worker_dir, @@ -202,7 +204,7 @@ async fn install_galaxy_collections( w_id: &str, mem_peak: &mut i32, canceled_by: &mut Option, - db: &sqlx::Pool, + conn: &Connection, occupancy_metrics: &mut OccupancyMetrics, ) -> anyhow::Result<()> { write_file(job_dir, "requirements.yml", collections_yml)?; @@ -211,7 +213,7 @@ async fn install_galaxy_collections( job_id, w_id, "\n\n--- ANSIBLE GALAXY INSTALL ---\n".to_string(), - db, + conn, ) .await; @@ -264,7 +266,7 @@ async fn install_galaxy_collections( let child = start_child_process(galaxy_collections_cmd, ANSIBLE_GALAXY_PATH.as_str()).await?; handle_child( job_id, - db, + conn, mem_peak, canceled_by, child, @@ -275,6 +277,7 @@ async fn install_galaxy_collections( None, false, &mut Some(occupancy_metrics), + None, ) .await?; @@ -289,7 +292,7 @@ pub async fn handle_ansible_job( job: &MiniPulledJob, mem_peak: &mut i32, canceled_by: &mut Option, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, inner_content: &String, @@ -305,7 +308,7 @@ pub async fn handle_ansible_job( )?; let (logs, reqs, playbook) = windmill_parser_yaml::parse_ansible_reqs(inner_content)?; - append_logs(&job.id, &job.workspace_id, logs, db).await; + append_logs(&job.id, &job.workspace_id, logs, conn).await; write_file(job_dir, "main.yml", &playbook)?; let additional_python_paths = handle_ansible_python_deps( @@ -314,7 +317,7 @@ pub async fn handle_ansible_job( reqs.as_ref(), &job.workspace_id, &job.id, - db, + conn, worker_name, worker_dir, mem_peak, @@ -331,7 +334,7 @@ pub async fn handle_ansible_job( args.insert(name.clone(), to_raw_value(path)); } } - if let Some(x) = transform_json(client, &job.workspace_id, &args, job, db).await? { + if let Some(x) = transform_json(client, &job.workspace_id, &args, job, conn).await? { write_file( job_dir, "args.json", @@ -371,16 +374,18 @@ pub async fn handle_ansible_job( let mut nsjail_extra_mounts = vec![]; if let Some(r) = reqs.as_ref() { - nsjail_extra_mounts = create_file_resources( - &job.id, - &job.workspace_id, - job_dir, - interpolated_args.as_ref(), - &r, - &client, - db, - ) - .await?; + if let Some(db) = conn.as_sql() { + nsjail_extra_mounts = create_file_resources( + &job.id, + &job.workspace_id, + job_dir, + interpolated_args.as_ref(), + &r, + &client, + db, + ) + .await?; + } for repo in r.git_repos { clone_repo( @@ -406,7 +411,7 @@ pub async fn handle_ansible_job( &job.workspace_id, mem_peak, canceled_by, - db, + conn, occupancy_metrics, ) .await?; @@ -416,7 +421,7 @@ pub async fn handle_ansible_job( &job.id, &job.workspace_id, "\n\n--- ANSIBLE PLAYBOOK EXECUTION ---\n".to_string(), - db, + conn, ) .await; @@ -446,7 +451,7 @@ remote_tmp={job_dir}/.ansible/tmp write_file(job_dir, "ansible.cfg", &ansible_cfg_content)?; let mut reserved_variables = - get_reserved_variables(job, &client.token, db, parent_runnable_path).await?; + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; let additional_python_paths_folders = additional_python_paths.join(":"); if !*DISABLE_NSJAIL { @@ -555,7 +560,7 @@ fi handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -566,6 +571,7 @@ fi job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await?; read_and_check_result(job_dir).await @@ -696,7 +702,7 @@ async fn create_file_resources( file_res.target_path, file_res.resource_path )); } - append_logs(job_id, w_id, logs, db).await; + append_logs(job_id, w_id, logs, &Connection::Sql(db.clone())).await; Ok(nsjail_mounts) } diff --git a/backend/windmill-worker/src/bash_executor.rs b/backend/windmill-worker/src/bash_executor.rs index a496b327b5..7a7a78282c 100644 --- a/backend/windmill-worker/src/bash_executor.rs +++ b/backend/windmill-worker/src/bash_executor.rs @@ -15,12 +15,9 @@ use tokio::process::Command; use uuid::Uuid; use windmill_common::{ error::Error, - worker::{to_raw_value, write_file}, + worker::{to_raw_value, write_file, Connection}, }; -#[cfg(feature = "dind")] -use windmill_common::DB; - #[cfg(feature = "dind")] use windmill_common::error::to_anyhow; @@ -63,7 +60,7 @@ pub async fn handle_bash_job( mem_peak: &mut i32, canceled_by: &mut Option, job: &MiniPulledJob, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, content: &str, @@ -81,7 +78,7 @@ pub async fn handle_bash_job( if annotation.docker { logs1.push_str("docker mode\n"); } - append_logs(&job.id, &job.workspace_id, logs1, db).await; + append_logs(&job.id, &job.workspace_id, logs1, &conn).await; write_file(job_dir, "main.sh", &format!("set -e\n{content}"))?; let script = format!( @@ -137,10 +134,10 @@ exit $exit_status write_file(job_dir, "wrapper.sh", &script)?; let mut reserved_variables = - get_reserved_variables(job, &client.token, db, parent_runnable_path).await?; + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; reserved_variables.insert("RUST_LOG".to_string(), "info".to_string()); - let args = build_args_map(job, client, db).await?.map(Json); + let args = build_args_map(job, client, conn).await?.map(Json); let job_args = if args.is_some() { args.as_ref() } else { @@ -215,7 +212,7 @@ exit $exit_status }; handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -226,6 +223,7 @@ exit $exit_status job.timeout, true, &mut Some(occupancy_metrics), + None, ) .await?; @@ -234,7 +232,7 @@ exit $exit_status return handle_docker_job( job.id, &job.workspace_id, - db, + conn, job.timeout, mem_peak, canceled_by, @@ -279,7 +277,7 @@ exit $exit_status async fn handle_docker_job( job_id: Uuid, workspace_id: &str, - db: &DB, + conn: &Connection, job_timeout: Option, mem_peak: &mut i32, canceled_by: &mut Option, @@ -314,7 +312,7 @@ async fn handle_docker_job( let ncontainer_id = container_id.to_string(); let w_id = workspace_id.to_string(); let j_id = job_id.clone(); - let db2 = db.clone(); + let conn2 = conn.clone(); let (tx, mut rx) = tokio::sync::broadcast::channel::<()>(1); let mut killpill_rx = killpill_rx.resubscribe(); @@ -336,7 +334,7 @@ async fn handle_docker_job( log = log_stream.next() => { match log { Some(Ok(log)) => { - append_logs(&j_id, w_id.clone(), log.to_string(), db2.clone()).await; + append_logs(&j_id, w_id.clone(), log.to_string(), &conn2).await; } Some(Err(e)) => { tracing::error!("Error getting logs: {:?}", e); @@ -370,7 +368,7 @@ async fn handle_docker_job( let result = run_future_with_polling_update_job_poller( job_id, job_timeout, - db, + conn, mem_peak, canceled_by, wait_f, @@ -471,7 +469,7 @@ pub async fn handle_powershell_job( mem_peak: &mut i32, canceled_by: &mut Option, job: &MiniPulledJob, - db: &sqlx::Pool, + db: &Connection, client: &AuthedClient, parent_runnable_path: Option, content: &str, @@ -483,7 +481,7 @@ pub async fn handle_powershell_job( occupancy_metrics: &mut OccupancyMetrics, ) -> Result, Error> { let pwsh_args = { - let args = build_args_map(job, client, db).await?.map(Json); + let args = build_args_map(job, client, &db).await?.map(Json); let job_args = if args.is_some() { args.as_ref() } else { @@ -569,6 +567,7 @@ pub async fn handle_powershell_job( job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await?; } @@ -780,6 +779,7 @@ $env:PSModulePath = \"{};$PSModulePathBackup\"", job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await?; diff --git a/backend/windmill-worker/src/bigquery_executor.rs b/backend/windmill-worker/src/bigquery_executor.rs index 28aa1398d3..9cc9fd6c90 100644 --- a/backend/windmill-worker/src/bigquery_executor.rs +++ b/backend/windmill-worker/src/bigquery_executor.rs @@ -5,6 +5,7 @@ use futures::{FutureExt, TryFutureExt}; use reqwest::Client; use serde_json::{json, value::RawValue, Value}; use windmill_common::error::to_anyhow; +use windmill_common::worker::Connection; use windmill_common::{error::Error, worker::to_raw_value}; use windmill_parser_sql::{ parse_bigquery_sig, parse_db_resource, parse_sql_blocks, parse_sql_statement_named_params, @@ -209,14 +210,14 @@ pub async fn do_bigquery( job: &MiniPulledJob, client: &AuthedClient, query: &str, - db: &sqlx::Pool, + conn: &Connection, mem_peak: &mut i32, canceled_by: &mut Option, worker_name: &str, column_order: &mut Option>, occupancy_metrics: &mut OccupancyMetrics, ) -> windmill_common::error::Result> { - let bigquery_args = build_args_values(job, client, db).await?; + let bigquery_args = build_args_values(job, client, conn).await?; let inline_db_res_path = parse_db_resource(&query); @@ -252,7 +253,7 @@ pub async fn do_bigquery( .map_err(|e| Error::ExecutionErr(e.to_string()))?; let (timeout_duration, _, _) = - resolve_job_timeout(&db, &job.workspace_id, job.id, job.timeout).await; + resolve_job_timeout(&conn, &job.workspace_id, job.id, job.timeout).await; let timeout_ms = timeout_duration.as_millis() as u64; let http_client = build_http_client(timeout_duration)?; @@ -366,7 +367,7 @@ pub async fn do_bigquery( let r = run_future_with_polling_update_job_poller( job.id, job.timeout, - db, + conn, mem_peak, canceled_by, result_f.map_err(to_anyhow), diff --git a/backend/windmill-worker/src/bun_executor.rs b/backend/windmill-worker/src/bun_executor.rs index ed6881b4fd..91284c9d41 100644 --- a/backend/windmill-worker/src/bun_executor.rs +++ b/backend/windmill-worker/src/bun_executor.rs @@ -9,7 +9,7 @@ use serde_json::value::RawValue; use uuid::Uuid; use windmill_parser_ts::remove_pinned_imports; -use windmill_queue::{append_logs, CanceledBy, MiniPulledJob}; +use windmill_queue::{append_logs, CanceledBy, MiniPulledJob, PrecomputedAgentInfo}; #[cfg(feature = "enterprise")] use crate::common::build_envs_map; @@ -42,7 +42,7 @@ use windmill_common::{ error::{self, Result}, get_latest_hash_for_path, scripts::ScriptLang, - worker::{exists_in_cache, save_cache, write_file, DISABLE_BUNDLING}, + worker::{exists_in_cache, save_cache, write_file, Connection, DISABLE_BUNDLING}, DB, }; @@ -96,7 +96,7 @@ pub async fn gen_bun_lockfile( canceled_by: &mut Option, job_id: &Uuid, w_id: &str, - db: Option<&sqlx::Pool>, + db: Option<&Connection>, token: &str, script_path: &str, job_dir: &str, @@ -166,6 +166,7 @@ pub async fn gen_bun_lockfile( None, false, occupancy_metrics, + None, ) .await?; } else { @@ -272,7 +273,7 @@ pub async fn install_bun_lockfile( canceled_by: &mut Option, job_id: &Uuid, w_id: &str, - db: Option<&sqlx::Pool>, + db: Option<&Connection>, job_dir: &str, worker_name: &str, common_bun_proc_envs: HashMap, @@ -349,6 +350,7 @@ pub async fn install_bun_lockfile( None, false, occupancy_metrics, + None, ) .await? } else { @@ -486,7 +488,7 @@ pub async fn generate_wrapper_mjs( w_id: &str, job_id: &Uuid, worker_name: &str, - db: &sqlx::Pool, + db: &Connection, timeout: Option, mem_peak: &mut i32, canceled_by: &mut Option, @@ -520,6 +522,7 @@ pub async fn generate_wrapper_mjs( timeout, false, occupancy_metrics, + None, ) .await?; fs::rename( @@ -535,7 +538,7 @@ pub async fn generate_bun_bundle( w_id: &str, job_id: &Uuid, worker_name: &str, - db: Option>, + db: Option<&Connection>, timeout: Option, mem_peak: &mut i32, canceled_by: &mut Option, @@ -570,6 +573,7 @@ pub async fn generate_bun_bundle( timeout, false, occupancy_metrics, + None, ) .await?; } else { @@ -594,7 +598,6 @@ pub async fn pull_codebase(w_id: &str, id: &str, job_dir: &str) -> Result<()> { if std::fs::metadata(&bun_cache_path).is_ok() { tracing::info!("loading {bun_cache_path} from cache"); - extract_saved_codebase(job_dir, &bun_cache_path, is_tar, &dst, false)?; } else { #[cfg(all(feature = "enterprise", feature = "parquet"))] @@ -676,21 +679,15 @@ pub async fn prebundle_bun_script( script_path: &str, job_id: &Uuid, w_id: &str, - db: Option, + db: Option<&DB>, job_dir: &str, base_internal_url: &str, worker_name: &str, token: &str, occupancy_metrics: &mut Option<&mut OccupancyMetrics>, ) -> Result<()> { - let (local_path, remote_path) = compute_bundle_local_and_remote_path( - inner_content, - lockfile, - script_path, - db.clone(), - w_id, - ) - .await; + let (local_path, remote_path) = + compute_bundle_local_and_remote_path(inner_content, lockfile, script_path, db, w_id).await; if exists_in_cache(&local_path, &remote_path).await { return Ok(()); } @@ -724,7 +721,7 @@ pub async fn prebundle_bun_script( w_id, job_id, worker_name, - db.clone(), + db.map(|x| Connection::from(x.clone())).as_ref(), None, &mut 0, &mut None, @@ -733,7 +730,7 @@ pub async fn prebundle_bun_script( ) .await?; - save_cache(&local_path, &remote_path, &origin).await?; + save_cache(&local_path, &remote_path, &origin, false).await?; Ok(()) } @@ -752,11 +749,11 @@ async fn get_script_import_updated_at(db: &DB, w_id: &str, script_path: &str) -> Ok(last_updated_at.to_string()) } -async fn compute_bundle_local_and_remote_path( +pub async fn compute_bundle_local_and_remote_path( inner_content: &str, requirements_o: Option<&String>, script_path: &str, - db: Option, + db: Option<&DB>, w_id: &str, ) -> (String, String) { let mut input_src = format!( @@ -824,7 +821,7 @@ pub async fn handle_bun_job( mem_peak: &mut i32, canceled_by: &mut Option, job: &MiniPulledJob, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, job_dir: &str, @@ -835,6 +832,7 @@ pub async fn handle_bun_job( shared_mount: &str, new_args: &mut Option>>, occupancy_metrics: &mut OccupancyMetrics, + precomputed_agent_info: Option, ) -> error::Result> { let mut annotation = windmill_common::worker::TypeScriptAnnotations::parse(inner_content); @@ -843,16 +841,32 @@ pub async fn handle_bun_job( && !*DISABLE_BUNDLING && codebase.is_none() { - let (local_path, remote_path) = compute_bundle_local_and_remote_path( - inner_content, - requirements_o, - job.runnable_path(), - Some(db.clone()), - &job.workspace_id, - ) - .await; + let (local_path, remote_path) = match conn { + Connection::Sql(db) => { + compute_bundle_local_and_remote_path( + inner_content, + requirements_o, + job.runnable_path(), + Some(db), + &job.workspace_id, + ) + .await + } + Connection::Http(_) => { + let (local_path, remote_path) = match precomputed_agent_info { + Some(PrecomputedAgentInfo::Bun { local, remote }) => (local, remote), + _ => { + return Err(error::Error::ExecutionErr( + "bun bundle is missing the precomputed agent info".to_string(), + )) + } + }; + (local_path, remote_path) + } + }; - let (cache, logs) = windmill_common::worker::load_cache(&local_path, &remote_path).await; + let (cache, logs) = + windmill_common::worker::load_cache(&local_path, &remote_path, false).await; (cache, logs, local_path, remote_path) } else { (false, "".to_string(), "".to_string(), "".to_string()) @@ -916,7 +930,7 @@ pub async fn handle_bun_job( canceled_by, &job.id, &job.workspace_id, - Some(db), + Some(conn), job_dir, worker_name, common_bun_proc_envs.clone(), @@ -928,13 +942,13 @@ pub async fn handle_bun_job( } else { // if !*DISABLE_NSJAIL || !empty_trusted_deps || has_custom_config_registry { let logs1 = "\n\n--- BUN INSTALL ---\n".to_string(); - append_logs(&job.id, &job.workspace_id, logs1, db).await; + append_logs(&job.id, &job.workspace_id, logs1, conn).await; let _ = gen_bun_lockfile( mem_peak, canceled_by, &job.id, &job.workspace_id, - Some(db), + Some(conn), &client.token, job.runnable_path(), job_dir, @@ -1104,12 +1118,13 @@ try {{ let reserved_variables_args_out_f = async { let args_and_out_f = async { if !annotation.native { - create_args_and_out_file(&client, job, job_dir, db).await?; + create_args_and_out_file(&client, job, job_dir, conn).await?; } Ok(()) as Result<()> }; let reserved_variables_f = async { - let vars = get_reserved_variables(job, &client.token, db, parent_runnable_path).await?; + let vars = + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; Ok(vars) as Result> }; let (_, reserved_variables) = tokio::try_join!(args_and_out_f, reserved_variables_f)?; @@ -1172,7 +1187,7 @@ try {{ &job.workspace_id, &job.id, worker_name, - Some(db.clone()), + Some(conn), job.timeout, mem_peak, canceled_by, @@ -1181,7 +1196,14 @@ try {{ ) .await?; if !local_path.is_empty() { - match save_cache(&local_path, &remote_path, &format!("{job_dir}/main.js")).await { + match save_cache( + &local_path, + &remote_path, + &format!("{job_dir}/main.js"), + false, + ) + .await + { Err(e) => { let em = format!("could not save {local_path} to bundle cache: {e:?}"); tracing::error!(em) @@ -1214,7 +1236,7 @@ try {{ &job.workspace_id, &job.id, worker_name, - db, + conn, job.timeout, mem_peak, canceled_by, @@ -1244,7 +1266,7 @@ try {{ .join("\n")); let js_code = read_file_content(&format!("{job_dir}/main.js")).await?; let started_at = Instant::now(); - let args = crate::common::build_args_map(job, client, db) + let args = crate::common::build_args_map(job, client, conn) .await? .map(sqlx::types::Json); let job_args = if args.is_some() { @@ -1253,16 +1275,17 @@ try {{ job.args.as_ref() }; - append_logs(&job.id, &job.workspace_id, format!("{init_logs}\n"), db).await; + append_logs(&job.id, &job.workspace_id, format!("{init_logs}\n"), conn).await; let result = crate::js_eval::eval_fetch_timeout( env_code, inner_content.clone(), js_code, job_args, + job.script_entrypoint_override.clone(), job.id, job.timeout, - db, + conn, mem_peak, canceled_by, worker_name, @@ -1278,7 +1301,7 @@ try {{ return Ok(result); } } - append_logs(&job.id, &job.workspace_id, init_logs, db).await; + append_logs(&job.id, &job.workspace_id, init_logs, conn).await; //do not cache local dependencies let child = if !*DISABLE_NSJAIL { @@ -1410,7 +1433,7 @@ try {{ handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -1421,6 +1444,7 @@ try {{ job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await?; @@ -1519,7 +1543,7 @@ pub async fn start_worker( annotation.nodejs = true; let context = variables::get_reserved_variables( - db, + &Connection::from(db.clone()), w_id, &token, "dedicated_worker@windmill.dev", @@ -1570,7 +1594,7 @@ pub async fn start_worker( &mut canceled_by, &Uuid::nil(), &w_id, - Some(db), + Some(&Connection::from(db.clone())), job_dir, worker_name, common_bun_proc_envs.clone(), @@ -1587,7 +1611,7 @@ pub async fn start_worker( &mut canceled_by, &Uuid::nil(), &w_id, - Some(db), + Some(&Connection::from(db.clone())), token, &script_path, job_dir, @@ -1688,7 +1712,7 @@ for await (const line of Readline.createInterface({{ input: process.stdin }})) { w_id, &Uuid::nil(), worker_name, - db, + &Connection::from(db.clone()), None, &mut mem_peak, &mut canceled_by, diff --git a/backend/windmill-worker/src/common.rs b/backend/windmill-worker/src/common.rs index cd4f26b776..2699b89d02 100644 --- a/backend/windmill-worker/src/common.rs +++ b/backend/windmill-worker/src/common.rs @@ -11,6 +11,7 @@ use sha2::Digest; use sqlx::types::Json; use sqlx::{Pool, Postgres}; use tokio::process::Command; +use tokio::sync::{RwLock, Semaphore}; use tokio::{fs::File, io::AsyncReadExt}; #[cfg(feature = "parquet")] @@ -19,7 +20,8 @@ use windmill_common::s3_helpers::{ }; use windmill_common::variables::{build_crypt_with_key_suffix, decrypt}; use windmill_common::worker::{ - to_raw_value, write_file, CLOUD_HOSTED, ROOT_CACHE_DIR, WORKER_CONFIG, + to_raw_value, update_ping_for_failed_init_script_query, write_file, Connection, Ping, PingType, + CLOUD_HOSTED, ROOT_CACHE_DIR, WORKER_CONFIG, }; use windmill_common::{ cache::{Cache, RawData}, @@ -28,9 +30,10 @@ use windmill_common::{ variables::ContextualVariable, }; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use windmill_queue::MiniPulledJob; +use std::ops::AsyncFn; use std::path::Path; use std::{collections::HashMap, sync::Arc, time::Duration}; @@ -39,15 +42,19 @@ use windmill_common::{variables, DB}; use tokio::{io::AsyncWriteExt, process::Child, time::Instant}; -use crate::{AuthedClient, JOB_DEFAULT_TIMEOUT, MAX_RESULT_SIZE, MAX_TIMEOUT_DURATION, PATH_ENV}; +use crate::agent_workers::UPDATE_PING_URL; +use crate::{ + AuthedClient, DISABLE_NSJAIL, JOB_DEFAULT_TIMEOUT, MAX_RESULT_SIZE, MAX_TIMEOUT_DURATION, + PATH_ENV, +}; pub async fn build_args_map<'a>( job: &'a MiniPulledJob, client: &AuthedClient, - db: &Pool, + conn: &Connection, ) -> error::Result>>> { if let Some(args) = &job.args { - return transform_json(client, &job.workspace_id, &args.0, &job, db).await; + return transform_json(client, &job.workspace_id, &args.0, &job, conn).await; } return Ok(None); } @@ -72,10 +79,10 @@ pub fn check_executor_binary_exists( pub async fn build_args_values( job: &MiniPulledJob, client: &AuthedClient, - db: &Pool, + conn: &Connection, ) -> error::Result> { if let Some(args) = &job.args { - transform_json_as_values(client, &job.workspace_id, &args.0, job, db).await + transform_json_as_values(client, &job.workspace_id, &args.0, job, conn).await } else { Ok(HashMap::new()) } @@ -86,10 +93,10 @@ pub async fn create_args_and_out_file( client: &AuthedClient, job: &MiniPulledJob, job_dir: &str, - db: &Pool, + conn: &Connection, ) -> Result<(), Error> { if let Some(args) = job.args.as_ref() { - if let Some(x) = transform_json(client, &job.workspace_id, &args.0, job, db).await? { + if let Some(x) = transform_json(client, &job.workspace_id, &args.0, job, conn).await? { write_file( job_dir, "args.json", @@ -127,7 +134,7 @@ pub async fn transform_json<'a>( workspace: &str, vs: &'a HashMap>, job: &MiniPulledJob, - db: &Pool, + db: &Connection, ) -> error::Result>>> { let mut has_match = false; for (_, v) in vs { @@ -164,7 +171,7 @@ pub async fn transform_json_as_values<'a>( workspace: &str, vs: &'a HashMap>, job: &MiniPulledJob, - db: &Pool, + db: &Connection, ) -> error::Result> { let mut r: HashMap = HashMap::new(); for (k, v) in vs { @@ -232,7 +239,7 @@ pub async fn transform_json_value( workspace: &str, v: Value, job: &MiniPulledJob, - db: &Pool, + conn: &Connection, ) -> error::Result { match v { Value::String(y) if y.starts_with("$var:") => { @@ -263,20 +270,32 @@ pub async fn transform_json_value( }) } Value::String(y) if y.starts_with("$encrypted:") => { - let encrypted = y.strip_prefix("$encrypted:").unwrap(); + match conn { + Connection::Sql(db) => { + let encrypted = y.strip_prefix("$encrypted:").unwrap(); - let root_job_id = - get_root_job_id(&job.flow_innermost_root_job.unwrap_or_else(|| job.id), db).await?; - let mc = build_crypt_with_key_suffix(&db, &job.workspace_id, &root_job_id.to_string()) - .await?; - decrypt(&mc, encrypted.to_string()).and_then(|x| { - serde_json::from_str(&x).map_err(|e| Error::internal_err(e.to_string())) - }) + let root_job_id = + get_root_job_id(&job.flow_innermost_root_job.unwrap_or_else(|| job.id), db) + .await?; + let mc = build_crypt_with_key_suffix( + &db, + &job.workspace_id, + &root_job_id.to_string(), + ) + .await?; + decrypt(&mc, encrypted.to_string()).and_then(|x| { + serde_json::from_str(&x).map_err(|e| Error::internal_err(e.to_string())) + }) + } + Connection::Http(_) => { + Err(Error::NotFound("Http connection not supported".to_string())) + } + } // let path = y.strip_prefix("$res:").unwrap(); } Value::String(y) if y.starts_with("$") => { - let variables = get_reserved_variables(job, &client.token, &db, None).await?; + let variables = get_reserved_variables(job, &client.token, conn, None).await?; let name = y.strip_prefix("$").unwrap(); @@ -291,7 +310,7 @@ pub async fn transform_json_value( for (a, b) in m.clone().into_iter() { m.insert( a.clone(), - transform_json_value(&a, client, workspace, b, job, &db).await?, + transform_json_value(&a, client, workspace, b, job, conn).await?, ); } Ok(Value::Object(m)) @@ -383,16 +402,21 @@ pub fn capitalize(s: &str) -> String { pub async fn get_reserved_variables( job: &MiniPulledJob, token: &str, - db: &sqlx::Pool, + db: &Connection, parent_runnable_path: Option, ) -> Result, Error> { let flow_path = if parent_runnable_path.is_some() { parent_runnable_path } else if let Some(uuid) = job.parent_job { - sqlx::query_scalar!("SELECT runnable_path FROM v2_job WHERE id = $1", uuid) - .fetch_optional(db) - .await? - .flatten() + match db { + Connection::Sql(db) => { + sqlx::query_scalar!("SELECT runnable_path FROM v2_job WHERE id = $1", uuid) + .fetch_optional(db) + .await? + .flatten() + } + Connection::Http(_) => None, + } } else { None }; @@ -453,26 +477,57 @@ pub fn sizeof_val(v: &serde_json::Value) -> usize { } pub async fn update_worker_ping_for_failed_init_script( - db: &DB, + conn: &Connection, worker_name: &str, last_job_id: Uuid, ) { - if let Err(e) = sqlx::query!( - "UPDATE worker_ping SET - ping_at = now(), - jobs_executed = 1, - current_job_id = $1, - current_job_workspace_id = 'admins' - WHERE worker = $2", - last_job_id, - worker_name - ) - .execute(db) - .await - { - tracing::error!("Error updating worker ping for failed init script: {e:?}"); + match conn { + Connection::Sql(db) => { + if let Err(e) = + update_ping_for_failed_init_script_query(worker_name, last_job_id, db).await + { + tracing::error!("Error updating worker ping for failed init script: {e:?}"); + } + } + Connection::Http(client) => { + if let Err(e) = client + .post::<_, ()>( + UPDATE_PING_URL, + &Ping { + last_job_executed: Some(last_job_id), + last_job_workspace_id: None, + worker_instance: None, + ip: None, + tags: None, + dw: None, + jobs_executed: None, + occupancy_rate: None, + occupancy_rate_15s: None, + occupancy_rate_5m: None, + occupancy_rate_30m: None, + version: None, + vcpus: None, + memory: None, + memory_usage: None, + wm_memory_usage: None, + ping_type: PingType::InitScript, + }, + ) + .await + { + tracing::error!("Error updating worker ping for failed init script: {e:?}"); + } + } } } + +pub fn error_to_value(err: Error) -> serde_json::Value { + match err { + Error::JsonErr(err) => err, + _ => json!({"message": err.to_string(), "name": "InternalErr"}), + } +} + pub struct OccupancyMetrics { pub running_job_started_at: Option, pub total_duration_of_running_jobs: f32, @@ -480,6 +535,13 @@ pub struct OccupancyMetrics { pub start_time: Instant, } +pub struct OccupancyResult { + pub occupancy_rate: f32, + pub occupancy_rate_15s: Option, + pub occupancy_rate_5m: Option, + pub occupancy_rate_30m: Option, +} + impl OccupancyMetrics { pub fn new(start_time: Instant) -> Self { OccupancyMetrics { @@ -490,7 +552,7 @@ impl OccupancyMetrics { } } - pub fn update_occupancy_metrics(&mut self) -> (f32, Option, Option, Option) { + pub fn update_occupancy_metrics(&mut self) -> OccupancyResult { let metrics = self; let current_occupied_duration = metrics .running_job_started_at @@ -541,12 +603,12 @@ impl OccupancyMetrics { .worker_occupancy_rate_history .push((total_occupation, elapsed)); - ( + OccupancyResult { occupancy_rate, occupancy_rate_15s, occupancy_rate_5m, occupancy_rate_30m, - ) + } } } @@ -557,15 +619,19 @@ pub async fn start_child_process(mut cmd: Command, executable: &str) -> Result, + _conn: &Connection, _w_id: &str, _job_id: Uuid, custom_timeout_secs: Option, ) -> (Duration, Option, bool) { let mut warn_msg: Option = None; #[cfg(feature = "cloud")] - let cloud_premium_workspace = - *CLOUD_HOSTED && windmill_common::workspaces::is_premium_workspace(_db, _w_id).await; + let cloud_premium_workspace = *CLOUD_HOSTED + && windmill_common::workspaces::is_premium_workspace( + _conn.as_sql().expect("cloud cannot use http connection"), + _w_id, + ) + .await; #[cfg(not(feature = "cloud"))] let cloud_premium_workspace = false; @@ -837,7 +903,7 @@ pub async fn get_cached_resource_value_if_valid( S3Object { s3: s3_file_key.clone(), storage: resource.storage.clone(), - filename: None, + ..Default::default() }, ) .await; @@ -946,3 +1012,570 @@ pub fn build_http_client(timeout_duration: std::time::Duration) -> error::Result .build() .map_err(|e| Error::internal_err(format!("Error building http client: {e:#}"))) } + +#[derive(Clone)] +pub struct RequiredDependency { + /// Expected directory of dependency in cache + /// For example: + /// /tmp/windmill/cache/python_311/rich==0.0.0 + /// IMPORTANT!: path should not end with '/' + pub path: String, + /// Name to use for S3 tars + /// If not specified will use top level directory of path. + pub custom_name: Option, + /// Display name + /// Name that will be used for console output and logging + /// If not specified will either use custom_name or top level directory of path. + pub short_name: Option, +} + +pub enum InstallStrategy { + /// Will invoke callback to install single dependency + Single(Arc Result + Send + Sync>), + /// Will try to pull S3 first and will invoke closure to install the rest + AllAtOnce(Arc) -> Result + Send + Sync>), +} +/// # General +/// +/// Languages that compile usually include dependencies in final executable. +/// When dynamic languages do not and runtime dependencies provided separately. +/// +/// This helper implies that the language is dynamic. +/// Python, Ruby, Java are dynamic and they can use this helper. +/// +/// # Features +/// +/// This helper will install all specified dependencies in parallel and if it is EE, cache to S3 +/// It has atomic success file, allowing to distinguish failed installations from succesfull. +/// +/// Besides that it provides console output and does logging. +/// +/// # Usage +/// +/// Most important arguments in this helper are `deps` and `install_fn` +/// +/// In `deps` you specify all dependencies that are needed to be on worker in order to execute script. +/// You don't know which are actually installed and which are not. +/// +/// `deps` is a vector of RequiredDependency. Check [RequiredDependency] for more context. +/// +/// After `deps` are provided helper will check each dependency and check if it is in cache, if not it will try to pull from S3 +/// and if it does not work either, it will invoke `install_fn` closure. +/// Closure arguments has dependency name as well as it`s expected path in cache. +/// Closure should return Command that will install dependency to asked place. +pub async fn par_install_language_dependencies<'a>( + deps: Vec, + language_name: &'a str, + installer_executable_name: &'a str, + platform_agnostic: bool, + concurrent_downloads: usize, + stdout_on_err: bool, + install_fn: InstallStrategy, + postinstall_cb: impl AsyncFn(Vec) -> Result<(), error::Error>, + job_id: &'a Uuid, + w_id: &'a str, + worker_name: &'a str, + conn: &Connection, +) -> anyhow::Result<()> { + #[cfg(not(all(feature = "enterprise", feature = "parquet")))] + let _ = (platform_agnostic, language_name); + + let total_time = std::time::Instant::now(); + + // Total to install + let mut not_installed = vec![]; + let total_to_install; + // let mut not_installed = vec![]; + let counter_arc = Arc::new(tokio::sync::Mutex::new(0)); + // Append logs with line like this: + // [9/21] + requests==2.32.3 << (S3) | in 57ms + #[allow(unused_assignments)] + async fn print_success( + mut s3_pull: bool, + mut s3_push: bool, + job_id: &Uuid, + w_id: &str, + req: &str, + req_tl: usize, + counter_arc: Arc>, + total_to_install: usize, + instant: std::time::Instant, + conn: &Connection, + ) { + #[cfg(not(all(feature = "enterprise", feature = "parquet")))] + { + (s3_pull, s3_push) = (false, false); + } + + #[cfg(all(feature = "enterprise", feature = "parquet"))] + if windmill_common::s3_helpers::OBJECT_STORE_CACHE_SETTINGS + .read() + .await + .is_none() + { + (s3_pull, s3_push) = (false, false); + } + + let mut counter = counter_arc.lock().await; + *counter += 1; + + windmill_queue::append_logs( + job_id, + w_id, + format!( + "\n{}+ {}{}{}| in {}ms", + windmill_common::worker::pad_string( + &format!("[{}/{total_to_install}]", counter), + 9 + ), + // Because we want to align to max len [999/999] we take 9 + // 123456789 + windmill_common::worker::pad_string(&req, req_tl + 1), + // Margin to the right ^ + if s3_pull { "<< (S3) " } else { "" }, + if s3_push { " > (S3) " } else { "" }, + instant.elapsed().as_millis(), + ), + conn, + ) + .await; + // Drop lock, so next print success can fire + } + + let mut name_tl = 0; + struct NotInstalledDependency { + path: String, + custom_name: Option, + short_name: Option, + display_name: String, + } + { + let mut to_be_installed_is_used = false; + for RequiredDependency { + path, // + custom_name, + short_name, + } in deps.into_iter() + { + if path.ends_with("/") { + anyhow::bail!("Internal error: path should not end with '/'") + } + let display_name = short_name + .as_ref() + .or(custom_name.as_ref()) + .or(path.split("/").last().map(|e| e.to_owned()).as_ref()) + .unwrap_or_else(|| { + tracing::warn!( + workspace_id = %w_id, + job_id = %job_id, + "failed to parse top level directory name for {path}, fallback to full path.", + ); + + &path + }) + .to_owned(); + { + // Later will help us align text in log console + if display_name.len() > name_tl { + name_tl = display_name.len(); + } + } + // Will look like: /tmp/windmill/cache/lang/dependency.valid.windmill + if tokio::fs::metadata(path.clone() + ".valid.windmill") + .await + .is_err() + { + if !to_be_installed_is_used { + windmill_queue::append_logs( + job_id, + w_id, + format!("\n--- INSTALLATION ---\n\nTo be installed:\n\n"), + conn, + ) + .await; + to_be_installed_is_used = true; + } + windmill_queue::append_logs(job_id, w_id, format!("- {display_name}\n"), conn) + .await; + not_installed.push(NotInstalledDependency { + path, + custom_name, + short_name, + display_name, + }); + } + } + } + total_to_install = not_installed.len(); + if total_to_install == 0 { + return Ok(()); + } + #[cfg(all(feature = "enterprise", feature = "parquet"))] + let is_not_pro = !matches!( + windmill_common::ee::get_license_plan().await, + windmill_common::ee::LicensePlan::Pro + ); + #[cfg(all(feature = "enterprise", feature = "parquet"))] + if is_not_pro && matches!(install_fn, InstallStrategy::AllAtOnce(_)) { + windmill_queue::append_logs( + job_id, + w_id, + format!("\nLooking for packages on S3:\n"), + conn, + ) + .await; + } + + // Parallelism level (N) + let parallel_limit = // Semaphore will panic if value less then 1 + concurrent_downloads.clamp(1, 30); + + tracing::info!( + workspace_id = %w_id, + "Install parallel limit: {}, job: {}", + parallel_limit, + job_id + ); + + let mut handles = vec![]; + let semaphore = Arc::new(Semaphore::new(parallel_limit)); + let not_pulled = Arc::new(RwLock::new(vec![])); + // let mut handles = Vec::with_capacity(total_to_install); + for NotInstalledDependency { + // + path, + custom_name, + short_name, + display_name, + } in not_installed + { + let permit = semaphore.clone().acquire_owned().await; // Acquire a permit + + if let Err(_) = permit { + tracing::error!( + workspace_id = %w_id, + "Cannot acquire permit on semaphore, that can only mean that semaphore has been closed." + ); + break; + } + + let permit = permit.unwrap(); + + #[cfg(all(feature = "enterprise", feature = "parquet"))] + let s3_pull_future = if is_not_pro { + if let Some(os) = windmill_common::s3_helpers::OBJECT_STORE_CACHE_SETTINGS + .read() + .await + .clone() + { + Some(crate::global_cache::pull_from_tar( + os, + path.clone(), + language_name.to_owned(), + custom_name.clone(), + platform_agnostic, + )) + } else { + None + } + } else { + None + }; + let child = { + if let InstallStrategy::Single(ref callback, ..) = install_fn { + let cmd = callback(RequiredDependency { + path: path.clone(), + custom_name: custom_name.clone(), + short_name: short_name.clone(), + })?; + tracing::debug!("{:?}", &cmd); + Some(start_child_process(cmd, &installer_executable_name).await?) + } else { + None + } + }; + + let ( + worker_name_2, + path_2, + display_name_2, + custom_name, + job_id_2, + w_id_2, + conn_2, + counter_arc, + language_name, + installer_executable_name, + not_pulled, + ) = ( + worker_name.to_owned(), + path.clone(), + display_name.clone(), + custom_name.clone(), + job_id.clone(), + w_id.to_owned(), + conn.clone(), + counter_arc.clone(), + language_name.to_owned(), + installer_executable_name.to_owned(), + not_pulled.clone(), + ); + #[cfg(not(all(feature = "enterprise", feature = "parquet")))] + let _ = language_name; + + let start = std::time::Instant::now(); + let handle = tokio::spawn(async move { + let _permit = permit; + + #[cfg(all(feature = "enterprise", feature = "parquet"))] + if let Some(s3_pull_future) = s3_pull_future { + if let Err(e) = s3_pull_future.await { + tracing::info!( + workspace_id = %w_id_2, + "No tarball was found for {:?} on S3 or different problem occured {job_id_2}:\n{e}", + &custom_name.clone().unwrap_or(path) + ); + } else { + // TODO: Refactor + // Create a file to indicate that installation was successfull + let valid_path = path_2.clone() + ".valid.windmill"; + // This is atomic operation, meaning, that it either completes and dependency is valid, + // or it does not and dependency is invalid and will be reinstalled next run + if let Err(e) = File::create(&valid_path).await { + tracing::error!( + workspace_id = %w_id_2, + job_id = %job_id_2, + "Failed to create {}!\n{e}\n + This file needed for jobs to function", + valid_path + ); + }; + print_success( + true, + false, + &job_id_2, + &w_id_2, + &display_name_2, + name_tl, + counter_arc, + total_to_install, + start, + &conn_2, + ) + .await; + return; + } + } + + let Some(child) = child else { + let mut lock = not_pulled.write().await; + lock.push(RequiredDependency { + path: path_2.clone(), + custom_name: custom_name.clone(), + short_name: short_name.clone(), + }); + return; + }; + if let Err(e) = crate::handle_child::handle_child( + &job_id_2, + &conn_2, + // TODO: Return mem_peak + &mut 0, + // TODO: Return canceld_by_ref + &mut None, + child, + !*DISABLE_NSJAIL, + &worker_name_2, + &w_id_2, + &installer_executable_name, + None, + false, + &mut None, + None, + ) + .await + { + windmill_queue::append_logs( + &job_id_2, + &w_id_2, + format!("error while installing {}: {e:?}", &display_name_2), + &conn_2, + ) + .await; + } else { + // if let Some(cb) = postinstall_cb { + // if let Err(e) = cb(vec![RequiredDependency { + // path: path_2.clone(), + // custom_name: custom_name.clone(), + // short_name: short_name.clone(), + // }]) + // .await + // { + // tracing::error!( + // workspace_id = %w_id_2, + // job_id = %job_id_2, + // "Postinstall callback failed!\n{e}\n + // This might affect execution", + // ); + // } + // } + print_success( + false, + true, + &job_id_2, + &w_id_2, + &display_name_2, + name_tl, + counter_arc, + total_to_install, + start, + &conn_2, + ) + .await; + // TODO: Refactor + // Create a file to indicate that installation was successfull + let valid_path = path_2.clone() + ".valid.windmill"; + // This is atomic operation, meaning, that it either completes and dependency is valid, + // or it does not and dependency is invalid and will be reinstalled next run + if let Err(e) = File::create(&valid_path).await { + tracing::error!( + workspace_id = %w_id_2, + job_id = %job_id_2, + "Failed to create {}!\n{e}\n + This file needed for jobs to function", + valid_path + ); + }; + #[cfg(all(feature = "enterprise", feature = "parquet"))] + { + if let Some(os) = windmill_common::s3_helpers::OBJECT_STORE_CACHE_SETTINGS + .read() + .await + .clone() + { + tokio::spawn(async move { + if let Err(e) = crate::global_cache::build_tar_and_push( + os, + path_2, + language_name, + custom_name, + platform_agnostic, + ) + .await + { + tracing::warn!("failed to build tar and push: {e:?}"); + } + }); + } + } + } + }); + handles.push(handle); + } + + for handle in handles { + if let Err(e) = handle.await { + tracing::error!("Error joining handles: {e:?}"); + } + } + if !not_pulled.read().await.is_empty() { + if let InstallStrategy::AllAtOnce(ref callback, ..) = install_fn { + let not_pulled_copy = not_pulled.read().await.clone(); + windmill_queue::append_logs( + job_id, + w_id, + format!("\n\nFetching {} packages...\n", not_pulled_copy.len()), + &conn, + ) + .await; + let cmd = callback(not_pulled_copy.clone())?; + tracing::debug!("{:?}", &cmd); + let child = start_child_process(cmd, &installer_executable_name).await?; + let mut buf = "".to_owned(); + let pipe_stdout = if stdout_on_err { Some(&mut buf) } else { None }; + if let Err(e) = crate::handle_child::handle_child( + // &job_id, + &Uuid::nil(), + &conn, + // TODO: Return mem_peak + &mut 0, + // TODO: Return canceld_by_ref + &mut None, + child, + !*DISABLE_NSJAIL, + &worker_name, + &w_id, + &installer_executable_name, + None, + false, + &mut None, + pipe_stdout, + ) + .await + { + bail!(format!( + "error while installing dependencies: {e:?}\n{}", + buf + )); + } + { + postinstall_cb(not_pulled_copy.clone()).await?; + } + for RequiredDependency { path, custom_name: _custom_name, .. } in + not_pulled_copy.into_iter() + { + // TODO: Refactor + // Create a file to indicate that installation was successfull + let valid_path = path.clone() + ".valid.windmill"; + // This is atomic operation, meaning, that it either completes and dependency is valid, + // or it does not and dependency is invalid and will be reinstalled next run + if let Err(e) = File::create(&valid_path).await { + tracing::error!( + workspace_id = %w_id, + job_id = %job_id, + "Failed to create {}!\n{e}\n + This file needed for jobs to function", + valid_path + ); + }; + #[cfg(all(feature = "enterprise", feature = "parquet"))] + { + if let Some(os) = windmill_common::s3_helpers::OBJECT_STORE_CACHE_SETTINGS + .read() + .await + .clone() + { + let language_name = language_name.to_owned(); + tokio::spawn(async move { + if let Err(e) = crate::global_cache::build_tar_and_push( + os, + path, + language_name, + _custom_name, + platform_agnostic, + ) + .await + { + tracing::warn!("failed to build tar and push: {e:?}"); + } + }); + } + } + } + } + } + { + let total_time = total_time.elapsed().as_millis(); + windmill_queue::append_logs( + &job_id, + w_id, + format!( + "\nDone. Time spent on installation phase: {}ms\n", + total_time + ), + conn, + ) + .await; + } + Ok(()) +} diff --git a/backend/windmill-worker/src/csharp_executor.rs b/backend/windmill-worker/src/csharp_executor.rs index 9acb32b684..2054e279db 100644 --- a/backend/windmill-worker/src/csharp_executor.rs +++ b/backend/windmill-worker/src/csharp_executor.rs @@ -67,7 +67,7 @@ pub async fn generate_nuget_lockfile( mem_peak: &mut i32, canceled_by: &mut Option, job_dir: &str, - db: &sqlx::Pool, + conn: &Connection, worker_name: &str, w_id: &str, occupancy_metrics: &mut OccupancyMetrics, @@ -115,7 +115,7 @@ pub async fn generate_nuget_lockfile( let gen_lockfile_process = start_child_process(gen_lockfile_cmd, DOTNET_PATH.as_str()).await?; handle_child( job_id, - db, + conn, mem_peak, canceled_by, gen_lockfile_process, @@ -126,6 +126,7 @@ pub async fn generate_nuget_lockfile( None, false, &mut Some(occupancy_metrics), + None, ) .await?; @@ -149,7 +150,7 @@ pub async fn generate_nuget_lockfile( _mem_peak: &mut i32, _canceled_by: &mut Option, _job_dir: &str, - _db: &sqlx::Pool, + _conn: &Connection, _worker_name: &str, _w_id: &str, _occupancy_metrics: &mut OccupancyMetrics, @@ -310,7 +311,7 @@ async fn build_cs_proj( mem_peak: &mut i32, canceled_by: &mut Option, job_dir: &str, - db: &sqlx::Pool, + conn: &Connection, worker_name: &str, w_id: &str, base_internal_url: &str, @@ -370,7 +371,7 @@ async fn build_cs_proj( let build_cs_process = start_child_process(build_cs_cmd, DOTNET_PATH.as_str()).await?; handle_child( job_id, - db, + conn, mem_peak, canceled_by, build_cs_process, @@ -381,9 +382,10 @@ async fn build_cs_proj( None, false, &mut Some(occupancy_metrics), + None, ) .await?; - append_logs(job_id, w_id, "\n\n", db).await; + append_logs(job_id, w_id, "\n\n", conn).await; if let Err(e) = std::fs::remove_file(Path::new(job_dir).join("nuget.config")) { if e.kind() != io::ErrorKind::NotFound { Err(anyhow!("Error erasing nuget.config: {}", e))?; @@ -400,6 +402,7 @@ async fn build_cs_proj( &bin_path, &format!("{CSHARP_OBJECT_STORE_PREFIX}{hash}"), &target, + false, ) .await { @@ -425,6 +428,7 @@ fn remove_lines_from_text(contents: &str, indices_to_remove: Vec) -> Stri result.join("\n") } +use windmill_common::worker::Connection; use windmill_queue::MiniPulledJob; #[cfg(not(feature = "csharp"))] @@ -432,7 +436,7 @@ pub async fn handle_csharp_job( _mem_peak: &mut i32, _canceled_by: &mut Option, _job: &MiniPulledJob, - _db: &sqlx::Pool, + _conn: &Connection, _client: &AuthedClient, _parent_runnable_path: Option, _inner_content: &str, @@ -446,13 +450,12 @@ pub async fn handle_csharp_job( ) -> Result, Error> { Err(anyhow!("C# is not available because the feature is not enabled").into()) } - #[cfg(feature = "csharp")] pub async fn handle_csharp_job( mem_peak: &mut i32, canceled_by: &mut Option, job: &MiniPulledJob, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, inner_content: &str, @@ -474,7 +477,8 @@ pub async fn handle_csharp_job( let bin_path = format!("{}/{hash}", CSHARP_CACHE_DIR); let remote_path = format!("{CSHARP_OBJECT_STORE_PREFIX}{hash}"); - let (cache, cache_logs) = windmill_common::worker::load_cache(&bin_path, &remote_path).await; + let (cache, cache_logs) = + windmill_common::worker::load_cache(&bin_path, &remote_path, false).await; let cache_logs = if cache { #[cfg(unix)] @@ -491,7 +495,7 @@ pub async fn handle_csharp_job( cache_logs } else { let logs1 = format!("{cache_logs}\n\n--- DOTNET BUILD ---\n"); - append_logs(&job.id, &job.workspace_id, logs1, db).await; + append_logs(&job.id, &job.workspace_id, logs1, conn).await; let (reqs, lines_to_remove) = parse_csharp_reqs(inner_content); for req in &reqs { @@ -503,7 +507,7 @@ pub async fn handle_csharp_job( req.0, req.1.as_ref().unwrap_or(&"".to_string()) ), - db, + conn, ) .await; } @@ -521,7 +525,7 @@ pub async fn handle_csharp_job( mem_peak, canceled_by, job_dir, - db, + conn, worker_name, &job.workspace_id, base_internal_url, @@ -531,13 +535,13 @@ pub async fn handle_csharp_job( .await? }; - create_args_and_out_file(client, job, job_dir, db).await?; + create_args_and_out_file(client, job, job_dir, conn).await?; let logs2 = format!("{cache_logs}\n\n--- C# CODE EXECUTION ---\n"); - append_logs(&job.id, &job.workspace_id, format!("{}\n", logs2), db).await; + append_logs(&job.id, &job.workspace_id, format!("{}\n", logs2), conn).await; let reserved_variables = - get_reserved_variables(job, &client.token, db, parent_runnable_path).await?; + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; let child = if !*DISABLE_NSJAIL { write_file( @@ -623,7 +627,7 @@ pub async fn handle_csharp_job( handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -634,6 +638,7 @@ pub async fn handle_csharp_job( job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await?; read_result(job_dir).await diff --git a/backend/windmill-worker/src/dedicated_worker.rs b/backend/windmill-worker/src/dedicated_worker.rs index 2b63a6d28a..33a83a1492 100644 --- a/backend/windmill-worker/src/dedicated_worker.rs +++ b/backend/windmill-worker/src/dedicated_worker.rs @@ -29,9 +29,7 @@ use windmill_queue::MiniPulledJob; use anyhow::Context; -use crate::{ - common::start_child_process, JobCompleted, JobCompletedSender, MAX_BUFFERED_DEDICATED_JOBS, -}; +use crate::{common::start_child_process, JobCompletedSender, MAX_BUFFERED_DEDICATED_JOBS}; use futures::{future, Future}; use std::{collections::HashMap, task::Poll}; @@ -78,7 +76,7 @@ pub async fn handle_dedicated_process( ) -> std::result::Result<(), error::Error> { //do not cache local dependencies - use windmill_queue::MiniPulledJob; + use windmill_queue::{JobCompleted, MiniPulledJob}; use crate::{handle_child::process_status, PROXY_ENVS}; let cmd_name = format!("dedicated {command_path}"); @@ -187,16 +185,16 @@ pub async fn handle_dedicated_process( 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).await; + append_logs(&job.id, &job.workspace_id, logs.clone(), &db.into()).await; if line.starts_with("wm_res[success]:") { - job_completed_tx.send(JobCompleted { job , result, result_columns: None, mem_peak: 0, canceled_by: None, success: true, cached_res_path: None, token: token.to_string(), duration: None }).await.unwrap() + 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 }).await.unwrap() } else { - job_completed_tx.send(JobCompleted { job , result, result_columns: None, mem_peak: 0, canceled_by: None, success: false, cached_res_path: None, token: token.to_string(), duration: None }).await.unwrap() + 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 }).await.unwrap() } }, Err(e) => { tracing::error!("Could not deserialize job result `{line}`: {e:?}"); - job_completed_tx.send(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 }).await.unwrap(); + 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 }).await.unwrap(); }, }; logs = init_log.clone(); @@ -397,13 +395,16 @@ async fn spawn_dedicated_workers_for_flow( } } FlowModuleValue::FlowScript { id, language, .. } => { - let spawn = cache::flow::fetch_script(db, *id).await.map(|data| { - SpawnWorker::RawScript { - path: "".to_string(), - content: data.code.clone(), - lock: data.lock.clone(), - lang: *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) => { @@ -571,7 +572,7 @@ async fn spawn_dedicated_worker( }; use windmill_queue::MiniPulledJob; - use crate::{build_envs, get_script_content_by_hash, ContentReqLangEnvs, JOB_TOKEN}; + use crate::{build_envs, get_script_content_by_hash, ContentReqLangEnvs}; #[cfg(not(feature = "enterprise"))] { @@ -586,7 +587,7 @@ async fn spawn_dedicated_worker( std::sync::Arc, >(MAX_BUFFERED_DEDICATED_JOBS); let killpill_rx = killpill_rx.resubscribe(); - let db = db.clone(); + 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(); @@ -613,11 +614,11 @@ async fn spawn_dedicated_worker( 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, &db).await.map( - |r: ContentReqLangEnvs| { + 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 @@ -626,7 +627,7 @@ async fn spawn_dedicated_worker( ) .bind(&path) .bind(&w_id) - .fetch_optional(&db) + .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 }))) @@ -658,10 +659,9 @@ async fn spawn_dedicated_worker( _ => return None, } + let db = db.clone(); let handle = tokio::spawn(async move { - let token = if let Some(token) = JOB_TOKEN.as_ref() { - token.clone() - } else { + let token = { let token = rd_string(32); if let Err(e) = sqlx::query_scalar!( "INSERT INTO token diff --git a/backend/windmill-worker/src/deno_executor.rs b/backend/windmill-worker/src/deno_executor.rs index 2b93c86ab4..696957f463 100644 --- a/backend/windmill-worker/src/deno_executor.rs +++ b/backend/windmill-worker/src/deno_executor.rs @@ -15,8 +15,11 @@ use crate::{ PATH_ENV, TZ_ENV, }; use tokio::{fs::File, io::AsyncReadExt, process::Command}; -use windmill_common::error::{self}; use windmill_common::{error::Result, worker::write_file, BASE_URL}; +use windmill_common::{ + error::{self}, + worker::Connection, +}; use windmill_parser::Typ; lazy_static::lazy_static! { @@ -97,7 +100,7 @@ pub async fn generate_deno_lock( mem_peak: &mut i32, canceled_by: &mut Option, job_dir: &str, - db: Option<&sqlx::Pool>, + db: Option<&Connection>, w_id: &str, worker_name: &str, base_internal_url: &str, @@ -156,6 +159,7 @@ pub async fn generate_deno_lock( None, false, occupancy_metrics, + None, ) .await?; } else { @@ -178,7 +182,7 @@ pub async fn handle_deno_job( mem_peak: &mut i32, canceled_by: &mut Option, job: &MiniPulledJob, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, job_dir: &str, @@ -191,7 +195,7 @@ pub async fn handle_deno_job( ) -> error::Result> { // let mut start = Instant::now(); let logs1 = "\n\n--- DENO CODE EXECUTION ---\n".to_string(); - append_logs(&job.id, &job.workspace_id, logs1, db).await; + append_logs(&job.id, &job.workspace_id, logs1, conn).await; let main_override = job.script_entrypoint_override.as_deref(); let apply_preprocessor = !job.is_flow_step() && job.preprocessed == Some(false); @@ -315,11 +319,12 @@ try {{ let reserved_variables_args_out_f = async { let args_and_out_f = async { - create_args_and_out_file(&client, job, job_dir, db).await?; + create_args_and_out_file(&client, job, job_dir, conn).await?; Ok(()) as Result<()> }; let reserved_variables_f = async { - let vars = get_reserved_variables(job, &client.token, db, parent_runnable_path).await?; + let vars = + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; Ok(vars) as Result> }; let (_, reserved_variables) = tokio::try_join!(args_and_out_f, reserved_variables_f)?; @@ -403,7 +408,7 @@ try {{ // start = Instant::now(); handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -414,6 +419,7 @@ try {{ job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await?; // logs.push_str(format!("execute: {:?}\n", start.elapsed().as_millis()).as_str()); @@ -512,7 +518,7 @@ pub async fn start_worker( let common_deno_proc_envs = get_common_deno_proc_envs(&token, base_internal_url).await; let context = variables::get_reserved_variables( - db, + &db.into(), w_id, &token, "dedicated_worker@windmill.dev", diff --git a/backend/windmill-worker/src/global_cache.rs b/backend/windmill-worker/src/global_cache.rs index 23ce255615..155e6db8c1 100644 --- a/backend/windmill-worker/src/global_cache.rs +++ b/backend/windmill-worker/src/global_cache.rs @@ -4,21 +4,22 @@ use tokio::time::Instant; use windmill_common::error; -#[cfg(all(feature = "enterprise", feature = "parquet", unix))] +#[cfg(all(feature = "enterprise", feature = "parquet"))] use object_store::ObjectStore; -#[cfg(all(feature = "enterprise", feature = "parquet", unix))] +#[cfg(all(feature = "enterprise", feature = "parquet"))] use std::sync::Arc; #[cfg(all(feature = "enterprise", feature = "parquet"))] pub const TARGET: &str = const_format::concatcp!(std::env::consts::OS, "_", std::env::consts::ARCH); -#[cfg(all(feature = "enterprise", feature = "parquet", unix))] +#[cfg(all(feature = "enterprise", feature = "parquet"))] pub async fn build_tar_and_push( s3_client: Arc, folder: String, - // python_311 - python_xyz: String, + lang: String, + custom_folder_name: Option, + platform_agnostic: bool, ) -> error::Result<()> { use object_store::path::Path; @@ -28,9 +29,13 @@ pub async fn build_tar_and_push( let start = Instant::now(); // e.g. tiny==1.0.0 - let folder_name = folder.split("/").last().unwrap(); + let folder_name = if let Some(name) = custom_folder_name { + name + } else { + folder.split("/").last().unwrap().to_owned() + }; - let prefix = &format!("{TAR_PYBASE_CACHE_DIR}/{}", python_xyz); + let prefix = &format!("{TAR_PYBASE_CACHE_DIR}/{}", lang); let tar_path = format!("{prefix}/{folder_name}_tar.tar",); let tar_file = std::fs::File::create(&tar_path)?; @@ -51,7 +56,10 @@ pub async fn build_tar_and_push( // })?; if let Err(e) = s3_client .put( - &Path::from(format!("/tar/{TARGET}/{python_xyz}/{folder_name}.tar")), + &Path::from(format!( + "/tar/{}/{lang}/{folder_name}.tar", + if platform_agnostic { "" } else { TARGET } + )), std::fs::read(&tar_path)?.into(), ) .await @@ -75,22 +83,30 @@ pub async fn build_tar_and_push( Ok(()) } -#[cfg(all(feature = "enterprise", feature = "parquet", unix))] +#[cfg(all(feature = "enterprise", feature = "parquet"))] pub async fn pull_from_tar( client: Arc, folder: String, - // python_311 - python_xyz: String, + lang: String, + custom_folder_name: Option, + platform_agnostic: bool, ) -> error::Result<()> { use windmill_common::s3_helpers::attempt_fetch_bytes; - let folder_name = folder.split("/").last().unwrap(); + let folder_name = if let Some(name) = custom_folder_name { + name + } else { + folder.split("/").last().unwrap().to_owned() + }; - tracing::info!("Attempting to pull piptar {folder_name} from bucket"); + tracing::info!("Attempting to pull tar {folder_name} from bucket"); let start = Instant::now(); - let tar_path = format!("tar/{TARGET}/{python_xyz}/{folder_name}.tar"); + let tar_path = format!( + "tar/{}/{lang}/{folder_name}.tar", + if platform_agnostic { "" } else { TARGET } + ); let bytes = attempt_fetch_bytes(client, &tar_path).await?; extract_tar(bytes, &folder).map_err(|e| { diff --git a/backend/windmill-worker/src/go_executor.rs b/backend/windmill-worker/src/go_executor.rs index 43e88c59aa..c0fc8a8085 100644 --- a/backend/windmill-worker/src/go_executor.rs +++ b/backend/windmill-worker/src/go_executor.rs @@ -8,7 +8,7 @@ use uuid::Uuid; use windmill_common::{ error::{self, Error}, utils::calculate_hash, - worker::{save_cache, write_file}, + worker::{save_cache, write_file, Connection}, }; use windmill_parser_go::{parse_go_imports, REQUIRE_PARSE}; use windmill_queue::{append_logs, CanceledBy, MiniPulledJob}; @@ -36,7 +36,7 @@ pub async fn handle_go_job( mem_peak: &mut i32, canceled_by: &mut Option, job: &MiniPulledJob, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, inner_content: &str, @@ -65,7 +65,8 @@ pub async fn handle_go_job( )); let bin_path = format!("{}/{hash}", GO_BIN_CACHE_DIR); let remote_path = format!("{GO_OBJECT_STORE_PREFIX}{hash}"); - let (cache, cache_logs) = windmill_common::worker::load_cache(&bin_path, &remote_path).await; + let (cache, cache_logs) = + windmill_common::worker::load_cache(&bin_path, &remote_path, false).await; let (skip_go_mod, skip_tidy) = if cache { (true, true) @@ -77,7 +78,7 @@ pub async fn handle_go_job( let cache_logs = if !cache { let logs1 = format!("{cache_logs}\n\n--- GO DEPENDENCIES SETUP ---\n"); - append_logs(&job.id, &job.workspace_id, logs1, db).await; + append_logs(&job.id, &job.workspace_id, logs1, conn).await; install_go_dependencies( &job.id, @@ -85,7 +86,7 @@ pub async fn handle_go_job( mem_peak, canceled_by, job_dir, - db, + conn, true, skip_go_mod, skip_tidy, @@ -95,7 +96,7 @@ pub async fn handle_go_job( ) .await?; - create_args_and_out_file(client, job, job_dir, db).await?; + create_args_and_out_file(client, job, job_dir, conn).await?; { let sig = windmill_parser_go::parse_go_sig(&inner_content)?; @@ -201,7 +202,7 @@ func Run(req Req) (interface{{}}, error){{ let build_go_process = start_child_process(build_go_cmd, GO_PATH.as_str()).await?; handle_child( &job.id, - db, + conn, mem_peak, canceled_by, build_go_process, @@ -212,6 +213,7 @@ func Run(req Req) (interface{{}}, error){{ None, false, &mut Some(occupation_metrics), + None, ) .await?; @@ -219,6 +221,7 @@ func Run(req Req) (interface{{}}, error){{ &bin_path, &format!("{GO_OBJECT_STORE_PREFIX}{hash}"), &format!("{job_dir}/main"), + false, ) .await { @@ -242,15 +245,15 @@ func Run(req Req) (interface{{}}, error){{ )) })?; - create_args_and_out_file(client, job, job_dir, db).await?; + create_args_and_out_file(client, job, job_dir, conn).await?; cache_logs }; let logs2 = format!("{cache_logs}\n\n--- GO CODE EXECUTION ---\n"); - append_logs(&job.id, &job.workspace_id, logs2, db).await; + append_logs(&job.id, &job.workspace_id, logs2, conn).await; let reserved_variables = - get_reserved_variables(job, &client.token, db, parent_runnable_path).await?; + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; let child = if !*DISABLE_NSJAIL { let _ = write_file( @@ -303,7 +306,7 @@ func Run(req Req) (interface{{}}, error){{ }; handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -314,6 +317,7 @@ func Run(req Req) (interface{{}}, error){{ job.timeout, false, &mut Some(occupation_metrics), + None, ) .await?; @@ -347,7 +351,7 @@ pub async fn install_go_dependencies( mem_peak: &mut i32, canceled_by: &mut Option, job_dir: &str, - db: &sqlx::Pool, + conn: &Connection, non_dep_job: bool, skip_go_mod: bool, has_sum: bool, @@ -367,7 +371,7 @@ pub async fn install_go_dependencies( handle_child( job_id, - db, + conn, mem_peak, canceled_by, child_process, @@ -378,6 +382,7 @@ pub async fn install_go_dependencies( None, false, &mut Some(occupation_metrics), + None, ) .await?; @@ -404,20 +409,22 @@ pub async fn install_go_dependencies( let mut skip_tidy = has_sum; if !has_sum { - if let Some(cached) = sqlx::query_scalar!( - "SELECT lockfile FROM pip_resolution_cache WHERE hash = $1", - hash - ) - .fetch_optional(db) - .await? - { - let logs1 = format!("\nfound cached resolution: {}", hash); - append_logs(&job_id, w_id, logs1, db).await; - gen_go_mod(code, job_dir, &cached).await?; - skip_tidy = true; - new_lockfile = false; - } else { - new_lockfile = true; + if let Some(db) = conn.as_sql() { + if let Some(cached) = sqlx::query_scalar!( + "SELECT lockfile FROM pip_resolution_cache WHERE hash = $1", + hash + ) + .fetch_optional(db) + .await? + { + let logs1 = format!("\nfound cached resolution: {}", hash); + append_logs(&job_id, w_id, logs1, conn).await; + gen_go_mod(code, job_dir, &cached).await?; + skip_tidy = true; + new_lockfile = false; + } else { + new_lockfile = true; + } } } @@ -433,7 +440,7 @@ pub async fn install_go_dependencies( handle_child( job_id, - db, + conn, mem_peak, canceled_by, child_process, @@ -444,6 +451,7 @@ pub async fn install_go_dependencies( None, false, &mut Some(occupation_metrics), + None, ) .await?; @@ -463,11 +471,15 @@ pub async fn install_go_dependencies( } if non_dep_job { - sqlx::query!( - "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('3 days')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = $2", - hash, - req_content - ).fetch_optional(db).await?; + if let Some(db) = conn.as_sql() { + sqlx::query!( + "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('3 days')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = $2", + hash, + req_content + ) + .fetch_optional(db) + .await?; + } return Ok(String::new()); } else { diff --git a/backend/windmill-worker/src/graphql_executor.rs b/backend/windmill-worker/src/graphql_executor.rs index c755d33beb..5da8b2d193 100644 --- a/backend/windmill-worker/src/graphql_executor.rs +++ b/backend/windmill-worker/src/graphql_executor.rs @@ -4,7 +4,7 @@ use anyhow::anyhow; use futures::{stream, TryStreamExt}; use serde_json::{json, value::RawValue}; use sqlx::types::Json; -use windmill_common::worker::to_raw_value; +use windmill_common::worker::{to_raw_value, Connection}; use windmill_common::{error::Error, worker::CLOUD_HOSTED}; use windmill_parser_graphql::parse_graphql_sig; use windmill_queue::{CanceledBy, MiniPulledJob}; @@ -37,13 +37,13 @@ pub async fn do_graphql( job: &MiniPulledJob, client: &AuthedClient, query: &str, - db: &sqlx::Pool, + conn: &Connection, mem_peak: &mut i32, canceled_by: &mut Option, worker_name: &str, occupation_metrics: &mut OccupancyMetrics, ) -> windmill_common::error::Result> { - let args = build_args_map(job, client, db).await?.map(Json); + let args = build_args_map(job, client, conn).await?.map(Json); let job_args = if args.is_some() { args.as_ref() } else { @@ -81,7 +81,7 @@ pub async fn do_graphql( } } let (timeout_duration, _, _) = - resolve_job_timeout(&db, &job.workspace_id, job.id, job.timeout).await; + resolve_job_timeout(&conn, &job.workspace_id, job.id, job.timeout).await; let http_client = build_http_client(timeout_duration)?; @@ -150,7 +150,7 @@ pub async fn do_graphql( let r = run_future_with_polling_update_job_poller( job.id, job.timeout, - db, + conn, mem_peak, canceled_by, result_f, diff --git a/backend/windmill-worker/src/handle_child.rs b/backend/windmill-worker/src/handle_child.rs index 7294950363..713046207f 100644 --- a/backend/windmill-worker/src/handle_child.rs +++ b/backend/windmill-worker/src/handle_child.rs @@ -4,8 +4,9 @@ use futures::Future; use nix::sys::signal::{self, Signal}; #[cfg(any(target_os = "linux", target_os = "macos"))] use nix::unistd::Pid; +use windmill_common::agent_workers::PingJobStatusResponse; +use windmill_common::jobs::LARGE_LOG_THRESHOLD_SIZE; -use sqlx::{Pool, Postgres}; #[cfg(windows)] use std::process::Stdio; use tokio::fs::File; @@ -15,7 +16,10 @@ use windmill_common::error::to_anyhow; use windmill_common::error::{self, Error}; -use windmill_common::worker::{get_windmill_memory_usage, get_worker_memory_usage, CLOUD_HOSTED}; +use windmill_common::worker::{ + get_windmill_memory_usage, get_worker_memory_usage, set_job_cancelled_query, Connection, + JobCancelled, CLOUD_HOSTED, +}; use windmill_queue::{append_logs, CanceledBy}; @@ -29,7 +33,6 @@ use std::{io, panic, time::Duration}; use tracing::{trace_span, Instrument}; use uuid::Uuid; -use windmill_common::DB; #[cfg(feature = "enterprise")] use windmill_common::job_metrics; @@ -49,8 +52,9 @@ use futures::{ }; use crate::common::{resolve_job_timeout, OccupancyMetrics}; -use crate::job_logger::{append_job_logs, append_with_limit, LARGE_LOG_THRESHOLD_SIZE}; +use crate::job_logger::{append_job_logs, append_with_limit}; use crate::job_logger_ee::process_streaming_log_lines; +use crate::worker_utils::{ping_job_status, update_worker_ping_from_job}; use crate::{MAX_RESULT_SIZE, MAX_WAIT_FOR_SIGINT, MAX_WAIT_FOR_SIGTERM}; lazy_static::lazy_static! { @@ -92,7 +96,7 @@ async fn kill_process_tree(pid: Option) -> Result<(), String> { #[tracing::instrument(name="run_subprocess", level = "info", skip_all, fields(otel.name = %child_name))] pub async fn handle_child( job_id: &Uuid, - db: &Pool, + conn: &Connection, mem_peak: &mut i32, canceled_by_ref: &mut Option, mut child: Child, @@ -103,6 +107,8 @@ pub async fn handle_child( custom_timeout: Option, sigterm: bool, occupancy_metrics: &mut Option<&mut OccupancyMetrics>, + // Do not print logs to output, but instead save to string. + pipe_stdout: Option<&mut String>, ) -> error::Result<()> { let start = Instant::now(); @@ -136,7 +142,7 @@ pub async fn handle_child( * waiting for the child to exit normally */ let update_job = update_job_poller( job_id, - db, + conn, mem_peak, canceled_by_ref, Box::pin(stream::unfold((), move |_| async move { @@ -182,15 +188,13 @@ pub async fn handle_child( } let (timeout_duration, timeout_warn_msg, is_job_specific) = - resolve_job_timeout(&db, w_id, job_id, custom_timeout).await; + resolve_job_timeout(&conn, w_id, job_id, custom_timeout).await; if let Some(msg) = timeout_warn_msg { - append_logs(&job_id, w_id, msg.as_str(), db).await; + append_logs(&job_id, w_id, msg.as_str(), conn).await; } /* a future that completes when the child process exits */ let wait_on_child = async { - let db = db.clone(); - let kill_reason = tokio::select! { biased; result = child.wait() => return result.map(Ok), @@ -206,18 +210,33 @@ pub async fn handle_child( let set_reason = async { if matches!(kill_reason, KillReason::Timeout { .. }) { - if let Err(err) = sqlx::query!( - "UPDATE v2_job_queue - SET canceled_by = 'timeout' - , canceled_reason = $1 - WHERE id = $2", - format!("duration > {}", timeout_duration.as_secs()), - job_id - ) - .execute(&db) - .await - { - tracing::error!(%job_id, %err, "error setting cancelation reason for job {job_id}: {err}"); + match conn { + Connection::Sql(db) => { + if let Err(err) = set_job_cancelled_query( + job_id, + db, + "timeout", + &format!("duration > {}", timeout_duration.as_secs()), + ) + .await + { + tracing::error!(%job_id, %err, "error setting cancelation reason for job {job_id}: {err}"); + } + } + Connection::Http(client) => { + if let Err(err) = client + .post::<_, ()>( + &format!("/api/agent_workers/set_job_cancelled/{}", job_id), + &JobCancelled { + canceled_by: "timeout".to_string(), + reason: format!("duration > {}", timeout_duration.as_secs()), + }, + ) + .await + { + tracing::error!(%job_id, %err, "error setting cancelation reason for job using http {job_id}: {err}"); + } + } } } }; @@ -304,6 +323,8 @@ pub async fn handle_child( let mut log_total_size: u64 = 0; let pg_log_total_size = Arc::new(AtomicU32::new(0)); + let mut pipe_stdout = pipe_stdout; + while let Some(line) = output.by_ref().next().await { let do_write_ = do_write.shared(); @@ -385,9 +406,14 @@ pub async fn handle_child( let worker_name = worker.to_string(); let w_id2 = w_id.to_string(); - (do_write, write_result) = tokio::spawn(append_job_logs(job_id, w_id2, joined, db.clone(), compact_logs, pg_log_total_size.clone(), worker_name)).remote_handle(); + if let Some(buf) = &mut pipe_stdout { + buf.push_str(&joined); + (do_write, write_result) = tokio::spawn(async { }).remote_handle(); + } else { + (do_write, write_result) = tokio::spawn(append_job_logs(job_id, w_id2, joined, conn.clone(), compact_logs, pg_log_total_size.clone(), worker_name)).remote_handle(); + } if let Err(err) = result { tracing::error!(%job_id, %err, "error reading output for job {job_id} '{child_name}': {err}"); @@ -490,7 +516,7 @@ pub(crate) async fn get_mem_peak(pid: Option, nsjail: bool) -> i32 { pub async fn run_future_with_polling_update_job_poller( job_id: Uuid, timeout: Option, - db: &DB, + conn: &Connection, mem_peak: &mut i32, canceled_by_ref: &mut Option, result_f: Fut, @@ -507,7 +533,7 @@ where let update_job = update_job_poller( job_id, - db, + conn, mem_peak, canceled_by_ref, get_mem, @@ -518,7 +544,7 @@ where ); let timeout_ms = u64::try_from( - resolve_job_timeout(&db, &w_id, job_id, timeout) + resolve_job_timeout(&conn, &w_id, job_id, timeout) .await .0 .as_millis(), @@ -553,7 +579,7 @@ pub enum UpdateJobPollingExit { pub async fn update_job_poller( job_id: Uuid, - db: &DB, + conn: &Connection, mem_peak: &mut i32, canceled_by_ref: &mut Option, mut get_mem: S, @@ -567,8 +593,7 @@ where { let update_job_interval = Duration::from_millis(500); - let db = db.clone(); - + let conn = conn.clone(); let mut interval = interval(update_job_interval); interval.set_missed_tick_behavior(MissedTickBehavior::Skip); @@ -590,22 +615,9 @@ where tracing::info!("job {job_id} on {worker_name} in {w_id} worker memory snapshot {}kB/{}kB", memory_usage.unwrap_or_default()/1024, wm_memory_usage.unwrap_or_default()/1024); let occupancy = occupancy_metrics.as_mut().map(|x| x.update_occupancy_metrics()); if job_id != Uuid::nil() { - sqlx::query!( - "UPDATE worker_ping SET ping_at = now(), current_job_id = $1, current_job_workspace_id = $2, memory_usage = $3, wm_memory_usage = $4, - occupancy_rate = $6, occupancy_rate_15s = $7, occupancy_rate_5m = $8, occupancy_rate_30m = $9 WHERE worker = $5", - &job_id, - &w_id, - memory_usage, - wm_memory_usage, - &worker_name, - occupancy.map(|x| x.0), - occupancy.and_then(|x| x.1), - occupancy.and_then(|x| x.2), - occupancy.and_then(|x| x.3), - ) - .execute(&db) - .await - .expect("update worker ping"); + if let Err(err) = update_worker_ping_from_job(&conn, &job_id, w_id, worker_name, memory_usage, wm_memory_usage, occupancy).await { + tracing::error!("Unable to update worker ping for job {} in workspace {}. Error was: {:?}", job_id, w_id, err); + } } } let current_mem = get_mem.next().await.unwrap_or(0); @@ -620,55 +632,49 @@ where #[cfg(feature = "enterprise")] { if job_id != Uuid::nil() { - - // tracking metric starting at i >= 2 b/c first point it useless and we don't want to track metric for super fast jobs - if i == 2 { - memory_metric_id = job_metrics::register_metric_for_job( - &db, - w_id.to_string(), - job_id, - "memory_kb".to_string(), - job_metrics::MetricKind::TimeseriesInt, - Some("Job Memory Footprint (kB)".to_string()), - ) - .await; - } - if let Ok(ref metric_id) = memory_metric_id { - if let Err(err) = job_metrics::record_metric(&db, w_id.to_string(), job_id, metric_id.to_owned(), job_metrics::MetricNumericValue::Integer(current_mem)).await { - tracing::error!("Unable to save memory stat for job {} in workspace {}. Error was: {:?}", job_id, w_id, err); + if let Connection::Sql(ref db) = conn { + // tracking metric starting at i >= 2 b/c first point it useless and we don't want to track metric for super fast jobs + if i == 2 { + memory_metric_id = job_metrics::register_metric_for_job( + &db, + w_id.to_string(), + job_id, + "memory_kb".to_string(), + job_metrics::MetricKind::TimeseriesInt, + Some("Job Memory Footprint (kB)".to_string()), + ) + .await; + } + if let Ok(ref metric_id) = memory_metric_id { + if let Err(err) = job_metrics::record_metric(&db, w_id.to_string(), job_id, metric_id.to_owned(), job_metrics::MetricNumericValue::Integer(current_mem)).await { + tracing::error!("Unable to save memory stat for job {} in workspace {}. Error was: {:?}", job_id, w_id, err); + } } } } } if job_id != Uuid::nil() { - let (canceled_by, canceled_reason, already_completed) = sqlx::query!( - "UPDATE v2_job_runtime r SET - memory_peak = $1, - ping = now() - FROM v2_job_queue q - WHERE r.id = $2 AND q.id = r.id - RETURNING canceled_by, canceled_reason", - *mem_peak, - job_id - ) - .map(|x| (x.canceled_by, x.canceled_reason, false)) - .fetch_optional(&db) - .await - .unwrap_or_else(|e| { - tracing::error!(%e, "error updating job {job_id}: {e:#}"); - Some((None, None, false)) - }) - .unwrap_or_else(|| { - // if the job is not in queue, it can only be in the completed_job so it is already complete - (None, None, true) - }); - if already_completed { + if matches!(conn, Connection::Http(_)) { + if i % 4 != 0 { + // only ping every 4th time (2s) on http agent mode + continue; + } + } + let ping_job_status = ping_job_status(&conn, &job_id, Some(*mem_peak), if current_mem > 0 { Some(current_mem) } else { None }).await.unwrap_or_else(|e| { + tracing::error!("Unable to ping job status for job {job_id}. Error was: {:?}", e); + PingJobStatusResponse { + canceled_by: None, + canceled_reason: None, + already_completed: false, + } + }); + if ping_job_status.already_completed { return UpdateJobPollingExit::AlreadyCompleted } - if canceled_by.is_some() { + if ping_job_status.canceled_by.is_some() { canceled_by_ref.replace(CanceledBy { - username: canceled_by.clone(), - reason: canceled_reason.clone(), + username: ping_job_status.canceled_by.clone(), + reason: ping_job_status.canceled_reason.clone(), }); break } diff --git a/backend/windmill-worker/src/java_executor.rs b/backend/windmill-worker/src/java_executor.rs new file mode 100644 index 0000000000..c589252005 --- /dev/null +++ b/backend/windmill-worker/src/java_executor.rs @@ -0,0 +1,921 @@ +use std::{collections::HashMap, path::PathBuf, process::Stdio, sync::Arc}; + +use anyhow::{anyhow, bail}; +use async_recursion::async_recursion; +use itertools::Itertools; +use serde_json::value::RawValue; +use tokio::{ + fs::{create_dir_all, metadata, remove_dir_all, File}, + io::AsyncWriteExt, + process::Command, +}; +use uuid::Uuid; +use windmill_common::{ + error::{self, Error}, + utils::calculate_hash, + worker::{copy_dir_recursively, save_cache, write_file, Connection}, +}; +use windmill_parser::Arg; +use windmill_parser_java::parse_java_sig_meta; +use windmill_queue::{append_logs, CanceledBy, MiniPulledJob}; + +use crate::{ + common::{ + create_args_and_out_file, get_reserved_variables, par_install_language_dependencies, + read_result, start_child_process, OccupancyMetrics, RequiredDependency, + }, + handle_child, AuthedClient, COURSIER_CACHE_DIR, DISABLE_NSJAIL, DISABLE_NUSER, JAVA_CACHE_DIR, + JAVA_REPOSITORY_DIR, MAVEN_REPOS, NO_DEFAULT_MAVEN, NSJAIL_PATH, PATH_ENV, PROXY_ENVS, +}; +lazy_static::lazy_static! { + static ref JAVA_CONCURRENT_DOWNLOADS: usize = std::env::var("JAVA_CONCURRENT_DOWNLOADS").ok().map(|flag| flag.parse().unwrap_or(20)).unwrap_or(20); + static ref JAVA_PATH: String = std::env::var("JAVA_PATH").unwrap_or_else(|_| "/usr/bin/java".to_string()); + static ref JAVAC_PATH: String = std::env::var("JAVAC_PATH").unwrap_or_else(|_| "/usr/bin/javac".to_string()); + static ref CS_PATH: String = std::env::var("COURSIER_PATH").unwrap_or_else(|_| "/usr/bin/coursier".to_string()); + static ref STOREPASS: String = std::env::var("JAVA_STOREPASS").unwrap_or("123456".into()); + static ref TRUST_STORE_PATH: String = std::env::var("JAVA_TRUST_STORE_PATH").unwrap_or("/usr/local/share/ca-certificates/truststore.jks".into()); +} + +const NSJAIL_CONFIG_RUN_JAVA_CONTENT: &str = include_str!("../nsjail/run.java.config.proto"); + +#[allow(dead_code)] +pub(crate) struct JobHandlerInput<'a> { + pub base_internal_url: &'a str, + pub canceled_by: &'a mut Option, + pub client: &'a AuthedClient, + pub parent_runnable_path: Option, + pub conn: &'a Connection, + pub envs: HashMap, + pub inner_content: &'a str, + pub job: &'a MiniPulledJob, + pub job_dir: &'a str, + pub mem_peak: &'a mut i32, + pub occupancy_metrics: &'a mut OccupancyMetrics, + pub requirements_o: Option<&'a String>, + pub shared_mount: &'a str, + pub worker_name: &'a str, +} + +pub async fn handle_java_job<'a>(mut args: JobHandlerInput<'a>) -> Result, Error> { + // --- Prepare --- + { + prepare(&mut args).await?; + } + // --- Generate Lockfile --- + + let deps = resolve( + &args.job.id, + &args.inner_content, + &args.job_dir, + &args.conn, + &args.job.workspace_id, + ) + .await?; + + // --- Install --- + + let classpath = install(&mut args, deps).await?; + + // --- Build .java files --- + { + compile(&mut args, &classpath).await?; + } + // --- Run --- + { + run(&mut args, &classpath).await?; + } + // --- Retrieve results --- + { + read_result(&args.job_dir).await + } +} + +async fn prepare<'a>( + JobHandlerInput { job, conn, job_dir, client, inner_content, .. }: &mut JobHandlerInput<'a>, +) -> Result<(), Error> { + // Create needed files + { + create_args_and_out_file(&client, job, job_dir, conn).await?; + let app_path = format!("{}/src/main/java/net/script/", job_dir); + create_dir_all(&app_path).await?; + File::create(format!("{app_path}/App.java")) + .await? + .write_all(&wrap(inner_content)?.into_bytes()) + .await?; + File::create(format!("{app_path}/Main.java")) + .await? + .write_all( + &format!( + "package net.script;\n{MINI_CLIENT_IMPORTS}\n{}\n{MINI_CLIENT}", + inner_content + ) + .into_bytes(), + ) + .await?; + } + Ok(()) +} + +pub async fn resolve<'a>( + job_id: &Uuid, + code: &str, + job_dir: &str, + conn: &Connection, + w_id: &str, +) -> Result { + let deps = { + let find_requirements = code.lines().find_position(|x| { + x.starts_with("//requirements:") || x.starts_with("// requirements:") + }); + + let specified_deps = if let Some((pos, _)) = find_requirements { + code.lines() + .skip(pos + 1) + .map_while(|x| { + if x.starts_with("//") { + Some(x.replace("//", "").trim().to_owned()) + } else { + None + } + }) + .collect::>() + } else { + Default::default() + }; + + let mut deps = vec![ + // Default requirements + "com.fasterxml.jackson.core:jackson-databind:2.9.8".to_owned(), + ]; + deps.extend(specified_deps); + deps.join("\n") + }; + + let req_hash = format!("java-{}", calculate_hash(&deps)); + if let Connection::Sql(db) = conn { + if let Some(cached) = sqlx::query_scalar!( + "SELECT lockfile FROM pip_resolution_cache WHERE hash = $1", + req_hash + ) + .fetch_optional(db) + .await? + { + return Ok(cached); + } + } + let lock = { + append_logs( + job_id, + w_id, + format!("\n--- RESOLVING LOCKFILE ---\n"), + &conn, + ) + .await; + + let mut cmd = Command::new(if cfg!(windows) { + "java" + } else { + JAVA_PATH.as_str() + }); + cmd.env_clear() + .current_dir(job_dir.to_owned()) + .env("PATH", PATH_ENV.as_str()) + .envs(PROXY_ENVS.clone()); + + // Configure proxies + { + let jps = parse_proxy()?; + if let Some(val) = jps.https_host { + cmd.arg(&format!("-Dhttps.proxyHost={}", val)); + } + if let Some(val) = jps.https_port { + cmd.arg(&format!("-Dhttps.proxyPort={}", val)); + } + if let Some(val) = jps.http_host { + cmd.arg(&format!("-Dhttp.proxyHost={}", val)); + } + if let Some(val) = jps.http_port { + cmd.arg(&format!("-Dhttp.proxyPort={}", val)); + } + if let Some(val) = jps.no_proxy { + cmd.arg(&format!("-Dhttp.nonProxyHosts=\"{}\"", val)); + } + } + if metadata(TRUST_STORE_PATH.clone()).await.is_ok() { + cmd.args(&[ + &format!("-Djavax.net.ssl.trustStore={}", *TRUST_STORE_PATH), + &format!("-Djavax.net.ssl.trustStorePassword={}", *STOREPASS), + ]); + } + cmd.args(&[ + "-jar", + &CS_PATH, + "resolve", + &get_no_default(), + "--parallel", + &format!("{}", *JAVA_CONCURRENT_DOWNLOADS), + "--cache", + COURSIER_CACHE_DIR, + ]) + .args(&get_repos().await) + .args(&deps.split("\n").collect_vec()) + .stderr(Stdio::piped()); + + #[cfg(windows)] + { + cmd.env("SystemRoot", crate::SYSTEM_ROOT.as_str()) + .env("USERPROFILE", crate::USERPROFILE_ENV.as_str()) + .env( + "TMP", + std::env::var("TMP").unwrap_or_else(|_| String::from("/tmp")), + ); + } + let output = cmd.output().await?; + // Check if the command was successful + if output.status.success() { + String::from_utf8(output.stdout).expect("Failed to convert output to String") + } else { + let stderr = + String::from_utf8(output.stderr).expect("Failed to convert error output to String"); + return Err(error::Error::internal_err(stderr)); + } + }; + + if let Connection::Sql(db) = conn { + sqlx::query!( + "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('3 days')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = $2", + req_hash, + lock.clone(), + ) + .fetch_optional(db) + .await?; + } + + append_logs(job_id, w_id, format!("\n{}", &lock), &conn).await; + Ok(lock) +} + +async fn install<'a>( + JobHandlerInput { worker_name, job, conn, job_dir, .. }: &mut JobHandlerInput<'a>, + deps: String, +) -> Result { + let deps = deps + .lines() + .map(|line| { + let unparsed_dep = line.replace(":jar", "").replace(":lib", ""); + let mut it = unparsed_dep.split(":"); + + match (it.next(), it.next(), it.next()) { + (Some(group_id), Some(artifact_id), Some(version)) => { + let path = format!( + "{JAVA_REPOSITORY_DIR}/{}/{artifact_id}/{version}", + group_id.replace(".", "/") + ); + Ok(RequiredDependency { + path, + custom_name: Some(format!("{group_id}:{artifact_id}:{version}")), + short_name: Some(format!("{artifact_id}:{version}")), + }) + } + _ => anyhow::bail!("{line} is not parsable"), + } + }) + .collect::>>()?; + + let classpath = deps + .clone() + .into_iter() + .map(|RequiredDependency { path, .. }| path + "/*") + .collect_vec() + .join(":") + + ":target"; + + #[cfg(windows)] + let classpath = classpath.replace(":", ";"); + + tracing::debug!( + workspace_id = %job.workspace_id, + "JAVA classpath: {}", &classpath + ); + let (repos, no_default, trust_store_metadata) = ( + get_repos().await, + get_no_default(), + metadata(TRUST_STORE_PATH.clone()).await, + ); + let job_dir = job_dir.to_owned(); + let fetch_dir = format!("{JAVA_CACHE_DIR}/tmp-fetch-{}", Uuid::new_v4()); + let fetch_dir2 = fetch_dir.clone(); + par_install_language_dependencies( + deps, + "java", + "java", + true, + *JAVA_CONCURRENT_DOWNLOADS, + true, + crate::common::InstallStrategy::AllAtOnce(Arc::new(move |dependencies| { + let mut cmd = Command::new(if cfg!(windows) { + "java" + } else { + JAVA_PATH.as_str() + }); + let artifacts = dependencies + .into_iter() + .map(|e| { + e.custom_name.ok_or(anyhow::anyhow!( + "Internal Error: Artifact name should be Some!" + )) + }) + .collect::>>()?; + cmd.env_clear() + .current_dir(&job_dir) + .env("PATH", PATH_ENV.as_str()) + .envs(PROXY_ENVS.clone()); + // Configure proxies + { + let jps = parse_proxy()?; + if let Some(val) = jps.https_host { + cmd.arg(&format!("-Dhttps.proxyHost={}", val)); + } + if let Some(val) = jps.https_port { + cmd.arg(&format!("-Dhttps.proxyPort={}", val)); + } + if let Some(val) = jps.http_host { + cmd.arg(&format!("-Dhttp.proxyHost={}", val)); + } + if let Some(val) = jps.http_port { + cmd.arg(&format!("-Dhttp.proxyPort={}", val)); + } + if let Some(val) = jps.no_proxy { + cmd.arg(&format!("-Dhttp.nonProxyHosts=\"{}\"", val)); + } + } + + if trust_store_metadata.is_ok() { + cmd.args(&[ + &format!("-Djavax.net.ssl.trustStore={}", *TRUST_STORE_PATH), + &format!("-Djavax.net.ssl.trustStorePassword={}", *STOREPASS), + ]); + } + cmd.args(&[ + "-jar", + &CS_PATH, + "fetch", + &no_default, + "--quiet", + "--parallel", + &format!("{}", *JAVA_CONCURRENT_DOWNLOADS), + "--cache", + &fetch_dir, + ]) + .args(&repos) + .arg("--intransitive") + .args(artifacts) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + #[cfg(windows)] + { + cmd.env("SystemRoot", crate::SYSTEM_ROOT.as_str()) + .env("USERPROFILE", crate::USERPROFILE_ENV.as_str()) + .env( + "TMP", + std::env::var("TMP").unwrap_or_else(|_| String::from("/tmp")), + ); + } + + Ok(cmd) + })), + async move |_| { + move_to_repository(&fetch_dir2, 0).await?; + remove_dir_all(&fetch_dir2).await?; + #[async_recursion] + async fn move_to_repository(path: &str, depth: u8) -> anyhow::Result<()> { + if depth == 3 { + copy_dir_recursively( + &PathBuf::from(path), + &PathBuf::from(JAVA_REPOSITORY_DIR), + )?; + + return Ok(()); + } + let mut entries = tokio::fs::read_dir(path).await?; + loop { + let Some(entry) = entries.next_entry().await? else { + break Ok(()); + }; + + let path = entry + .path() + .to_str() + .ok_or(anyhow!("Internal Error: Cannot convert Path to Str"))? + .to_owned(); + + move_to_repository(&path, depth + 1).await?; + } + } + Ok(()) + }, + &job.id, + &job.workspace_id, + worker_name, + conn, + ) + .await?; + Ok(classpath) +} + +async fn compile<'a>( + JobHandlerInput { + occupancy_metrics, + mem_peak, + canceled_by, + worker_name, + job, + conn, + job_dir, + client, + envs, + base_internal_url, + inner_content, + requirements_o, + parent_runnable_path, + .. + }: &mut JobHandlerInput<'a>, + classpath: &'a str, + // plugins: Vec<&'a str>, +) -> Result<(), Error> { + fn compute_hash(code: &str, requirements_o: Option<&String>) -> String { + calculate_hash(&format!( + "{}{}", + code, + requirements_o + .as_ref() + .map(|x| x.to_string()) + .unwrap_or_default() + )) + } + let reserved_variables = + get_reserved_variables(job, &client.token, conn, parent_runnable_path.clone()).await?; + let hash = compute_hash(inner_content, *requirements_o); + let bin_path = format!("{}/{hash}", JAVA_CACHE_DIR); + let remote_path = format!("java_jar/{hash}"); + let (cache, ..) = windmill_common::worker::load_cache(&bin_path, &remote_path, true).await; + + if cache { + let target = format!("{job_dir}/target"); + + #[cfg(unix)] + let symlink = std::os::unix::fs::symlink(&bin_path, &target); + #[cfg(windows)] + let symlink = copy_dir_recursively(&PathBuf::from(&bin_path), &PathBuf::from(&target)); + + symlink.map_err(|e| { + Error::ExecutionErr(format!( + "could not copy cached binary from {bin_path} to {job_dir}/main: {e:?}" + )) + })?; + } else { + // let plugin_registry = format!("{job_dir}/plugin-registry"); + let child = { + append_logs( + &job.id, + &job.workspace_id, + format!("\n--- COMPILING .JAVA FILES\n"), + &conn, + ) + .await; + + let mut cmd = Command::new(if cfg!(windows) { + "javac" + } else { + JAVAC_PATH.as_str() + }); + cmd.env_clear() + .current_dir(job_dir.to_owned()) + .env("PATH", PATH_ENV.as_str()) + .env("BASE_INTERNAL_URL", base_internal_url) + .envs(envs) + .envs(reserved_variables) + .envs(PROXY_ENVS.clone()) + .args(&[ + "-classpath", + &classpath, + "src/main/java/net/script/Main.java", + "src/main/java/net/script/App.java", + "-d", + "./target", + ]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + + #[cfg(windows)] + { + cmd.env("SystemRoot", crate::SYSTEM_ROOT.as_str()) + .env("USERPROFILE", crate::USERPROFILE_ENV.as_str()) + .env( + "TMP", + std::env::var("TMP").unwrap_or_else(|_| String::from("/tmp")), + ); + } + start_child_process(cmd, "javac").await? + }; + handle_child::handle_child( + &job.id, + conn, + mem_peak, + canceled_by, + child, + !*DISABLE_NSJAIL, + worker_name, + &job.workspace_id, + "javac", + job.timeout, + false, + &mut Some(occupancy_metrics), + None, + ) + .await?; + + match save_cache( + &bin_path, + &format!("java_jar/{hash}"), + &format!("{job_dir}/target"), + true, + ) + .await + { + Err(e) => { + let em = format!( + "could not save {bin_path} to {} to java cache: {e:?}", + format!("{job_dir}/main"), + ); + tracing::error!(em); + } + Ok(logs) => { + tracing::trace!(logs); + } + } + }; + + Ok(()) +} +async fn run<'a>( + JobHandlerInput { + occupancy_metrics, + mem_peak, + canceled_by, + worker_name, + job, + conn, + job_dir, + shared_mount, + client, + envs, + base_internal_url, + parent_runnable_path, + .. + }: &mut JobHandlerInput<'a>, + classpath: &'a str, +) -> Result<(), Error> { + let reserved_variables = + get_reserved_variables(job, &client.token, conn, parent_runnable_path.clone()).await?; + + let child = if !cfg!(windows) && !*DISABLE_NSJAIL { + append_logs( + &job.id, + &job.workspace_id, + format!("\n--- ISOLATED JAVA CODE EXECUTION ---\n"), + &conn, + ) + .await; + + write_file( + job_dir, + "run.config.proto", + &NSJAIL_CONFIG_RUN_JAVA_CONTENT + .replace("{JOB_DIR}", job_dir) + .replace("{CACHE_DIR}", JAVA_CACHE_DIR) + .replace("{SHARED_MOUNT}", &shared_mount) + // .replace("{CACHED_TARGET}", &shared_mount) + .replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string()), + )?; + let mut cmd = Command::new(NSJAIL_PATH.as_str()); + cmd.env_clear() + .current_dir(job_dir) + .env("PATH", PATH_ENV.as_str()) + .env("BASE_INTERNAL_URL", base_internal_url) + .envs(envs) + .envs(reserved_variables) + .envs(PROXY_ENVS.clone()) + .args(vec![ + "--config", + "run.config.proto", + "--", + JAVA_PATH.as_str(), + ]); + if metadata(TRUST_STORE_PATH.clone()).await.is_ok() { + cmd.args(&[ + &format!("-Djavax.net.ssl.trustStore={}", *TRUST_STORE_PATH), + &format!("-Djavax.net.ssl.trustStorePassword={}", *STOREPASS), + ]); + } + // Configure proxies + { + let jps = parse_proxy()?; + if let Some(val) = jps.https_host { + cmd.arg(&format!("-Dhttps.proxyHost={}", val)); + } + if let Some(val) = jps.https_port { + cmd.arg(&format!("-Dhttps.proxyPort={}", val)); + } + if let Some(val) = jps.http_host { + cmd.arg(&format!("-Dhttp.proxyHost={}", val)); + } + if let Some(val) = jps.http_port { + cmd.arg(&format!("-Dhttp.proxyPort={}", val)); + } + if let Some(val) = jps.no_proxy { + cmd.arg(&format!("-Dhttp.nonProxyHosts=\"{}\"", val)); + } + } + cmd.args(vec!["-classpath", &classpath, "net.script.App"]); + cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); + + start_child_process(cmd, NSJAIL_PATH.as_str()).await? + } else { + append_logs( + &job.id, + &job.workspace_id, + format!("\n--- JAVA CODE EXECUTION ---\n"), + &conn, + ) + .await; + + let mut cmd = Command::new(if cfg!(windows) { + "java" + } else { + JAVA_PATH.as_str() + }); + cmd.env_clear() + .current_dir(job_dir.to_owned()) + .env("PATH", PATH_ENV.as_str()) + .env("BASE_INTERNAL_URL", base_internal_url) + .envs(envs) + .envs(reserved_variables); + if metadata(TRUST_STORE_PATH.clone()).await.is_ok() { + cmd.args(&[ + &format!("-Djavax.net.ssl.trustStore={}", *TRUST_STORE_PATH), + &format!("-Djavax.net.ssl.trustStorePassword={}", *STOREPASS), + ]); + } + // Configure proxies + { + let jps = parse_proxy()?; + if let Some(val) = jps.https_host { + cmd.arg(&format!("-Dhttps.proxyHost={}", val)); + } + if let Some(val) = jps.https_port { + cmd.arg(&format!("-Dhttps.proxyPort={}", val)); + } + if let Some(val) = jps.http_host { + cmd.arg(&format!("-Dhttp.proxyHost={}", val)); + } + if let Some(val) = jps.http_port { + cmd.arg(&format!("-Dhttp.proxyPort={}", val)); + } + if let Some(val) = jps.no_proxy { + cmd.arg(&format!("-Dhttp.nonProxyHosts=\"{}\"", val)); + } + } + cmd.args(&["-classpath", &classpath, "net.script.App"]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + + #[cfg(windows)] + { + cmd.env("SystemRoot", crate::SYSTEM_ROOT.as_str()) + .env("USERPROFILE", crate::USERPROFILE_ENV.as_str()) + .env( + "TMP", + std::env::var("TMP").unwrap_or_else(|_| String::from("/tmp")), + ); + } + start_child_process(cmd, "java").await? + }; + handle_child::handle_child( + &job.id, + conn, + mem_peak, + canceled_by, + child, + !*DISABLE_NSJAIL, + worker_name, + &job.workspace_id, + "java", + job.timeout, + false, + &mut Some(occupancy_metrics), + None, + ) + .await +} + +#[derive(Default, Debug)] +struct JavaProxySettings { + http_host: Option, + http_port: Option, + https_host: Option, + https_port: Option, + no_proxy: Option, +} +fn parse_proxy() -> anyhow::Result { + let mut jps = JavaProxySettings::default(); + for (ident, mut val) in PROXY_ENVS.clone() { + match ident { + "HTTPS_PROXY" => { + if val.contains("http://") { + bail!("HTTPS_PROXY url cannot contain http scheme."); + } + if !val.contains("https://") { + val = format!("https://{val}"); + } + let mut url = url::Url::parse(&val)?; + let port = url.port(); + // Make sure port and schema is not included in final url + { + url.set_port(None).unwrap_or_default(); + jps.https_host = Some(url.as_str().replace("https://", "")); + if let Some(port) = port { + jps.https_port = Some(format!("{}", port)); + } + } + } + "HTTP_PROXY" => { + if val.contains("https://") { + bail!("HTTP_PROXY url cannot contain https scheme."); + } + if !val.contains("http://") { + val = format!("http://{val}"); + } + let mut url = url::Url::parse(&val)?; + let port = url.port(); + // Make sure port and schema is not included in final url + { + url.set_port(None).unwrap_or_default(); + jps.http_host = Some(url.as_str().replace("http://", "")); + if let Some(port) = port { + jps.https_port = Some(format!("{}", port)); + } + } + } + // Java uses | instead of , + "NO_PROXY" => jps.no_proxy = Some(val.replace(",", "|")), + _ => {} + } + } + + Ok(jps) +} +async fn get_repos() -> Vec { + MAVEN_REPOS + .read() + .await + .as_ref() + .map(|repos| { + repos + .trim() + .split_whitespace() + .into_iter() + .map(|el| vec!["--repository".to_owned(), el.to_owned()]) + .collect_vec() + }) + .unwrap_or_default() + .concat() +} + +fn get_no_default() -> String { + if NO_DEFAULT_MAVEN.load(std::sync::atomic::Ordering::Relaxed) { + "--no-default" + } else { + // Command does not take empty arguments + "-q" + } + .into() +} + +/// Wraps content script +/// that upon execution reads args.json (which are piped and transformed from previous flow step or top level inputs) +/// Also wrapper takes output of program and serializes to result.json (Which windmill will know how to use later) +fn wrap(inner_content: &str) -> Result { + let sig = parse_java_sig_meta(inner_content)?; + let ret_void = sig.returns_void; + let spread = sig + .main_sig + .args + .clone() + .into_iter() + .map(|Arg { name, .. }| { + // Apply additional input transformation + format!(" parsedArgs.{name}") + }) + .collect_vec() + .join(","); + let args = sig + .main_sig + .args + .clone() + .into_iter() + .map(|Arg { name, otyp, .. }| { + // Apply additional input transformation + format!("public {} {name};\n", otyp.unwrap()) + }) + .collect_vec() + .join(" "); + Ok(r#" +package net.script; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.FileOutputStream; +import net.script.Main; + +public class App{ + + public static class Args {ARGS} + + public static void main(String[] args) { + try { + InputStream fileInputStream = new FileInputStream("args.json"); + ObjectMapper mapper = new ObjectMapper(); + Args parsedArgs = mapper.readValue(fileInputStream, Args.class); + fileInputStream.close(); + {MAIN_HANDLER} + FileOutputStream fileOutputStream = new FileOutputStream("result.json"); + mapper.writeValue(fileOutputStream, res); + fileOutputStream.close(); + + } catch (Exception e) { // Catching general Exception + e.printStackTrace(); // Handle the exception + } + } +} + "# + .replace( + "{MAIN_HANDLER}", + if ret_void { + " + Main.main(SPREAD); + Object res = null; + " + } else { + " + Object res = Main.main(SPREAD); + " + }, + ) + .replace("SPREAD", &spread) + .replace("ARGS", &args)) +} +const MINI_CLIENT_IMPORTS: &str = r#" +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +"#; +const MINI_CLIENT: &str = r#" +class Wmill { + public static String getVariable(String path) { + var baseUrl = System.getenv("BASE_INTERNAL_URL"); + var workspace = System.getenv("WM_WORKSPACE"); + var uri = java.text.MessageFormat.format("{0}/api/w/{1}/variables/get_value/{2}", baseUrl, workspace, path); + + // Create an HttpRequest + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(uri)) + .header("Authorization", "Bearer " + System.getenv("WM_TOKEN")) // Add the Authorization header + .GET() // Set the request method to GET + .build(); + + // Send the request and get the response + return HttpClient.newHttpClient().sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .thenApply(HttpResponse::body) + .join(); // Wait for the completion + } + public static String getResource(String path) { + var baseUrl = System.getenv("BASE_INTERNAL_URL"); + var workspace = System.getenv("WM_WORKSPACE"); + var uri = java.text.MessageFormat.format("{0}/api/w/{1}/resources/get_value_interpolated/{2}", baseUrl, workspace, path); + + // Create an HttpRequest + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(uri)) + .header("Authorization", "Bearer " + System.getenv("WM_TOKEN")) // Add the Authorization header + .GET() // Set the request method to GET + .build(); + + // Send the request and get the response + return HttpClient.newHttpClient().sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .thenApply(HttpResponse::body) + .join(); // Wait for the completion + } +} +"#; diff --git a/backend/windmill-worker/src/job_logger.rs b/backend/windmill-worker/src/job_logger.rs index fa4ac15383..97784340c5 100644 --- a/backend/windmill-worker/src/job_logger.rs +++ b/backend/windmill-worker/src/job_logger.rs @@ -1,6 +1,7 @@ use regex::Regex; -use windmill_common::worker::CLOUD_HOSTED; +pub use windmill_common::jobs::LARGE_LOG_THRESHOLD_SIZE; +use windmill_common::worker::{Connection, CLOUD_HOSTED}; use windmill_queue::append_logs; @@ -8,7 +9,6 @@ use std::sync::atomic::AtomicU32; use std::sync::Arc; use uuid::Uuid; -use windmill_common::DB; #[cfg(not(all(feature = "enterprise", feature = "parquet")))] use crate::job_logger_ee::default_disk_log_storage; @@ -25,39 +25,40 @@ pub enum CompactLogs { S3, } -pub(crate) async fn append_job_logs( +pub async fn append_job_logs( job_id: Uuid, w_id: String, logs: String, - db: DB, + conn: Connection, must_compact_logs: bool, total_size: Arc, worker_name: String, ) -> () { - if must_compact_logs { - #[cfg(all(feature = "enterprise", feature = "parquet"))] - s3_storage(job_id, &w_id, &db, logs, total_size, &worker_name).await; + match conn { + Connection::Sql(db) if must_compact_logs => { + #[cfg(all(feature = "enterprise", feature = "parquet"))] + s3_storage(job_id, &w_id, &db, logs, total_size, &worker_name).await; - #[cfg(not(all(feature = "enterprise", feature = "parquet")))] - { - default_disk_log_storage( - job_id, - &w_id, - &db, - logs, - total_size, - CompactLogs::NotEE, - &worker_name, - ) - .await; + #[cfg(not(all(feature = "enterprise", feature = "parquet")))] + { + default_disk_log_storage( + job_id, + &w_id, + &db, + logs, + total_size, + CompactLogs::NotEE, + &worker_name, + ) + .await; + } + } + _ => { + append_logs(&job_id, w_id, logs, &conn).await; } - } else { - append_logs(&job_id, w_id, logs, db).await; } } -pub const LARGE_LOG_THRESHOLD_SIZE: usize = 9000; - lazy_static::lazy_static! { static ref RE_00: Regex = Regex::new('\u{00}'.to_string().as_str()).unwrap(); pub static ref NO_LOGS_AT_ALL: bool = std::env::var("NO_LOGS_AT_ALL").ok().is_some_and(|x| x == "1" || x == "true"); diff --git a/backend/windmill-worker/src/js_eval.rs b/backend/windmill-worker/src/js_eval.rs index ea6d3cf763..33a9b57690 100644 --- a/backend/windmill-worker/src/js_eval.rs +++ b/backend/windmill-worker/src/js_eval.rs @@ -45,7 +45,7 @@ use windmill_common::error::Error; #[cfg(feature = "deno_core")] use windmill_common::worker::{write_file, TMP_DIR}; -use windmill_common::{flow_status::JobResult, DB}; +use windmill_common::flow_status::JobResult; use windmill_queue::CanceledBy; use crate::{common::OccupancyMetrics, AuthedClient}; @@ -749,15 +749,19 @@ fn capture_proxy(s: &str) -> Option<(String, Option<(String, String)>)> { ) }) } + +use windmill_common::worker::Connection; + #[cfg(not(feature = "deno_core"))] pub async fn eval_fetch_timeout( _env_code: String, _ts_expr: String, _js_expr: String, _args: Option<&Json>>>, + _script_entrypoint_override: Option, _job_id: Uuid, _job_timeout: Option, - _db: &DB, + _conn: &Connection, _mem_peak: &mut i32, _canceled_by: &mut Option, _worker_name: &str, @@ -775,9 +779,10 @@ pub async fn eval_fetch_timeout( ts_expr: String, js_expr: String, args: Option<&Json>>>, + script_entrypoint_override: Option, job_id: Uuid, job_timeout: Option, - db: &DB, + conn: &Connection, mem_peak: &mut i32, canceled_by: &mut Option, worker_name: &str, @@ -789,7 +794,13 @@ pub async fn eval_fetch_timeout( let (sender, mut receiver) = oneshot::channel::(); - let parsed_args = windmill_parser_ts::parse_deno_signature(&ts_expr, true, false, None)?.args; + let parsed_args = windmill_parser_ts::parse_deno_signature( + &ts_expr, + true, + false, + script_entrypoint_override.clone(), + )? + .args; let spread = parsed_args .into_iter() .map(|x| { @@ -817,7 +828,7 @@ pub async fn eval_fetch_timeout( )); } - let db_ = db.clone(); + let conn_ = conn.clone(); let w_id_ = w_id.to_string(); let result_f = tokio::task::spawn_blocking(move || { let ops = vec![op_get_static_args(), op_log()]; @@ -902,7 +913,7 @@ pub async fn eval_fetch_timeout( let future = async { let r = tokio::select! { - r = eval_fetch(&mut js_runtime, &js_expr, Some(env_code), load_client, &job_id) => Ok(r), + r = eval_fetch(&mut js_runtime, &js_expr, Some(env_code), script_entrypoint_override, load_client, &job_id) => Ok(r), _ = memory_limit_rx.recv() => Err(Error::ExecutionErr("Memory limit reached, killing isolate".to_string())) }; @@ -913,7 +924,7 @@ pub async fn eval_fetch_timeout( "{extra_logs}{}", js_runtime.op_state().borrow().borrow::().s ), - db_, + &conn_, ) .await; @@ -928,7 +939,7 @@ pub async fn eval_fetch_timeout( let res = run_future_with_polling_update_job_poller( job_id, job_timeout, - db, + conn, mem_peak, canceled_by, async { result_f.await? }, @@ -990,6 +1001,7 @@ async fn eval_fetch( js_runtime: &mut JsRuntime, expr: &str, env_code: Option, + script_entrypoint_override: Option, load_client: bool, job_id: &Uuid, ) -> anyhow::Result> { @@ -1016,13 +1028,16 @@ async fn eval_fetch( }) .context("failed to load module")?; + let main_override = script_entrypoint_override.unwrap_or("main".to_string()); let script = js_runtime .execute_script( "", - r#" + format!( + r#" let args = Deno.core.ops.op_get_static_args().map(JSON.parse) -import("file:///eval.ts").then((module) => module.main(...args)).then(JSON.stringify) -"#, +import("file:///eval.ts").then((module) => module.{main_override}(...args)).then(JSON.stringify) +"# + ), ) .map_err(|e| { write_error_expr(expr, &job_id); diff --git a/backend/windmill-worker/src/lib.rs b/backend/windmill-worker/src/lib.rs index ba47fd81fc..2b0a5d6f4a 100644 --- a/backend/windmill-worker/src/lib.rs +++ b/backend/windmill-worker/src/lib.rs @@ -5,14 +5,14 @@ mod mssql_executor; #[cfg(feature = "enterprise")] mod snowflake_executor; +mod agent_workers; #[cfg(feature = "python")] mod ansible_executor; mod bash_executor; -#[cfg(feature = "nu")] -mod nu_executor; -#[cfg(feature = "benchmark")] -pub mod bench; +#[cfg(feature = "java")] +mod java_executor; + mod bun_executor; pub mod common; mod config; @@ -24,11 +24,13 @@ mod global_cache; mod go_executor; mod graphql_executor; mod handle_child; -mod job_logger; +pub mod job_logger; mod job_logger_ee; mod js_eval; #[cfg(feature = "mysql")] mod mysql_executor; +#[cfg(feature = "nu")] +mod nu_executor; #[cfg(feature = "oracledb")] mod oracledb_executor; mod otel_ee; @@ -37,20 +39,22 @@ mod pg_executor; mod php_executor; #[cfg(feature = "python")] mod python_executor; -mod result_processor; +pub mod result_processor; #[cfg(feature = "rust")] mod rust_executor; +mod sanitized_sql_params; +mod schema; mod worker; mod worker_flow; mod worker_lockfiles; -mod sanitized_sql_params; -mod schema; +mod worker_utils; pub use worker::*; pub use result_processor::handle_job_error; pub use bun_executor::{ - get_common_bun_proc_envs, install_bun_lockfile, prebundle_bun_script, prepare_job_dir, + compute_bundle_local_and_remote_path, get_common_bun_proc_envs, install_bun_lockfile, + prebundle_bun_script, prepare_job_dir, }; pub use deno_executor::generate_deno_lock; diff --git a/backend/windmill-worker/src/mssql_executor.rs b/backend/windmill-worker/src/mssql_executor.rs index 659686268e..d827e57095 100644 --- a/backend/windmill-worker/src/mssql_executor.rs +++ b/backend/windmill-worker/src/mssql_executor.rs @@ -8,9 +8,11 @@ use tiberius::{AuthMethod, Client, ColumnData, Config, FromSqlOwned, Query, Row, use tokio::net::TcpStream; use tokio_util::compat::TokioAsyncWriteCompatExt; use uuid::Uuid; -use windmill_common::error::to_anyhow; -use windmill_common::error::{self, Error}; -use windmill_common::worker::to_raw_value; +use windmill_common::{ + error::{self, to_anyhow, Error}, + utils::empty_string_as_none, + worker::{to_raw_value, Connection}, +}; use windmill_parser_sql::{parse_db_resource, parse_mssql_sig}; use windmill_queue::MiniPulledJob; use windmill_queue::{append_logs, CanceledBy}; @@ -20,14 +22,27 @@ use crate::handle_child::run_future_with_polling_update_job_poller; use crate::sanitized_sql_params::sanitize_and_interpolate_unsafe_sql_args; use crate::AuthedClient; +use serde::Deserializer; + #[derive(Deserialize)] struct MssqlDatabase { host: String, - user: String, - password: String, + user: Option, + password: Option, port: Option, dbname: String, instance_name: Option, + #[serde(default, deserialize_with = "deserialize_aad_token")] + aad_token: Option, + trust_cert: Option, + #[serde(default, deserialize_with = "empty_string_as_none")] + ca_cert: Option, +} + +#[derive(Debug, Deserialize)] +struct AadToken { + #[serde(default, deserialize_with = "empty_string_as_none")] + token: Option, } lazy_static::lazy_static! { @@ -38,13 +53,14 @@ pub async fn do_mssql( job: &MiniPulledJob, client: &AuthedClient, query: &str, - db: &sqlx::Pool, + conn: &Connection, mem_peak: &mut i32, canceled_by: &mut Option, worker_name: &str, occupancy_metrics: &mut OccupancyMetrics, + job_dir: &str, ) -> error::Result> { - let mssql_args = build_args_values(job, client, db).await?; + let mssql_args = build_args_values(job, client, conn).await?; let inline_db_res_path = parse_db_resource(&query); @@ -90,12 +106,42 @@ pub async fn do_mssql( if readonly_intent { let logs = format!("\nSetting ApplicationIntent to ReadOnly"); - append_logs(&job.id, &job.workspace_id, logs, db).await; + append_logs(&job.id, &job.workspace_id, logs, conn).await; } - // Using SQL Server authentication. - config.authentication(AuthMethod::sql_server(database.user, database.password)); - config.trust_cert(); // on production, it is not a good idea to do this + // Handle authentication based on available credentials + if let Some(token_value) = &database.aad_token { + if let Some(token) = &token_value.token { + config.authentication(AuthMethod::aad_token(token)); + } else { + return Err(Error::BadRequest( + "Invalid AAD token format - expected { token: string }".to_string(), + )); + } + } else if let (Some(user), Some(password)) = (&database.user, &database.password) { + config.authentication(AuthMethod::sql_server(user.clone(), password.clone())); + } else { + return Err(Error::BadRequest( + "Neither AAD token nor username/password credentials are set".to_string(), + )); + } + + // Handle certificate trust configuration + if database.trust_cert.unwrap_or(true) { + // If trust_cert is true, ignore ca_cert and trust any certificate + config.trust_cert(); + tracing::info!("MSSQL: disabling certificate validation"); + } else if let Some(ca_cert) = &database.ca_cert { + // Only use ca_cert if trust_cert is false + let cert_path = format!("{}/ca_cert.pem", job_dir); + + std::fs::write(&cert_path, ca_cert) + .map_err(|e| Error::ExecutionErr(format!("Failed to write CA certificate: {}", e)))?; + + // Use the CA certificate for trust + config.trust_cert_ca(cert_path); + tracing::info!("MSSQL: using provided CA certificate for trust"); + } let tcp = if use_instance_name { TcpStream::connect_named(&config).await.map_err(to_anyhow)? // named instance @@ -178,7 +224,7 @@ pub async fn do_mssql( let raw_result = run_future_with_polling_update_job_poller( job.id, job.timeout, - db, + conn, mem_peak, canceled_by, result_f, @@ -334,3 +380,15 @@ fn sql_to_json_value(val: ColumnData) -> Result { ), } } + +fn deserialize_aad_token<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let result = AadToken::deserialize(deserializer); + + match result { + Ok(token) if token.token.is_some() => Ok(Some(token)), + _ => Ok(None), + } +} diff --git a/backend/windmill-worker/src/mysql_executor.rs b/backend/windmill-worker/src/mysql_executor.rs index 2cab8ce8b2..a1309395a7 100644 --- a/backend/windmill-worker/src/mysql_executor.rs +++ b/backend/windmill-worker/src/mysql_executor.rs @@ -11,7 +11,7 @@ use serde_json::{json, value::RawValue, Value}; use tokio::sync::Mutex; use windmill_common::{ error::{to_anyhow, Error}, - worker::to_raw_value, + worker::{to_raw_value, Connection}, }; use windmill_parser_sql::{ parse_db_resource, parse_mysql_sig, parse_sql_blocks, parse_sql_statement_named_params, @@ -106,14 +106,14 @@ pub async fn do_mysql( job: &MiniPulledJob, client: &AuthedClient, query: &str, - db: &sqlx::Pool, + conn: &Connection, mem_peak: &mut i32, canceled_by: &mut Option, worker_name: &str, column_order: &mut Option>, occupancy_metrics: &mut OccupancyMetrics, ) -> windmill_common::error::Result> { - let job_args = build_args_values(job, client, db).await?; + let job_args = build_args_values(job, client, conn).await?; let inline_db_res_path = parse_db_resource(&query); @@ -234,8 +234,8 @@ pub async fn do_mysql( } let pool = mysql_async::Pool::new(opts); - let conn = pool.get_conn().await.map_err(to_anyhow)?; - let conn_a = Arc::new(Mutex::new(conn)); + let mysql_conn = pool.get_conn().await.map_err(to_anyhow)?; + let conn_a = Arc::new(Mutex::new(mysql_conn)); let queries = parse_sql_blocks(query); @@ -281,7 +281,7 @@ pub async fn do_mysql( let result = run_future_with_polling_update_job_poller( job.id, job.timeout, - db, + conn, mem_peak, canceled_by, result_f, diff --git a/backend/windmill-worker/src/nu_executor.rs b/backend/windmill-worker/src/nu_executor.rs index e40e1029f4..b2f6590c41 100644 --- a/backend/windmill-worker/src/nu_executor.rs +++ b/backend/windmill-worker/src/nu_executor.rs @@ -3,7 +3,10 @@ use std::{collections::HashMap, process::Stdio}; use itertools::Itertools; use serde_json::value::RawValue; use tokio::{fs::File, io::AsyncWriteExt, process::Command}; -use windmill_common::{error::Error, worker::write_file}; +use windmill_common::{ + error::Error, + worker::{write_file, Connection}, +}; use windmill_parser::Arg; use windmill_parser_nu::parse_nu_signature; use windmill_queue::{append_logs, CanceledBy, MiniPulledJob}; @@ -30,7 +33,7 @@ pub(crate) struct JobHandlerInput<'a> { pub canceled_by: &'a mut Option, pub client: &'a AuthedClient, pub parent_runnable_path: Option, - pub db: &'a sqlx::Pool, + pub conn: &'a Connection, pub envs: HashMap, pub inner_content: &'a str, pub job: &'a MiniPulledJob, @@ -52,7 +55,7 @@ pub async fn handle_nu_job<'a>(mut args: JobHandlerInput<'a>) -> Result( canceled_by, worker_name, job, - db, + conn, job_dir, shared_mount, client, @@ -229,13 +232,13 @@ async fn run<'a>( // plugins: Vec<&'a str>, ) -> Result<(), Error> { let reserved_variables = - get_reserved_variables(job, &client.token, db, parent_runnable_path.clone()).await?; + get_reserved_variables(job, &client.token, conn, parent_runnable_path.clone()).await?; let child = if !cfg!(windows) && !*DISABLE_NSJAIL { append_logs( &job.id, &job.workspace_id, format!("\n\n--- ISOLATED NU CODE EXECUTION ---\n"), - db.clone(), + conn, ) .await; @@ -274,7 +277,7 @@ async fn run<'a>( &job.id, &job.workspace_id, format!("\n\n--- NU CODE EXECUTION ---\n"), - db.clone(), + &conn, ) .await; @@ -323,7 +326,7 @@ async fn run<'a>( }; handle_child::handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -334,6 +337,7 @@ async fn run<'a>( job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await } diff --git a/backend/windmill-worker/src/oracledb_executor.rs b/backend/windmill-worker/src/oracledb_executor.rs index 2020e421df..7c63e02c81 100644 --- a/backend/windmill-worker/src/oracledb_executor.rs +++ b/backend/windmill-worker/src/oracledb_executor.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; use serde_json::{json, value::RawValue, Value}; use windmill_common::{ error::{to_anyhow, Error}, - worker::to_raw_value, + worker::{to_raw_value, Connection}, }; use windmill_queue::MiniPulledJob; @@ -296,7 +296,7 @@ pub async fn do_oracledb( job: &MiniPulledJob, client: &AuthedClient, query: &str, - db: &sqlx::Pool, + conn: &Connection, mem_peak: &mut i32, canceled_by: &mut Option, worker_name: &str, @@ -309,7 +309,7 @@ pub async fn do_oracledb( "Oracle Database", )?; - let job_args = build_args_values(job, client, db).await?; + let job_args = build_args_values(job, client, conn).await?; let inline_db_res_path = parse_db_resource(&query); @@ -354,14 +354,14 @@ pub async fn do_oracledb( .init(); } - let conn = tokio::task::spawn_blocking(|| { + let oracle_conn = tokio::task::spawn_blocking(|| { oracle::Connection::connect(database.user, database.password, database.database) .map_err(|e| Error::ExecutionErr(e.to_string())) }) .await .map_err(to_anyhow)??; - let conn_a = Arc::new(std::sync::Mutex::new(conn)); + let conn_a = Arc::new(std::sync::Mutex::new(oracle_conn)); let queries = parse_sql_blocks(&query); @@ -396,7 +396,7 @@ pub async fn do_oracledb( let result = run_future_with_polling_update_job_poller( job.id, job.timeout, - db, + conn, mem_peak, canceled_by, result_f, diff --git a/backend/windmill-worker/src/pg_executor.rs b/backend/windmill-worker/src/pg_executor.rs index e9aa27eca9..79002e4d1f 100644 --- a/backend/windmill-worker/src/pg_executor.rs +++ b/backend/windmill-worker/src/pg_executor.rs @@ -27,7 +27,7 @@ use tokio_postgres::{ use uuid::Uuid; use windmill_common::error::to_anyhow; use windmill_common::error::{self, Error}; -use windmill_common::worker::{to_raw_value, CLOUD_HOSTED}; +use windmill_common::worker::{to_raw_value, Connection, CLOUD_HOSTED}; use windmill_parser::{Arg, Typ}; use windmill_parser_sql::{ parse_db_resource, parse_pg_statement_arg_indices, parse_pgsql_sig, parse_sql_blocks, @@ -161,14 +161,14 @@ pub async fn do_postgresql( job: &MiniPulledJob, client: &AuthedClient, query: &str, - db: &sqlx::Pool, + conn: &Connection, mem_peak: &mut i32, canceled_by: &mut Option, worker_name: &str, column_order: &mut Option>, occupancy_metrics: &mut OccupancyMetrics, ) -> error::Result> { - let pg_args = build_args_values(job, client, db).await?; + let pg_args = build_args_values(job, client, conn).await?; let inline_db_res_path = parse_db_resource(&query); @@ -353,7 +353,7 @@ pub async fn do_postgresql( let result = run_future_with_polling_update_job_poller( job.id, job.timeout, - db, + conn, mem_peak, canceled_by, result_f, diff --git a/backend/windmill-worker/src/php_executor.rs b/backend/windmill-worker/src/php_executor.rs index 19dce7f1b9..ac50beb99f 100644 --- a/backend/windmill-worker/src/php_executor.rs +++ b/backend/windmill-worker/src/php_executor.rs @@ -7,7 +7,7 @@ use tokio::{fs::File, io::AsyncReadExt, process::Command}; use uuid::Uuid; use windmill_common::{ error::{self, to_anyhow, Result}, - worker::write_file, + worker::{write_file, Connection}, }; use windmill_queue::MiniPulledJob; @@ -67,7 +67,7 @@ pub async fn composer_install( canceled_by: &mut Option, job_id: &Uuid, w_id: &str, - db: &sqlx::Pool, + conn: &Connection, job_dir: &str, worker_name: &str, requirements: String, @@ -94,7 +94,7 @@ pub async fn composer_install( handle_child( job_id, - db, + conn, mem_peak, canceled_by, child_process, @@ -105,6 +105,7 @@ pub async fn composer_install( None, false, &mut Some(occupancy_metrics), + None, ) .await?; @@ -138,7 +139,7 @@ pub async fn handle_php_job( mem_peak: &mut i32, canceled_by: &mut Option, job: &MiniPulledJob, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, job_dir: &str, @@ -166,14 +167,14 @@ pub async fn handle_php_job( let autoload_line = if let Some(composer_json) = composer_json { let logs1 = "\n\n--- COMPOSER INSTALL ---\n".to_string(); - append_logs(&job.id, &job.workspace_id, logs1, db).await; + append_logs(&job.id, &job.workspace_id, logs1, conn).await; composer_install( mem_peak, canceled_by, &job.id, &job.workspace_id, - db, + conn, job_dir, worker_name, composer_json, @@ -188,7 +189,7 @@ pub async fn handle_php_job( let init_logs = "\n\n--- PHP CODE EXECUTION ---\n".to_string(); - append_logs(&job.id, job.workspace_id.to_string(), init_logs, db).await; + append_logs(&job.id, job.workspace_id.to_string(), init_logs, conn).await; let _ = write_file(job_dir, "main.php", inner_content)?; @@ -262,12 +263,13 @@ try {{ let reserved_variables_args_out_f = async { let args_and_out_f = async { - create_args_and_out_file(&client, job, job_dir, db).await?; + create_args_and_out_file(&client, job, job_dir, conn).await?; Ok(()) as Result<()> }; let reserved_variables_f = async { - let vars = get_reserved_variables(job, &client.token, db, parent_runnable_path.clone()) - .await?; + let vars = + get_reserved_variables(job, &client.token, conn, parent_runnable_path.clone()) + .await?; Ok(vars) as Result> }; let (_, reserved_variables) = tokio::try_join!(args_and_out_f, reserved_variables_f)?; @@ -328,7 +330,7 @@ try {{ handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -339,6 +341,7 @@ try {{ job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await?; read_result(job_dir).await diff --git a/backend/windmill-worker/src/python_executor.rs b/backend/windmill-worker/src/python_executor.rs index 648c40a9a3..c642abae49 100644 --- a/backend/windmill-worker/src/python_executor.rs +++ b/backend/windmill-worker/src/python_executor.rs @@ -10,7 +10,6 @@ use anyhow::anyhow; use itertools::Itertools; use regex::Regex; use serde_json::value::RawValue; -use sqlx::{Pool, Postgres}; use tokio::{ fs::{metadata, DirBuilder, File}, io::AsyncReadExt, @@ -27,15 +26,16 @@ use windmill_common::{ Error::{self}, }, utils::calculate_hash, - worker::{write_file, PythonAnnotations, WORKER_CONFIG}, - DB, + worker::{ + copy_dir_recursively, pad_string, write_file, Connection, PythonAnnotations, WORKER_CONFIG, + }, }; #[cfg(feature = "enterprise")] use windmill_common::variables::get_secret_value_as_admin; use std::env::var; -use windmill_queue::{append_logs, CanceledBy}; +use windmill_queue::{append_logs, CanceledBy, PrecomputedAgentInfo}; lazy_static::lazy_static! { static ref PYTHON_PATH: Option = var("PYTHON_PATH").ok().map(|v| { @@ -49,6 +49,7 @@ lazy_static::lazy_static! { static ref PY_CONCURRENT_DOWNLOADS: usize = var("PY_CONCURRENT_DOWNLOADS").ok().map(|flag| flag.parse().unwrap_or(20)).unwrap_or(20); + static ref NON_ALPHANUM_CHAR: Regex = regex::Regex::new(r"[^0-9A-Za-z=.-]").unwrap(); static ref TRUSTED_HOST: Option = var("PY_TRUSTED_HOST").ok().or(var("PIP_TRUSTED_HOST").ok()); @@ -76,6 +77,7 @@ use crate::{ start_child_process, OccupancyMetrics, }, handle_child::handle_child, + worker_utils::ping_job_status, AuthedClient, DISABLE_NSJAIL, DISABLE_NUSER, HOME_ENV, INSTANCE_PYTHON_VERSION, NSJAIL_PATH, PATH_ENV, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL, PROXY_ENVS, PY_INSTALL_DIR, TZ_ENV, UV_CACHE_DIR, }; @@ -94,7 +96,7 @@ pub enum PyVersion { } impl PyVersion { - pub async fn from_instance_version(job_id: &Uuid, w_id: &str, db: &Pool) -> Self { + pub async fn from_instance_version(job_id: &Uuid, w_id: &str, conn: &Connection) -> Self { let mut err = None; let pyv = match INSTANCE_PYTHON_VERSION.read().await.clone() { Some(v) => PyVersion::from_string_with_dots(&v).unwrap_or_else(|| { @@ -107,7 +109,7 @@ impl PyVersion { }; if let Some(msg) = err { - append_logs(job_id, w_id, &msg, db).await; + append_logs(job_id, w_id, &msg, conn).await; tracing::error!(msg); } pyv @@ -210,7 +212,7 @@ impl PyVersion { job_id: &Uuid, mem_peak: &mut i32, // canceled_by: &mut Option, - db: &Pool, + conn: &Connection, worker_name: &str, w_id: &str, occupancy_metrics: &mut Option<&mut OccupancyMetrics>, @@ -220,7 +222,7 @@ impl PyVersion { // } let res = self - .get_python_inner(job_id, mem_peak, db, worker_name, w_id, occupancy_metrics) + .get_python_inner(job_id, mem_peak, conn, worker_name, w_id, occupancy_metrics) .await; if let Err(ref e) = res { @@ -234,7 +236,7 @@ impl PyVersion { format!( "\nError while getting python from uv, falling back to system python: {e:?}" ), - db, + conn, ) .await; } @@ -245,7 +247,7 @@ impl PyVersion { job_id: &Uuid, mem_peak: &mut i32, // canceled_by: &mut Option, - db: &Pool, + conn: &Connection, worker_name: &str, w_id: &str, occupancy_metrics: &mut Option<&mut OccupancyMetrics>, @@ -256,7 +258,7 @@ impl PyVersion { if py_path.is_err() { // Install it if let Err(err) = self - .install_python(job_id, mem_peak, db, worker_name, w_id, occupancy_metrics) + .install_python(job_id, mem_peak, conn, worker_name, w_id, occupancy_metrics) .await { tracing::error!("Cannot install python: {err}"); @@ -282,13 +284,13 @@ impl PyVersion { job_id: &Uuid, mem_peak: &mut i32, // canceled_by: &mut Option, - db: &Pool, + conn: &Connection, worker_name: &str, w_id: &str, occupancy_metrics: &mut Option<&mut OccupancyMetrics>, ) -> error::Result<()> { let v = self.to_string_with_dot(); - append_logs(job_id, w_id, format!("\nINSTALLING PYTHON ({})", v), db).await; + append_logs(job_id, w_id, format!("\nINSTALLING PYTHON ({})", v), conn).await; // Create dirs for newly installed python // If we dont do this, NSJAIL will not be able to mount cache // For the default version directory created during startup (main.rs) @@ -336,10 +338,10 @@ impl PyVersion { let child_process = start_child_process(child_cmd, "uv").await?; - append_logs(&job_id, &w_id, logs, db).await; + append_logs(&job_id, &w_id, logs, conn).await; handle_child( job_id, - db, + conn, mem_peak, &mut None, child_process, @@ -350,6 +352,7 @@ impl PyVersion { None, false, occupancy_metrics, + None, ) .await } @@ -457,7 +460,7 @@ pub async fn uv_pip_compile( mem_peak: &mut i32, canceled_by: &mut Option, job_dir: &str, - db: &Pool, + conn: &Connection, worker_name: &str, w_id: &str, occupancy_metrics: &mut Option<&mut OccupancyMetrics>, @@ -504,25 +507,27 @@ pub async fn uv_pip_compile( let requirements = format!("# py{}\n{}", py_version.to_string_no_dot(), requirements); #[cfg(feature = "enterprise")] - let requirements = replace_pip_secret(db, w_id, &requirements, worker_name, job_id).await?; + let requirements = replace_pip_secret(conn, w_id, &requirements, worker_name, job_id).await?; let req_hash = format!("py-{}", calculate_hash(&requirements)); if !no_cache { - if let Some(cached) = sqlx::query_scalar!( - "SELECT lockfile FROM pip_resolution_cache WHERE hash = $1", - // Python version is included in hash, - // hash will be the different for every python version - req_hash - ) - .fetch_optional(db) - .await? - { - logs.push_str(&format!( - "\nFound cached resolution: {req_hash}, on python version: {}", - py_version.to_string_with_dot() - )); - return Ok(cached); + if let Some(db) = conn.as_sql() { + if let Some(cached) = sqlx::query_scalar!( + "SELECT lockfile FROM pip_resolution_cache WHERE hash = $1", + // Python version is included in hash, + // hash will be the different for every python version + req_hash + ) + .fetch_optional(db) + .await? + { + logs.push_str(&format!( + "\nFound cached resolution: {req_hash}, on python version: {}", + py_version.to_string_with_dot() + )); + return Ok(cached); + } } } @@ -533,7 +538,7 @@ pub async fn uv_pip_compile( { // Make sure we have python runtime installed py_version - .get_python(job_id, mem_peak, db, worker_name, w_id, occupancy_metrics) + .get_python(job_id, mem_peak, conn, worker_name, w_id, occupancy_metrics) .await?; let mut args = vec![ @@ -629,10 +634,10 @@ pub async fn uv_pip_compile( } let child_process = start_child_process(child_cmd, uv_cmd).await?; - append_logs(&job_id, &w_id, logs, db).await; + append_logs(&job_id, &w_id, logs, conn).await; handle_child( job_id, - db, + conn, mem_peak, canceled_by, child_process, @@ -644,6 +649,7 @@ pub async fn uv_pip_compile( None, false, occupancy_metrics, + None, ) .await .map_err(|e| { @@ -668,11 +674,13 @@ pub async fn uv_pip_compile( .collect::>() .join("\n") ); - sqlx::query!( + if let Some(db) = conn.as_sql() { + sqlx::query!( "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('3 days')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = $2", req_hash, lockfile ).fetch_optional(db).await?; + } Ok(lockfile) } @@ -708,7 +716,7 @@ async fn postinstall( additional_python_paths: &mut Vec, job_dir: &str, job: &MiniPulledJob, - db: &sqlx::Pool, + conn: &Connection, ) -> windmill_common::error::Result<()> { // It is guranteed that additional_python_paths only contains paths within windmill/cache/ // All other paths you would usually expect in PYTHONPATH are NOT included. These are added in downstream @@ -769,7 +777,7 @@ async fn postinstall( &job.id, &job.workspace_id, "\n\nCopying some packages from cache to job_dir...\n".to_string(), - db, + conn, ) .await; // Remove PATHs we just moved @@ -780,43 +788,26 @@ async fn postinstall( Ok(()) } -fn copy_dir_recursively(src: &Path, dst: &Path) -> windmill_common::error::Result<()> { - if !dst.exists() { - fs::create_dir_all(dst)?; - } - - tracing::debug!("Copying recursively from {:?} to {:?}", src, dst); - - for entry in fs::read_dir(src)? { - let entry = entry?; - let src_path = entry.path(); - let dst_path = dst.join(entry.file_name()); - - if src_path.is_dir() && !src_path.is_symlink() { - copy_dir_recursively(&src_path, &dst_path)?; - } else { - fs::copy(&src_path, &dst_path)?; - } - } - - tracing::debug!("Finished copying recursively from {:?} to {:?}", src, dst); - - Ok(()) -} - async fn get_python_path( py_version: PyVersion, worker_name: &str, job_id: &Uuid, w_id: &str, mem_peak: &mut i32, - db: &sqlx::Pool, + conn: &Connection, occupancy_metrics: &mut Option<&mut OccupancyMetrics>, ) -> windmill_common::error::Result { let python_path = if let Some(python_path) = PYTHON_PATH.clone() { python_path } else if let Some(python_path) = py_version - .get_python(&job_id, mem_peak, db, worker_name, w_id, occupancy_metrics) + .get_python( + &job_id, + mem_peak, + conn, + worker_name, + w_id, + occupancy_metrics, + ) .await? { python_path @@ -837,7 +828,7 @@ pub async fn handle_python_job( job: &MiniPulledJob, mem_peak: &mut i32, canceled_by: &mut Option, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, inner_content: &String, @@ -846,6 +837,7 @@ pub async fn handle_python_job( envs: HashMap, new_args: &mut Option>>, occupancy_metrics: &mut OccupancyMetrics, + precomputed_agent_info: Option, ) -> windmill_common::error::Result> { let script_path = crate::common::use_flow_root_path(job.runnable_path()); @@ -856,12 +848,13 @@ pub async fn handle_python_job( &job.workspace_id, &script_path, &job.id, - db, + conn, worker_name, worker_dir, mem_peak, canceled_by, &mut Some(occupancy_metrics), + precomputed_agent_info, ) .await?; @@ -873,13 +866,13 @@ pub async fn handle_python_job( &job.id, &job.workspace_id, mem_peak, - db, + conn, &mut Some(occupancy_metrics), ) .await?; if !no_postinstall { - if let Err(e) = postinstall(&mut additional_python_paths, job_dir, job, db).await { + if let Err(e) = postinstall(&mut additional_python_paths, job_dir, job, conn).await { tracing::error!("Postinstall stage has failed. Reason: {e}"); } tracing::debug!("Finished deps postinstall stage"); @@ -893,7 +886,7 @@ pub async fn handle_python_job( "\n\n--- PYTHON ({}) CODE EXECUTION ---\n", py_version.to_string_with_dot() ), - db, + conn, ) .await; } @@ -922,7 +915,7 @@ pub async fn handle_python_job( let apply_preprocessor = pre_spread.is_some(); - create_args_and_out_file(&client, job, job_dir, db).await?; + create_args_and_out_file(&client, job, job_dir, conn).await?; tracing::debug!("Finished preparing wrapper"); let preprocessor = if let Some(pre_spread) = pre_spread { @@ -1025,7 +1018,7 @@ except BaseException as e: tracing::debug!("Finished writing wrapper"); let mut reserved_variables = - get_reserved_variables(job, &client.token, db, parent_runnable_path).await?; + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; // Add /tmp/windmill/cache/python_xyz/global-site-packages to PYTHONPATH. // Usefull if certain wheels needs to be preinstalled before execution. @@ -1150,7 +1143,7 @@ mount {{ handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -1161,6 +1154,7 @@ mount {{ job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await?; @@ -1373,43 +1367,47 @@ async fn prepare_wrapper( #[cfg(feature = "enterprise")] async fn replace_pip_secret( - db: &DB, + conn: &Connection, w_id: &str, req: &str, worker_name: &str, job_id: &Uuid, ) -> error::Result { - if PIP_SECRET_VARIABLE.is_match(req) { - let mut joined = "".to_string(); - for req in req.lines() { - let nreq = if PIP_SECRET_VARIABLE.is_match(req) { - let capture = PIP_SECRET_VARIABLE.captures(req); - let variable = capture.unwrap().get(1).unwrap().as_str(); - if !variable.contains("/PIP_SECRET_") { - return Err(error::Error::internal_err(format!( + if let Some(db) = conn.as_sql() { + if PIP_SECRET_VARIABLE.is_match(req) { + let mut joined = "".to_string(); + for req in req.lines() { + let nreq = if PIP_SECRET_VARIABLE.is_match(req) { + let capture = PIP_SECRET_VARIABLE.captures(req); + let variable = capture.unwrap().get(1).unwrap().as_str(); + if !variable.contains("/PIP_SECRET_") { + return Err(error::Error::internal_err(format!( "invalid secret variable in pip requirements, (last part of path ma): {}", req ))); - } - let secret = get_secret_value_as_admin(db, w_id, variable).await?; - tracing::info!( - worker = %worker_name, - job_id = %job_id, - workspace_id = %w_id, - "found secret variable in pip requirements: {}", - req - ); - PIP_SECRET_VARIABLE - .replace(req, secret.as_str()) - .to_string() - } else { - req.to_string() - }; - joined.push_str(&nreq); - joined.push_str("\n"); - } + } + let secret = get_secret_value_as_admin(db, w_id, variable).await?; + tracing::info!( + worker = %worker_name, + job_id = %job_id, + workspace_id = %w_id, + "found secret variable in pip requirements: {}", + req + ); + PIP_SECRET_VARIABLE + .replace(req, secret.as_str()) + .to_string() + } else { + req.to_string() + }; + joined.push_str(&nreq); + joined.push_str("\n"); + } - Ok(joined) + Ok(joined) + } else { + Ok(req.to_string()) + } } else { Ok(req.to_string()) } @@ -1422,12 +1420,13 @@ async fn handle_python_deps( w_id: &str, script_path: &str, job_id: &Uuid, - db: &DB, + conn: &Connection, worker_name: &str, worker_dir: &str, mem_peak: &mut i32, canceled_by: &mut Option, occupancy_metrics: &mut Option<&mut OccupancyMetrics>, + precomputed_agent_info: Option, ) -> error::Result<(PyVersion, Vec)> { create_dependencies_dir(job_dir).await; @@ -1440,26 +1439,39 @@ async fn handle_python_deps( .clone(); let mut requirements; + let compilation_error_hint; let mut annotated_pyv = None; let mut annotated_pyv_numeric = None; let is_deployed = requirements_o.is_some(); - let instance_pyv = PyVersion::from_instance_version(job_id, w_id, db).await; + let instance_pyv = PyVersion::from_instance_version(job_id, w_id, conn).await; let annotations = windmill_common::worker::PythonAnnotations::parse(inner_content); let requirements = match requirements_o { Some(r) => r, None => { let mut already_visited = vec![]; - requirements = windmill_parser_py_imports::parse_python_imports( - inner_content, - w_id, - script_path, - db, - &mut already_visited, - &mut annotated_pyv_numeric, - ) - .await? - .join("\n"); + (requirements, compilation_error_hint) = match conn { + Connection::Sql(db) => { + let (r, h) = windmill_parser_py_imports::parse_python_imports( + inner_content, + w_id, + script_path, + db, + &mut already_visited, + &mut annotated_pyv_numeric, + ) + .await?; + + (r.join("\n"), h) + } + Connection::Http(_) => match precomputed_agent_info { + Some(PrecomputedAgentInfo::Python { py_version, requirements }) => { + annotated_pyv_numeric = py_version; + (requirements.clone().unwrap_or_else(|| "".to_string()), None) + } + _ => ("".to_string(), None), + }, + }; annotated_pyv = annotated_pyv_numeric.and_then(|v| PyVersion::from_numeric(v)); @@ -1470,7 +1482,7 @@ async fn handle_python_deps( mem_peak, canceled_by, job_dir, - db, + conn, worker_name, w_id, occupancy_metrics, @@ -1479,7 +1491,11 @@ async fn handle_python_deps( ) .await .map_err(|e| { - Error::ExecutionErr(format!("pip compile failed: {}", e.to_string())) + Error::ExecutionErr(format!( + "pip compile failed: {}{}", + e.to_string(), + compilation_error_hint.unwrap_or_default() + )) })?; } &requirements @@ -1511,7 +1527,7 @@ async fn handle_python_deps( w_id, mem_peak, canceled_by, - db, + conn, worker_name, job_dir, worker_dir, @@ -1709,19 +1725,6 @@ async fn spawn_uv_install( } } -/// length = 5 -/// value = "foo" -/// output = "foo " -/// 12345 -fn pad_string(value: &str, total_length: usize) -> String { - if value.len() >= total_length { - value.to_string() // Return the original string if it's already long enough - } else { - let padding_needed = total_length - value.len(); - format!("{value}{}", " ".repeat(padding_needed)) // Pad with spaces - } -} - /// uv pip install, include cached or pull from S3 pub async fn handle_python_reqs( requirements: Vec<&str>, @@ -1729,7 +1732,7 @@ pub async fn handle_python_reqs( w_id: &str, mem_peak: &mut i32, _canceled_by: &mut Option, - db: &sqlx::Pool, + conn: &Connection, _worker_name: &str, job_dir: &str, worker_dir: &str, @@ -1752,7 +1755,7 @@ pub async fn handle_python_reqs( counter_arc: Arc>, total_to_install: usize, instant: std::time::Instant, - db: Pool, + conn: &Connection, ) { #[cfg(not(all(feature = "enterprise", feature = "parquet", unix)))] { @@ -1781,7 +1784,7 @@ pub async fn handle_python_reqs( if s3_push { " > (S3) " } else { "" }, instant.elapsed().as_millis(), ), - db, + conn, ) .await; // Drop lock, so next print success can fire @@ -1843,7 +1846,7 @@ pub async fn handle_python_reqs( &job_id, w_id, format!("\nenv deps from local cache: {}\n", in_cache.join(", ")), - db, + conn, ) .await; } @@ -1857,7 +1860,7 @@ pub async fn handle_python_reqs( let (_done_tx, mut done_rx) = tokio::sync::mpsc::channel::<()>(1); let job_id_2 = job_id.clone(); - let db_2 = db.clone(); + let conn_2 = conn.clone(); let w_id_2 = w_id.to_string(); // Wheels to install @@ -1907,9 +1910,12 @@ pub async fn handle_python_reqs( *mem_peak_lock }; + // Notify server that we are still alive // Detect if job has been canceled - let canceled = sqlx::query_scalar!( + let canceled = match conn_2 { + Connection::Sql(ref db) => { + sqlx::query_scalar!( "UPDATE v2_job_runtime r SET memory_peak = $1, ping = now() @@ -1918,17 +1924,25 @@ pub async fn handle_python_reqs( RETURNING canceled_by IS NOT NULL AS \"canceled!\"", mem_peak_actual, job_id_2 - ) - .fetch_optional(&db_2) - .await - .unwrap_or_else(|e| { - tracing::error!(%e, "error updating job {job_id_2}: {e:#}"); - Some(false) - }) - .unwrap_or_else(|| { - // if the job is not in queue, it can only be in the completed_job so it is already complete - false - }); + ) + .fetch_optional(db) + .await + .unwrap_or_else(|e| { + tracing::error!(%e, "error updating job {job_id_2}: {e:#}"); + Some(false) + }) + .unwrap_or_else(|| { + // if the job is not in queue, it can only be in the completed_job so it is already complete + false + }) + } + Connection::Http(_) => { + if let Err(e) = ping_job_status(&conn_2, &job_id_2, Some(mem_peak_actual), None).await { + tracing::error!(%e, "error pinging job {job_id_2}: {e:#}"); + } + false + } + }; if canceled { @@ -1985,7 +1999,7 @@ pub async fn handle_python_reqs( parallel_limit )); } - append_logs(&job_id, w_id, logs, db).await; + append_logs(&job_id, w_id, logs, conn).await; } let semaphore = Arc::new(Semaphore::new(parallel_limit)); @@ -1997,7 +2011,14 @@ pub async fn handle_python_reqs( let total_time = std::time::Instant::now(); let py_path = py_version - .get_python(job_id, mem_peak, db, _worker_name, w_id, _occupancy_metrics) + .get_python( + job_id, + mem_peak, + conn, + _worker_name, + w_id, + _occupancy_metrics, + ) .await?; let has_work = req_with_penv.len() > 0; @@ -2021,7 +2042,7 @@ pub async fn handle_python_reqs( "started setup python dependencies" ); - let db = db.clone(); + let conn = conn.clone(); let job_id = job_id.clone(); let job_dir = job_dir.to_owned(); let w_id = w_id.to_owned(); @@ -2053,7 +2074,7 @@ pub async fn handle_python_reqs( tokio::select! { // Cancel was called on the job _ = kill_rx.recv() => return Err(anyhow::anyhow!("S3 pull was canceled")), - pull = pull_from_tar(os, venv_p.clone(), py_version.to_cache_dir_top_level()) => { + pull = pull_from_tar(os, venv_p.clone(), py_version.to_cache_dir_top_level(), None, false) => { if let Err(e) = pull { tracing::info!( workspace_id = %w_id, @@ -2070,7 +2091,7 @@ pub async fn handle_python_reqs( counter_arc, total_to_install, start, - db + &conn ).await; pids.lock().await.get_mut(i).and_then(|e| e.take()); @@ -2109,7 +2130,7 @@ pub async fn handle_python_reqs( format!( "\nError while spawning proccess:\n{e}", ), - db, + &conn, ) .await; pids.lock().await.get_mut(i).and_then(|e| e.take()); @@ -2160,7 +2181,7 @@ pub async fn handle_python_reqs( "\nError while installing {}:\n{stderr_buf}", &req ), - db, + &conn, ) .await; pids.lock().await.get_mut(i).and_then(|e| e.take()); @@ -2197,14 +2218,14 @@ pub async fn handle_python_reqs( counter_arc, total_to_install, start, - db, // + &conn, // ) .await; #[cfg(all(feature = "enterprise", feature = "parquet", unix))] if s3_push { if let Some(os) = OBJECT_STORE_CACHE_SETTINGS.read().await.clone() { - tokio::spawn(build_tar_and_push(os, venv_p.clone(), py_version.to_cache_dir_top_level())); + tokio::spawn(build_tar_and_push(os, venv_p.clone(), py_version.to_cache_dir_top_level(), None, false)); } } @@ -2251,7 +2272,13 @@ pub async fn handle_python_reqs( if has_work { let total_time = total_time.elapsed().as_millis(); - append_logs(&job_id, w_id, format!("\nenv set in {}ms", total_time), db).await; + append_logs( + &job_id, + w_id, + format!("\nenv set in {}ms", total_time), + conn, + ) + .await; } *mem_peak = *mem_peak_thread_safe.lock().await; @@ -2318,7 +2345,7 @@ pub async fn start_worker( let mut mem_peak: i32 = 0; let mut canceled_by: Option = None; let context = variables::get_reserved_variables( - db, + &Connection::Sql(db.clone()), w_id, &token, "dedicated_worker@windmill.dev", @@ -2345,12 +2372,13 @@ pub async fn start_worker( w_id, script_path, &Uuid::nil(), - db, + &Connection::Sql(db.clone()), worker_name, job_dir, &mut mem_peak, &mut canceled_by, &mut None, + None, ) .await?; @@ -2433,7 +2461,7 @@ for line in sys.stdin: } let reserved_variables = windmill_common::variables::get_reserved_variables( - db, + &Connection::Sql(db.clone()), w_id, token, "dedicated_worker", @@ -2475,7 +2503,7 @@ for line in sys.stdin: &Uuid::nil(), w_id, &mut mem_peak, - db, + &Connection::Sql(db.clone()), &mut None, ) .await?; diff --git a/backend/windmill-worker/src/result_processor.rs b/backend/windmill-worker/src/result_processor.rs index 4c2e9fa7a0..e1b2a763f6 100644 --- a/backend/windmill-worker/src/result_processor.rs +++ b/backend/windmill-worker/src/result_processor.rs @@ -2,7 +2,7 @@ use opentelemetry::trace::FutureExt; use serde::Serialize; -use sqlx::{types::Json, Pool, Postgres}; +use sqlx::types::Json; use std::{ collections::HashMap, sync::{ @@ -21,35 +21,105 @@ use windmill_common::{ error::{self, Error}, jobs::JobKind, utils::WarnAfterExt, - worker::{to_raw_value, WORKER_GROUP}, + worker::{to_raw_value, Connection, WORKER_GROUP}, KillpillSender, DB, }; #[cfg(feature = "benchmark")] -use crate::bench::{BenchmarkInfo, BenchmarkIter}; +use windmill_common::bench::{BenchmarkInfo, BenchmarkIter}; -use windmill_queue::{append_logs, get_queued_job, CanceledBy, MiniPulledJob, WrappedError}; +use windmill_queue::{ + append_logs, get_queued_job, CanceledBy, JobCompleted, MiniPulledJob, WrappedError, +}; use serde_json::{json, value::RawValue}; -use tokio::{ - sync::mpsc::{Receiver, Sender}, - task::JoinHandle, -}; +use tokio::{sync::broadcast, task::JoinHandle}; use windmill_queue::{add_completed_job, add_completed_job_error}; use crate::{ bash_executor::ANSI_ESCAPE_RE, - common::{read_result, save_in_cache}, + common::{error_to_value, read_result, save_in_cache}, otel_ee::add_root_flow_job_to_otlp, worker_flow::update_flow_status_after_job_completion, - AuthedClient, JobCompleted, JobCompletedSender, SameWorkerSender, SendResult, INIT_SCRIPT_TAG, + AuthedClient, JobCompletedSender, SameWorkerSender, SendResult, INIT_SCRIPT_TAG, }; +async fn process_jc( + jc: JobCompleted, + worker_name: &str, + base_internal_url: &str, + db: &DB, + worker_dir: &str, + same_worker_tx: &SameWorkerSender, + job_completed_sender: &JobCompletedSender, + #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, +) { + let success: bool = jc.success; + + let span = tracing::span!( + tracing::Level::INFO, + "job_postprocessing", + job_id = %jc.job.id, root_job = field::Empty, workspace_id = %jc.job.workspace_id, worker = %worker_name,tag = %jc.job.tag, + // hostname = %hostname, + language = field::Empty, + script_path = field::Empty, + flow_step_id = field::Empty, + parent_job = field::Empty, + otel.name = field::Empty + ); + let rj = if let Some(root_job) = jc.job.flow_innermost_root_job { + root_job + } else { + jc.job.id + }; + windmill_common::otel_ee::set_span_parent(&span, &rj); + + if let Some(lg) = jc.job.script_lang.as_ref() { + span.record("language", lg.as_str()); + } + if let Some(step_id) = jc.job.flow_step_id.as_ref() { + span.record( + "otel.name", + format!("job_postprocessing {}", step_id).as_str(), + ); + span.record("flow_step_id", step_id.as_str()); + } else { + span.record("otel.name", "job postprocessing"); + } + if let Some(parent_job) = jc.job.parent_job.as_ref() { + span.record("parent_job", parent_job.to_string().as_str()); + } + if let Some(script_path) = jc.job.runnable_path.as_ref() { + span.record("script_path", script_path.as_str()); + } + if let Some(root_job) = jc.job.flow_innermost_root_job.as_ref() { + span.record("root_job", root_job.to_string().as_str()); + } + + let root_job = handle_receive_completed_job( + jc, + &base_internal_url, + &db, + &worker_dir, + &same_worker_tx, + &worker_name, + job_completed_sender.clone(), + #[cfg(feature = "benchmark")] + bench, + ) + .instrument(span) + .await; + + if let Some(root_job) = root_job { + add_root_flow_job_to_otlp(&root_job, success); + } +} + pub fn start_background_processor( - mut job_completed_rx: Receiver, - job_completed_sender: Sender, + job_completed_rx: flume::Receiver, + job_completed_sender: JobCompletedSender, same_worker_queue_size: Arc, job_completed_processor_is_done: Arc, base_internal_url: String, @@ -57,6 +127,7 @@ pub fn start_background_processor( worker_dir: String, same_worker_tx: SameWorkerSender, worker_name: String, + mut killpill_rx: broadcast::Receiver<()>, killpill_tx: KillpillSender, is_dedicated_worker: bool, ) -> JoinHandle<()> { @@ -66,19 +137,33 @@ pub fn start_background_processor( #[cfg(feature = "benchmark")] let mut infos = BenchmarkInfo::new(); + enum JobCompletedRx { + JobCompleted(SendResult), + Killpill, + } //if we have been killed, we want to drain the queue of jobs while let Some(sr) = { if has_been_killed && same_worker_queue_size.load(Ordering::SeqCst) == 0 { - job_completed_rx.try_recv().ok() + job_completed_rx + .try_recv() + .ok() + .map(JobCompletedRx::JobCompleted) } else { - job_completed_rx.recv().await + tokio::select! { + result = job_completed_rx.recv_async() => { + result.ok().map(JobCompletedRx::JobCompleted) + } + _ = killpill_rx.recv() => { + Some(JobCompletedRx::Killpill) + } + } } } { #[cfg(feature = "benchmark")] let mut bench = BenchmarkIter::new(); match sr { - SendResult::JobCompleted(jc) => { + JobCompletedRx::JobCompleted(SendResult::JobCompleted(jc)) => { let is_init_script_and_failure = !jc.success && jc.job.tag.as_str() == INIT_SCRIPT_TAG; let is_dependency_job = matches!( @@ -86,66 +171,19 @@ pub fn start_background_processor( JobKind::Dependencies | JobKind::FlowDependencies ); - let success = jc.success; - - let span = tracing::span!( - tracing::Level::INFO, - "job_postprocessing", - job_id = %jc.job.id, root_job = field::Empty, workspace_id = %jc.job.workspace_id, worker = %worker_name,tag = %jc.job.tag, - // hostname = %hostname, - language = field::Empty, - script_path = field::Empty, - flow_step_id = field::Empty, - parent_job = field::Empty, - otel.name = field::Empty - ); - let rj = if let Some(root_job) = jc.job.flow_innermost_root_job { - root_job - } else { - jc.job.id - }; - windmill_common::otel_ee::set_span_parent(&span, &rj); - - if let Some(lg) = jc.job.script_lang.as_ref() { - span.record("language", lg.as_str()); - } - if let Some(step_id) = jc.job.flow_step_id.as_ref() { - span.record( - "otel.name", - format!("job_postprocessing {}", step_id).as_str(), - ); - span.record("flow_step_id", step_id.as_str()); - } else { - span.record("otel.name", "job postprocessing"); - } - if let Some(parent_job) = jc.job.parent_job.as_ref() { - span.record("parent_job", parent_job.to_string().as_str()); - } - if let Some(script_path) = jc.job.runnable_path.as_ref() { - span.record("script_path", script_path.as_str()); - } - if let Some(root_job) = jc.job.flow_innermost_root_job.as_ref() { - span.record("root_job", root_job.to_string().as_str()); - } - - let root_job = handle_receive_completed_job( + process_jc( jc, + &worker_name, &base_internal_url, &db, &worker_dir, &same_worker_tx, - &worker_name, - job_completed_sender.clone(), + &job_completed_sender, #[cfg(feature = "benchmark")] &mut bench, ) - .instrument(span) .await; - if let Some(root_job) = root_job { - add_root_flow_job_to_otlp(&root_job, success); - } - if is_init_script_and_failure { tracing::error!("init script errored, exiting"); killpill_tx.send(); @@ -169,7 +207,7 @@ pub fn start_background_processor( infos.add_iter(bench, true); } } - SendResult::UpdateFlow { + JobCompletedRx::JobCompleted(SendResult::UpdateFlow { flow, w_id, success, @@ -177,7 +215,7 @@ pub fn start_background_processor( worker_dir, stop_early_override, token, - } => { + }) => { // let r; tracing::info!(parent_flow = %flow, "updating flow status"); if let Err(e) = update_flow_status_after_job_completion( @@ -207,7 +245,7 @@ pub fn start_background_processor( tracing::error!("Error updating flow status after job completion for {flow} on {worker_name}: {e:#}"); } } - SendResult::Kill => { + JobCompletedRx::Killpill => { has_been_killed = true; } } @@ -250,7 +288,7 @@ async fn send_job_completed( duration, }; job_completed_tx - .send(jc) + .send_job(jc) .with_context(windmill_common::otel_ee::otel_ctx()) .await .expect("send job completed") @@ -267,20 +305,22 @@ pub async fn process_result( token: &str, column_order: Option>, new_args: Option>>, - db: &DB, + conn: &Connection, duration: Option, ) -> error::Result { match result { Ok(r) => { // Update script args to preprocessed args - if let Some(preprocessed_args) = new_args { - sqlx::query!( - "UPDATE v2_job SET args = $1, preprocessed = TRUE WHERE id = $2", - Json(preprocessed_args) as Json>>, - job.id - ) - .execute(db) - .await?; + if let Connection::Sql(db) = conn { + if let Some(preprocessed_args) = new_args { + sqlx::query!( + "UPDATE v2_job SET args = $1, preprocessed = TRUE WHERE id = $2", + Json(preprocessed_args) as Json>>, + job.id + ) + .execute(db) + .await?; + } } send_job_completed( @@ -307,18 +347,30 @@ pub async fn process_result( if res.as_ref().is_some_and(|x| !x.get().is_empty()) { res.unwrap() } else { - let last_10_log_lines = sqlx::query_scalar!( + match conn { + Connection::Sql(db) => { + let last_10_log_lines = sqlx::query_scalar!( "SELECT right(logs, 600) FROM job_logs WHERE job_id = $1 AND workspace_id = $2 ORDER BY created_at DESC LIMIT 1", &job.id, &job.workspace_id ).fetch_one(db).await.ok().flatten().unwrap_or("".to_string()); - let log_lines = last_10_log_lines - .split("CODE EXECUTION ---") - .last() - .unwrap_or(&last_10_log_lines); + let log_lines = last_10_log_lines + .split("CODE EXECUTION ---") + .last() + .unwrap_or(&last_10_log_lines); - extract_error_value(&program, log_lines, i, job.flow_step_id.clone()) + extract_error_value( + &program, + log_lines, + i, + job.flow_step_id.clone(), + ) + } + Connection::Http(_) => { + to_raw_value(&"See logs for more details".to_string()) + } + } } } err @ _ => to_raw_value(&SerializedError { @@ -355,7 +407,7 @@ pub async fn handle_receive_completed_job( worker_dir: &str, same_worker_tx: &SameWorkerSender, worker_name: &str, - job_completed_tx: Sender, + job_completed_tx: JobCompletedSender, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> Option> { let token = jc.token.clone(); @@ -422,7 +474,7 @@ pub async fn process_completed_job( worker_dir: &str, same_worker_tx: SameWorkerSender, worker_name: &str, - job_completed_tx: Sender, + job_completed_tx: JobCompletedSender, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> error::Result>> { if success { @@ -455,6 +507,8 @@ pub async fn process_completed_job( })?; } + add_time!(bench, "pre add_completed_job"); + add_completed_job( db, &job, @@ -543,7 +597,7 @@ pub async fn process_completed_job( #[tracing::instrument(name = "job_error", level = "info", skip_all, fields(job_id = %job.id))] pub async fn handle_job_error( - db: &Pool, + db: &DB, client: &AuthedClient, job: &MiniPulledJob, mem_peak: i32, @@ -553,20 +607,17 @@ pub async fn handle_job_error( same_worker_tx: SameWorkerSender, worker_dir: &str, worker_name: &str, - job_completed_tx: Sender, + job_completed_tx: JobCompletedSender, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) { - let err = match err { - Error::JsonErr(err) => err, - _ => json!({"message": err.to_string(), "name": "InternalErr"}), - }; + let err = error_to_value(err); let update_job_future = || async { append_logs( &job.id, &job.workspace_id, format!("Unexpected error during job execution:\n{err:#?}"), - db, + &db.into(), ) .await; add_completed_job_error( @@ -626,7 +677,7 @@ pub async fn handle_job_error( &parent_job.id, &job.workspace_id, format!("Unexpected error during flow job error handling:\n{err}"), - db, + &db.into(), ) .await; let _ = add_completed_job_error( diff --git a/backend/windmill-worker/src/rust_executor.rs b/backend/windmill-worker/src/rust_executor.rs index d2a0c3217d..9f0b783471 100644 --- a/backend/windmill-worker/src/rust_executor.rs +++ b/backend/windmill-worker/src/rust_executor.rs @@ -8,7 +8,7 @@ use tokio::{fs::File, io::AsyncReadExt, process::Command}; use windmill_common::{ error::{self, Error}, utils::calculate_hash, - worker::{save_cache, write_file}, + worker::{save_cache, write_file, Connection}, }; use windmill_queue::MiniPulledJob; use windmill_queue::{append_logs, CanceledBy}; @@ -127,7 +127,7 @@ pub async fn generate_cargo_lockfile( mem_peak: &mut i32, canceled_by: &mut Option, job_dir: &str, - db: &sqlx::Pool, + conn: &Connection, worker_name: &str, w_id: &str, occupancy_metrics: &mut OccupancyMetrics, @@ -153,7 +153,7 @@ pub async fn generate_cargo_lockfile( let gen_lockfile_process = start_child_process(gen_lockfile_cmd, CARGO_PATH.as_str()).await?; handle_child( job_id, - db, + conn, mem_peak, canceled_by, gen_lockfile_process, @@ -164,6 +164,7 @@ pub async fn generate_cargo_lockfile( None, false, &mut Some(occupancy_metrics), + None, ) .await?; @@ -179,7 +180,7 @@ pub async fn build_rust_crate( mem_peak: &mut i32, canceled_by: &mut Option, job_dir: &str, - db: &sqlx::Pool, + conn: &Connection, worker_name: &str, w_id: &str, base_internal_url: &str, @@ -215,7 +216,7 @@ pub async fn build_rust_crate( let build_rust_process = start_child_process(build_rust_cmd, CARGO_PATH.as_str()).await?; handle_child( job_id, - db, + conn, mem_peak, canceled_by, build_rust_process, @@ -226,9 +227,10 @@ pub async fn build_rust_crate( None, false, &mut Some(occupancy_metrics), + None, ) .await?; - append_logs(job_id, w_id, "\n\n", db).await; + append_logs(job_id, w_id, "\n\n", conn).await; tokio::fs::copy( &format!("{job_dir}/target/release/main"), @@ -245,6 +247,7 @@ pub async fn build_rust_crate( &bin_path, &format!("{RUST_OBJECT_STORE_PREFIX}{hash}"), &format!("{job_dir}/main"), + false, ) .await { @@ -276,7 +279,7 @@ pub async fn handle_rust_job( mem_peak: &mut i32, canceled_by: &mut Option, job: &MiniPulledJob, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, inner_content: &str, @@ -294,7 +297,8 @@ pub async fn handle_rust_job( let bin_path = format!("{}/{hash}", RUST_CACHE_DIR); let remote_path = format!("{RUST_OBJECT_STORE_PREFIX}{hash}"); - let (cache, cache_logs) = windmill_common::worker::load_cache(&bin_path, &remote_path).await; + let (cache, cache_logs) = + windmill_common::worker::load_cache(&bin_path, &remote_path, false).await; let cache_logs = if cache { let target = format!("{job_dir}/main"); @@ -310,11 +314,11 @@ pub async fn handle_rust_job( )) })?; - create_args_and_out_file(client, job, job_dir, db).await?; + create_args_and_out_file(client, job, job_dir, conn).await?; cache_logs } else { let logs1 = format!("{cache_logs}\n\n--- CARGO BUILD ---\n"); - append_logs(&job.id, &job.workspace_id, logs1, db).await; + append_logs(&job.id, &job.workspace_id, logs1, conn).await; gen_cargo_crate(inner_content, job_dir)?; @@ -324,14 +328,14 @@ pub async fn handle_rust_job( } } - create_args_and_out_file(client, job, job_dir, db).await?; + create_args_and_out_file(client, job, job_dir, conn).await?; build_rust_crate( &job.id, mem_peak, canceled_by, job_dir, - db, + conn, worker_name, &job.workspace_id, base_internal_url, @@ -342,10 +346,10 @@ pub async fn handle_rust_job( }; let logs2 = format!("{cache_logs}\n\n--- RUST CODE EXECUTION ---\n"); - append_logs(&job.id, &job.workspace_id, logs2, db).await; + append_logs(&job.id, &job.workspace_id, logs2, conn).await; let reserved_variables = - get_reserved_variables(job, &client.token, db, parent_runnable_path).await?; + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; let child = if !*DISABLE_NSJAIL { let _ = write_file( @@ -396,7 +400,7 @@ pub async fn handle_rust_job( }; handle_child( &job.id, - db, + conn, mem_peak, canceled_by, child, @@ -407,6 +411,7 @@ pub async fn handle_rust_job( job.timeout, false, &mut Some(occupancy_metrics), + None, ) .await?; read_result(job_dir).await diff --git a/backend/windmill-worker/src/snowflake_executor.rs b/backend/windmill-worker/src/snowflake_executor.rs index 377c553d56..a4aba420c0 100644 --- a/backend/windmill-worker/src/snowflake_executor.rs +++ b/backend/windmill-worker/src/snowflake_executor.rs @@ -9,6 +9,7 @@ use serde_json::{json, value::RawValue, Value}; use sha2::{Digest, Sha256}; use std::collections::HashMap; use windmill_common::error::to_anyhow; +use windmill_common::worker::Connection; use windmill_common::{error::Error, worker::to_raw_value}; use windmill_parser_sql::{parse_db_resource, parse_snowflake_sig, parse_sql_blocks}; @@ -249,14 +250,14 @@ pub async fn do_snowflake( job: &MiniPulledJob, client: &AuthedClient, query: &str, - db: &sqlx::Pool, + conn: &Connection, mem_peak: &mut i32, canceled_by: &mut Option, worker_name: &str, column_order: &mut Option>, occupancy_metrics: &mut OccupancyMetrics, ) -> windmill_common::error::Result> { - let snowflake_args = build_args_values(job, client, db).await?; + let snowflake_args = build_args_values(job, client, conn).await?; let inline_db_res_path = parse_db_resource(&query); @@ -362,7 +363,7 @@ pub async fn do_snowflake( json!(database.database.unwrap().to_uppercase()), ); } - let timeout = resolve_job_timeout(&db, &job.workspace_id, job.id, job.timeout) + let timeout = resolve_job_timeout(&conn, &job.workspace_id, job.id, job.timeout) .await .0 .as_secs(); @@ -371,7 +372,7 @@ pub async fn do_snowflake( let queries = parse_sql_blocks(query); let (timeout_duration, _, _) = - resolve_job_timeout(&db, &job.workspace_id, job.id, job.timeout).await; + resolve_job_timeout(&conn, &job.workspace_id, job.id, job.timeout).await; let http_client = build_http_client(timeout_duration)?; @@ -424,7 +425,7 @@ pub async fn do_snowflake( let r = run_future_with_polling_update_job_poller( job.id, job.timeout, - db, + conn, mem_peak, canceled_by, result_f.map_err(to_anyhow), diff --git a/backend/windmill-worker/src/worker.rs b/backend/windmill-worker/src/worker.rs index f37df77c63..34193803f6 100644 --- a/backend/windmill-worker/src/worker.rs +++ b/backend/windmill-worker/src/worker.rs @@ -12,16 +12,15 @@ use anyhow::anyhow; use futures::TryFutureExt; use windmill_common::{ + agent_workers::DECODED_AGENT_TOKEN, apps::AppScriptId, - auth::{fetch_authed_from_permissioned_as, JWTAuthClaims, JobPerms}, cache::{future::FutureCachedExt, ScriptData, ScriptMetadata}, - jwt, schema::{should_validate_schema, SchemaValidator}, scripts::PREVIEW_IS_TAR_CODEBASE_HASH, utils::WarnAfterExt, worker::{ - get_memory, get_vcpus, get_windmill_memory_usage, get_worker_memory_usage, write_file, - ROOT_CACHE_DIR, ROOT_CACHE_NOMOUNT_DIR, TMP_DIR, + write_file, Connection, HttpClient, MAX_TIMEOUT, ROOT_CACHE_DIR, ROOT_CACHE_NOMOUNT_DIR, + TMP_DIR, }, KillpillSender, }; @@ -42,7 +41,7 @@ use windmill_common::METRICS_ENABLED; use reqwest::Response; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use sqlx::{types::Json, Pool, Postgres}; +use sqlx::types::Json; use std::{ collections::HashMap, fs::DirBuilder, @@ -62,15 +61,15 @@ use windmill_common::{ flows::FlowNodeId, jobs::JobKind, scripts::{get_full_hub_script_by_path, ScriptHash, ScriptLang, PREVIEW_IS_CODEBASE_HASH}, - users::SUPERADMIN_SECRET_EMAIL, utils::StripPath, - worker::{update_ping, CLOUD_HOSTED, NO_LOGS, WORKER_CONFIG, WORKER_GROUP}, + worker::{CLOUD_HOSTED, NO_LOGS, WORKER_CONFIG, WORKER_GROUP}, DB, IS_READY, }; use windmill_queue::{ - append_logs, canceled_job_to_result, empty_result, pull, push, CanceledBy, MiniPulledJob, - PulledJob, PushArgs, PushIsolationLevel, HTTP_CLIENT, + append_logs, canceled_job_to_result, empty_result, get_same_worker_job, pull, push_init_job, + CanceledBy, JobAndPerms, JobCompleted, MiniPulledJob, PrecomputedAgentInfo, PulledJob, + SameWorkerPayload, HTTP_CLIENT, }; #[cfg(feature = "prometheus")] @@ -86,7 +85,8 @@ use tokio::fs::symlink_file as symlink; use tokio::{ sync::{ - mpsc::{self, Sender}, + broadcast, + mpsc::{self, Receiver, Sender}, RwLock, }, task::JoinHandle, @@ -96,10 +96,11 @@ use tokio::{ use rand::Rng; use crate::{ + agent_workers::queue_init_job, bash_executor::{handle_bash_job, handle_powershell_job}, bun_executor::handle_bun_job, common::{ - build_args_map, cached_result_path, get_cached_resource_value_if_valid, + build_args_map, cached_result_path, error_to_value, get_cached_resource_value_if_valid, get_reserved_variables, update_worker_ping_for_failed_init_script, OccupancyMetrics, }, csharp_executor::handle_csharp_job, @@ -113,17 +114,21 @@ use crate::{ pg_executor::do_postgresql, result_processor::{process_result, start_background_processor}, schema::schema_validator_from_main_arg_sig, - worker_flow::{handle_flow, update_flow_status_in_progress}, + worker_flow::handle_flow, worker_lockfiles::{ handle_app_dependency_job, handle_dependency_job, handle_flow_dependency_job, }, + worker_utils::{insert_ping, queue_vacuum, update_worker_ping_full}, }; #[cfg(feature = "rust")] use crate::rust_executor::handle_rust_job; #[cfg(feature = "nu")] -use crate::nu_executor::{handle_nu_job, JobHandlerInput}; +use crate::nu_executor::{handle_nu_job, JobHandlerInput as JobHandlerInputNu}; + +#[cfg(feature = "java")] +use crate::java_executor::{handle_java_job, JobHandlerInput as JobHandlerInputJava}; #[cfg(feature = "php")] use crate::php_executor::handle_php_job; @@ -140,9 +145,6 @@ use crate::mysql_executor::do_mysql; #[cfg(feature = "oracledb")] use crate::oracledb_executor::do_oracledb; -use backon::ConstantBuilder; -use backon::{BackoffBuilder, Retryable}; - #[cfg(feature = "enterprise")] use crate::dedicated_worker::create_dedicated_worker_map; @@ -156,104 +158,10 @@ use crate::mssql_executor::do_mssql; use crate::bigquery_executor::do_bigquery; #[cfg(feature = "benchmark")] -use crate::bench::{benchmark_init, BenchmarkInfo, BenchmarkIter}; +use windmill_common::bench::{benchmark_init, BenchmarkInfo, BenchmarkIter}; use windmill_common::add_time; -// struct Permission -pub async fn create_token(db: &DB, job: &MiniPulledJob, perms: Option) -> String { - // skipping test runs - if job.workspace_id != "" { - let label = if job.permissioned_as != format!("u/{}", job.created_by) - && job.permissioned_as != job.created_by - { - format!("ephemeral-script-end-user-{}", job.created_by) - } else { - "ephemeral-script".to_string() - }; - create_token_for_owner( - &db, - &job.workspace_id, - &job.permissioned_as, - &label, - *SCRIPT_TOKEN_EXPIRY, - &job.permissioned_as_email, - &job.id, - perms, - ) - .warn_after_seconds(5) - .await - .expect("could not create job token") - } else { - return "".to_string(); - } -} - -#[tracing::instrument(level = "trace", skip_all)] -pub async fn create_token_for_owner( - db: &Pool, - w_id: &str, - owner: &str, - label: &str, - expires_in: u64, - email: &str, - job_id: &Uuid, - perms: Option, -) -> error::Result { - // TODO: Bad implementation. We should not have access to this DB here. - if let Some(token) = JOB_TOKEN.as_ref() { - return Ok(token.clone()); - } - - let job_perms = if perms.is_some() { - Ok(perms) - } else { - sqlx::query_as!( - JobPerms, - "SELECT email, username, is_admin, is_operator, groups, folders FROM job_perms WHERE job_id = $1 AND workspace_id = $2", - job_id, - w_id - ) - .fetch_optional(db) - .await - }; - - let job_authed = match job_perms { - Ok(Some(jp)) => jp.into(), - _ => { - tracing::warn!("Could not get permissions for job {job_id} from job_perms table, getting permissions directly..."); - fetch_authed_from_permissioned_as(owner.to_string(), email.to_string(), w_id, db) - .await - .map_err(|e| { - Error::internal_err(format!( - "Could not get permissions directly for job {job_id}: {e:#}" - )) - })? - } - }; - - let payload = JWTAuthClaims { - email: job_authed.email, - username: job_authed.username, - is_admin: job_authed.is_admin, - is_operator: job_authed.is_operator, - groups: job_authed.groups, - folders: job_authed.folders, - label: Some(label.to_string()), - workspace_id: w_id.to_string(), - exp: (chrono::Utc::now() + chrono::Duration::seconds(expires_in as i64)).timestamp() - as usize, - job_id: Some(job_id.to_string()), - scopes: None, - }; - - let token = jwt::encode_with_internal_secret(&payload) - .await - .with_context(|| format!("Could not encode JWT token for job {job_id}"))?; - - Ok(format!("jwt_{}", token)) -} - pub const PY310_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "python_310"); pub const PY311_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "python_311"); pub const PY312_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "python_312"); @@ -264,6 +172,8 @@ pub const TAR_PY311_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "tar/python_311" pub const TAR_PY312_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "tar/python_312"); pub const TAR_PY313_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "tar/python_313"); +pub const TAR_JAVA_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "tar/java"); + pub const UV_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "uv"); pub const PY_INSTALL_DIR: &str = concatcp!(ROOT_CACHE_DIR, "py_runtime"); pub const TAR_PYBASE_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "tar"); @@ -275,6 +185,12 @@ pub const GO_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "go"); pub const RUST_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "rust"); pub const NU_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "nu"); pub const CSHARP_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "csharp"); + +// JAVA +pub const JAVA_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "java"); +pub const COURSIER_CACHE_DIR: &str = concatcp!(JAVA_CACHE_DIR, "/coursier-cache"); +pub const JAVA_REPOSITORY_DIR: &str = concatcp!(JAVA_CACHE_DIR, "/repository"); +// for related places search: ADD_NEW_LANG pub const BUN_CACHE_DIR: &str = concatcp!(ROOT_CACHE_NOMOUNT_DIR, "bun"); pub const BUN_BUNDLE_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "bun"); pub const BUN_CODEBASE_BUNDLE_CACHE_DIR: &str = concatcp!(ROOT_CACHE_NOMOUNT_DIR, "script_bundle"); @@ -288,8 +204,6 @@ const NUM_SECS_READINGS: u64 = 60; const INCLUDE_DEPS_PY_SH_CONTENT: &str = include_str!("../nsjail/download_deps.py.sh"); -pub const DEFAULT_CLOUD_TIMEOUT: u64 = 900; -pub const DEFAULT_SELFHOSTED_TIMEOUT: u64 = 604800; // 7 days pub const DEFAULT_SLEEP_QUEUE: u64 = 50; // only 1 native job so that we don't have to worry about concurrency issues on non dedicated native jobs workers @@ -297,8 +211,8 @@ pub const DEFAULT_NATIVE_JOBS: usize = 1; const VACUUM_PERIOD: u32 = 50000; -#[cfg(any(target_os = "linux"))] -const DROP_CACHE_PERIOD: u32 = 1000; +// #[cfg(any(target_os = "linux"))] +// const DROP_CACHE_PERIOD: u32 = 1000; pub const MAX_BUFFERED_DEDICATED_JOBS: usize = 3; @@ -330,16 +244,20 @@ const DOTNET_DEFAULT_PATH: &str = "/usr/bin/dotnet"; lazy_static::lazy_static! { - pub static ref JOB_TOKEN: Option = std::env::var("JOB_TOKEN").ok(); - pub static ref SLEEP_QUEUE: u64 = std::env::var("SLEEP_QUEUE") .ok() - .and_then(|x| x.parse::().ok()) - .unwrap_or(DEFAULT_SLEEP_QUEUE * std::env::var("NUM_WORKERS") - .ok() - .map(|x| x.parse().ok()) - .flatten() - .unwrap_or(2) / 2); + .and_then(|x| x.parse::().ok()) + .unwrap_or_else(|| { + if std::env::var("MODE").unwrap_or_default() == "agent" { + 1000 + } else { + DEFAULT_SLEEP_QUEUE * std::env::var("NUM_WORKERS") + .ok() + .map(|x| x.parse().ok()) + .flatten() + .unwrap_or(2) / 2 + } + }); pub static ref DISABLE_NUSER: bool = std::env::var("DISABLE_NUSER") @@ -399,16 +317,18 @@ lazy_static::lazy_static! { pub static ref NPM_CONFIG_REGISTRY: Arc>> = Arc::new(RwLock::new(None)); pub static ref BUNFIG_INSTALL_SCOPES: Arc>> = Arc::new(RwLock::new(None)); pub static ref NUGET_CONFIG: Arc>> = Arc::new(RwLock::new(None)); + pub static ref MAVEN_REPOS: Arc>> = Arc::new(RwLock::new(None)); + pub static ref NO_DEFAULT_MAVEN: AtomicBool = AtomicBool::new(std::env::var("NO_DEFAULT_MAVEN") + .ok() + .and_then(|x| x.parse::().ok()) + .unwrap_or(false)); pub static ref PIP_EXTRA_INDEX_URL: Arc>> = Arc::new(RwLock::new(None)); pub static ref PIP_INDEX_URL: Arc>> = Arc::new(RwLock::new(None)); pub static ref INSTANCE_PYTHON_VERSION: Arc>> = Arc::new(RwLock::new(None)); pub static ref JOB_DEFAULT_TIMEOUT: Arc>> = Arc::new(RwLock::new(None)); - static ref MAX_TIMEOUT: u64 = std::env::var("TIMEOUT") - .ok() - .and_then(|x| x.parse::().ok()) - .unwrap_or_else(|| if *CLOUD_HOSTED { DEFAULT_CLOUD_TIMEOUT } else { DEFAULT_SELFHOSTED_TIMEOUT }); + pub static ref MAX_WAIT_FOR_SIGINT: u64 = std::env::var("MAX_WAIT_FOR_SIGINT") .ok() @@ -422,10 +342,6 @@ lazy_static::lazy_static! { pub static ref MAX_TIMEOUT_DURATION: Duration = Duration::from_secs(*MAX_TIMEOUT); - pub static ref SCRIPT_TOKEN_EXPIRY: u64 = std::env::var("SCRIPT_TOKEN_EXPIRY") - .ok() - .and_then(|x| x.parse::().ok()) - .unwrap_or(*MAX_TIMEOUT); pub static ref GLOBAL_CACHE_INTERVAL: u64 = std::env::var("GLOBAL_CACHE_INTERVAL") .ok() @@ -604,24 +520,96 @@ impl AuthedClient { } } -#[allow(dead_code)] -#[derive(Clone)] -pub struct JobCompletedSender(Sender); - #[derive(Clone)] pub struct SameWorkerSender(pub Sender, pub Arc); -pub struct SameWorkerPayload { - pub job_id: Uuid, - pub recoverable: bool, +#[allow(dead_code)] +#[derive(Clone)] +pub enum JobCompletedSender { + Sql(flume::Sender, broadcast::Sender<()>), + Http(HttpClient), + NeverUsed, } impl JobCompletedSender { - pub async fn send( - &self, - jc: JobCompleted, - ) -> Result<(), tokio::sync::mpsc::error::SendError> { - self.0.send(SendResult::JobCompleted(jc)).await + pub fn new( + conn: &Connection, + buffer_size: usize, + ) -> ( + Self, + Option<(flume::Receiver, broadcast::Receiver<()>)>, + ) { + match conn { + Connection::Sql(_) => { + let (sender, receiver) = flume::bounded::(buffer_size); + let (killpill_tx, killpill_rx) = broadcast::channel::<()>(buffer_size); + ( + Self::Sql(sender, killpill_tx), + Some((receiver, killpill_rx)), + ) + } + Connection::Http(client) => (Self::Http(client.clone()), None), + } + } + pub fn new_never_used() -> (Self, Option>) { + (Self::NeverUsed, None) + } + + pub async fn send_job(&self, jc: JobCompleted) -> anyhow::Result<()> { + match self { + Self::Sql(sender, _) => sender + .send_async(SendResult::JobCompleted(jc)) + .await + .map_err(|_e| { + anyhow::anyhow!("Failed to send job completed to background processor") + }), + Self::Http(client) => { + crate::agent_workers::send_result(client, jc).await?; + Ok(()) + } + Self::NeverUsed => { + tracing::error!( + "Sending job completed to NeverUsed JobCompletedSender, this should not happen" + ); + Ok(()) + } + } + } + + pub async fn send(&self, send_result: SendResult) -> Result<(), flume::SendError> { + match self { + Self::Sql(sender, _) => sender.send_async(send_result).await, + Self::Http(_) => { + tracing::error!("Sending job completed to http client, this should not happen"); + Ok(()) + } + Self::NeverUsed => { + tracing::error!( + "Sending job completed to NeverUsed JobCompletedSender, this should not happen" + ); + Ok(()) + } + } + } + + pub async fn kill(&self) -> Result<(), broadcast::error::SendError<()>> { + match self { + Self::Sql(_, killpill_tx) => { + tracing::info!("Sending killpill to bg processors"); + killpill_tx.send(())?; + Ok(()) + } + Self::Http(_) => { + tracing::error!("Sending kill to http client, this should not happen"); + Ok(()) + } + Self::NeverUsed => { + tracing::error!( + "Sending kill to NeverUsed JobCompletedSender, this should not happen" + ); + Ok(()) + } + } } } @@ -650,11 +638,11 @@ pub async fn drop_cache() { Ok(mut file) => { // Write '3' to the file to drop caches if let Err(e) = tokio::io::AsyncWriteExt::write_all(&mut file, b"3").await { - tracing::warn!("Failed to write to /proc/sys/vm/drop_caches (expected to not work in not in privileged mode, only required to forcefully drop the cache to avoid spurrious oom killer): {}", e); + tracing::warn!("Failed to write to /proc/sys/vm/drop_caches (expected to work only in privileged mode, only required to forcefully drop the cache to avoid spurrious oom killer): {}", e); } } Err(e) => { - tracing::warn!("Failed to open /proc/sys/vm/drop_caches (expected to not work in not in privileged mode, only required to forcefully drop the cache to avoid spurrious oom killer):: {}", e); + tracing::warn!("Failed to open /proc/sys/vm/drop_caches (expected to work only in privileged mode, only required to forcefully drop the cache to avoid spurrious oom killer):: {}", e); } } } @@ -664,17 +652,17 @@ const OUTSTANDING_WAIT_TIME_THRESHOLD_MS: i64 = 1000; async fn insert_wait_time( job_id: Uuid, root_job_id: Option, - db: &Pool, + db: &DB, wait_time: i64, ) -> sqlx::error::Result<()> { sqlx::query!( - "INSERT INTO outstanding_wait_time(job_id, self_wait_time_ms) VALUES ($1, $2) - ON CONFLICT (job_id) DO UPDATE SET self_wait_time_ms = EXCLUDED.self_wait_time_ms", - job_id, - wait_time - ) - .execute(db) - .await?; + "INSERT INTO outstanding_wait_time(job_id, self_wait_time_ms) VALUES ($1, $2) + ON CONFLICT (job_id) DO UPDATE SET self_wait_time_ms = EXCLUDED.self_wait_time_ms", + job_id, + wait_time + ) + .execute(db) + .await?; if let Some(root_id) = root_job_id { // TODO: queued_job.root_job is not guaranteed to be the true root job (e.g. parallel flow @@ -685,16 +673,16 @@ async fn insert_wait_time( COALESCE(outstanding_wait_time.aggregate_wait_time_ms, 0) + EXCLUDED.aggregate_wait_time_ms", root_id, wait_time - ) - .execute(db) - .await?; + ) + .execute(db) + .await?; } Ok(()) } fn add_outstanding_wait_time( + conn: &Connection, queued_job: &MiniPulledJob, - db: &Pool, waiting_threshold: i64, ) -> () { let wait_time; @@ -711,22 +699,21 @@ fn add_outstanding_wait_time( let job_id = queued_job.id; let root_job_id = queued_job.flow_innermost_root_job; - let db = db.clone(); + let conn = conn.clone(); - tokio::spawn(async move { + if let Some(db) = conn.as_sql() { + let db = db.clone(); + tokio::spawn(async move { match insert_wait_time(job_id, root_job_id, &db, wait_time).await { Ok(()) => tracing::warn!("job {job_id} waited for an executor for a significant amount of time. Recording value wait_time={}ms", wait_time), Err(e) => tracing::error!("Failed to insert outstanding wait time: {}", e), } - }.in_current_span()); + }.in_current_span()); + } } -// struct WorkerMtrics { -// job_ -// } - pub async fn run_worker( - db: &Pool, + conn: &Connection, hostname: &str, worker_name: String, i_worker: u64, @@ -735,7 +722,6 @@ pub async fn run_worker( mut killpill_rx: tokio::sync::broadcast::Receiver<()>, killpill_tx: KillpillSender, base_internal_url: &str, - agent_mode: bool, ) { #[cfg(not(feature = "enterprise"))] if !*DISABLE_NSJAIL { @@ -752,16 +738,16 @@ pub async fn run_worker( #[cfg(feature = "python")] { - let (db, worker_name, hostname, worker_dir) = ( - db.clone(), + let (conn, worker_name, hostname, worker_dir) = ( + conn.clone(), worker_name.clone(), hostname.to_owned(), worker_dir.clone(), ); tokio::spawn(async move { - if let Err(e) = PyVersion::from_instance_version(&Uuid::nil(), "", &db) + if let Err(e) = PyVersion::from_instance_version(&Uuid::nil(), "", &conn) .await - .get_python(&Uuid::nil(), &mut 0, &db, &worker_name, "", &mut None) + .get_python(&Uuid::nil(), &mut 0, &conn, &worker_name, "", &mut None) .await { tracing::error!( @@ -772,7 +758,7 @@ pub async fn run_worker( ); } if let Err(e) = PyVersion::Py311 - .get_python(&Uuid::nil(), &mut 0, &db, &worker_name, "", &mut None) + .get_python(&Uuid::nil(), &mut 0, &conn, &worker_name, "", &mut None) .await { tracing::error!( @@ -805,7 +791,9 @@ pub async fn run_worker( let mut last_ping = Instant::now() - Duration::from_secs(NUM_SECS_PING + 1); - update_ping(hostname, &worker_name, ip, db).await; + insert_ping(hostname, &worker_name, ip, conn) + .await + .expect("initial ping could be sent"); #[cfg(feature = "prometheus")] let uptime_metric = if METRICS_ENABLED.load(Ordering::Relaxed) { @@ -1014,7 +1002,11 @@ pub async fn run_worker( .unwrap(); #[cfg(feature = "benchmark")] - benchmark_init(benchmark_jobs, &db).await; + { + if let Some(db) = conn.as_sql() { + benchmark_init(benchmark_jobs, db).await; + } + } #[cfg(feature = "prometheus")] if let Some(ws) = WORKER_STARTED.as_ref() { @@ -1023,27 +1015,32 @@ pub async fn run_worker( let (same_worker_tx, mut same_worker_rx) = mpsc::channel::(5); - let (job_completed_tx, job_completed_rx) = mpsc::channel::(3); - - let job_completed_tx = JobCompletedSender(job_completed_tx); + let (job_completed_tx, job_completed_rx) = JobCompletedSender::new(&conn, 3); let same_worker_queue_size = Arc::new(AtomicU16::new(0)); let same_worker_tx = SameWorkerSender(same_worker_tx, same_worker_queue_size.clone()); - let job_completed_processor_is_done = Arc::new(AtomicBool::new(false)); + let job_completed_processor_is_done = + Arc::new(AtomicBool::new(matches!(conn, Connection::Http(_)))); - let send_result = start_background_processor( - job_completed_rx, - job_completed_tx.0.clone(), - same_worker_queue_size.clone(), - job_completed_processor_is_done.clone(), - base_internal_url.to_string(), - db.clone(), - worker_dir.clone(), - same_worker_tx.clone(), - worker_name.clone(), - killpill_tx.clone(), - is_dedicated_worker, - ); + let send_result = match (conn, job_completed_rx) { + (Connection::Sql(db), Some((job_completed_rx, bg_killpill_rx))) => { + Some(start_background_processor( + job_completed_rx, + job_completed_tx.clone(), + same_worker_queue_size.clone(), + job_completed_processor_is_done.clone(), + base_internal_url.to_string(), + db.clone(), + worker_dir.clone(), + same_worker_tx.clone(), + worker_name.clone(), + bg_killpill_rx, + killpill_tx.clone(), + is_dedicated_worker, + )) + } + _ => None, + }; let mut last_executed_job: Option = None; @@ -1056,12 +1053,20 @@ pub async fn run_worker( let vacuum_shift = rand::rng().random_range(0..VACUUM_PERIOD); IS_READY.store(true, Ordering::Relaxed); - tracing::info!( - worker = %worker_name, hostname = %hostname, - "listening for jobs, WORKER_GROUP: {}, config: {:?}", - *WORKER_GROUP, - WORKER_CONFIG.read().await - ); + if let Some(token) = DECODED_AGENT_TOKEN.as_ref() { + tracing::info!( + worker = %worker_name, hostname = %hostname, + "listening for jobs, agent mode, tags: {:?}", + token.tags + ); + } else { + tracing::info!( + worker = %worker_name, hostname = %hostname, + "listening for jobs, WORKER_GROUP: {}, config: {:?}", + *WORKER_GROUP, + WORKER_CONFIG.read().await + ); + } // (dedi_path, dedicated_worker_tx, dedicated_worker_handle) // Option>>, @@ -1072,16 +1077,21 @@ pub async fn run_worker( HashMap>>, bool, Vec>, - ) = create_dedicated_worker_map( - &killpill_tx, - &killpill_rx, - db, - &worker_dir, - base_internal_url, - &worker_name, - &job_completed_tx, - ) - .await; + ) = match conn { + Connection::Sql(pool) => { + create_dedicated_worker_map( + &killpill_tx, + &killpill_rx, + pool, + &worker_dir, + base_internal_url, + &worker_name, + &job_completed_tx, + ) + .await + } + Connection::Http(_) => (HashMap::new(), false, vec![]), + }; #[cfg(not(feature = "enterprise"))] let (dedicated_workers, is_flow_worker, dedicated_handles): ( @@ -1091,7 +1101,7 @@ pub async fn run_worker( ) = (HashMap::new(), false, vec![]); if i_worker == 1 { - if let Err(e) = queue_init_bash_maybe(db, same_worker_tx.clone(), &worker_name).await { + if let Err(e) = queue_init_bash_maybe(conn, same_worker_tx.clone(), &worker_name).await { killpill_tx.send(); tracing::error!(worker = %worker_name, hostname = %hostname, "Error queuing init bash script for worker {worker_name}: {e:#}"); return; @@ -1118,7 +1128,7 @@ pub async fn run_worker( }; let mut suspend_first_success = false; let mut last_reading = Instant::now() - Duration::from_secs(NUM_SECS_READINGS + 1); - let mut last_30jobs_suspended: Vec = vec![false; 30]; + let mut last_30jobs_suspended = 0; let mut last_suspend_first = Instant::now(); let mut killed_but_draining_same_worker_jobs = false; @@ -1128,11 +1138,12 @@ pub async fn run_worker( { if let Ok(_) = killpill_rx.try_recv() { tracing::info!(worker = %worker_name, hostname = %hostname, "killpill received on worker waiting for valid key"); - job_completed_tx - .0 - .send(SendResult::Kill) - .await - .expect("send kill to job completed tx"); + if send_result.is_some() { + job_completed_tx + .kill() + .await + .expect("send kill to job completed tx"); + } break; } let valid_key = *LICENSE_KEY_VALID.read().await; @@ -1169,106 +1180,70 @@ pub async fn run_worker( } if last_ping.elapsed().as_secs() > NUM_SECS_PING { - let tags = WORKER_CONFIG.read().await.worker_tags.clone(); - - let memory_usage = get_worker_memory_usage(); - let wm_memory_usage = get_windmill_memory_usage(); - - let (vcpus, memory) = if *REFRESH_CGROUP_READINGS - && last_reading.elapsed().as_secs() > NUM_SECS_READINGS - { - last_reading = Instant::now(); - (get_vcpus(), get_memory()) - } else { - (None, None) - }; - - let (occupancy_rate, occupancy_rate_15s, occupancy_rate_5m, occupancy_rate_30m) = - occupancy_metrics.update_occupancy_metrics(); - - if let Err(e) = (|| sqlx::query!( - "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2, - occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, vcpus = COALESCE($7, vcpus), - memory = COALESCE($8, memory), occupancy_rate_15s = $9, occupancy_rate_5m = $10, occupancy_rate_30m = $11 WHERE worker = $6", + let read_cgroups = + *REFRESH_CGROUP_READINGS && last_reading.elapsed().as_secs() > NUM_SECS_READINGS; + update_worker_ping_full( + &conn, + read_cgroups, jobs_executed, - tags.as_slice(), - occupancy_rate, - memory_usage, - wm_memory_usage, &worker_name, - vcpus, - memory, - occupancy_rate_15s, - occupancy_rate_5m, - occupancy_rate_30m - ).execute(db)).retry( - ConstantBuilder::default() - .with_delay(std::time::Duration::from_secs(2)) - .with_max_times(10) - .build(), + &hostname, + &mut occupancy_metrics, + &killpill_tx, ) - .notify(|err, dur| { - tracing::error!( - worker = %worker_name, hostname = %hostname, - "retrying updating worker ping in {dur:#?}, err: {err:#?}" - ); - }) - .sleep(tokio::time::sleep) - .await { - tracing::error!( - worker = %worker_name, hostname = %hostname, - "failed to update worker ping, exiting: {}", e); - killpill_tx.send(); - } - tracing::info!( - worker = %worker_name, hostname = %hostname, - "ping update, memory: container={}MB, windmill={}MB", - memory_usage.unwrap_or_default() / (1024 * 1024), - wm_memory_usage.unwrap_or_default() / (1024 * 1024) - ); + .await; + if read_cgroups { + last_reading = Instant::now(); + } last_ping = Instant::now(); } if (jobs_executed as u32 + vacuum_shift) % VACUUM_PERIOD == 0 { - let db2 = db.clone(); - let current_span = tracing::Span::current(); - let worker_name = worker_name.clone(); - let hostname = hostname.to_string(); - tokio::task::spawn( - (async move { - tracing::info!(worker = %worker_name, hostname = %hostname, "vacuuming queue"); - if let Err(e) = sqlx::query!("VACUUM v2_job_queue, v2_job_runtime, v2_job_status") - .execute(&db2) - .await - { - tracing::error!(worker = %worker_name, hostname = %hostname, "failed to vacuum queue: {}", e); - } - tracing::info!(worker = %worker_name, hostname = %hostname, "vacuumed queue"); - }) - .instrument(current_span), - ); + queue_vacuum(&conn, &worker_name, &hostname).await; jobs_executed += 1; } - #[cfg(any(target_os = "linux"))] - if (jobs_executed as u32 + 1) % DROP_CACHE_PERIOD == 0 { - drop_cache().await; - jobs_executed += 1; - } + // #[cfg(any(target_os = "linux"))] + // if (jobs_executed as u32 + 1) % DROP_CACHE_PERIOD == 0 { + // drop_cache().await; + // jobs_executed += 1; + // } #[cfg(feature = "benchmark")] if benchmark_jobs > 0 && infos.iters == benchmark_jobs as u64 { tracing::info!("benchmark finished, exiting"); job_completed_tx - .0 - .send(SendResult::Kill) + .kill() .await .expect("send kill to job completed tx"); break; } else { tracing::info!("benchmark not finished, still pulling jobs {}", infos.iters); } + enum NextJob { + Sql(PulledJob), + Http(JobAndPerms), + } + + impl NextJob { + pub fn job(self) -> MiniPulledJob { + match self { + NextJob::Sql(job) => job.job, + NextJob::Http(job) => job.job, + } + } + } + + impl std::ops::Deref for NextJob { + type Target = MiniPulledJob; + fn deref(&self) -> &Self::Target { + match self { + NextJob::Sql(job) => &job.job, + NextJob::Http(job) => &job.job, + } + } + } let next_job = { // println!("2: {:?}", instant.elapsed()); @@ -1284,29 +1259,42 @@ pub async fn run_worker( "received {} from same worker channel", same_worker_job.job_id ); - let job = get_same_worker_job(db, &same_worker_job).await; - // tracing::error!("r: {:?}", r); - if job.is_err() && !same_worker_job.recoverable { - tracing::error!( - worker = %worker_name, hostname = %hostname, - "failed to fetch same_worker job on a non recoverable job, exiting" - ); - job_completed_tx - .0 - .send(SendResult::Kill) + + match &conn { + Connection::Sql(db) => { + let job = get_same_worker_job(db, &same_worker_job).await; + // tracing::error!("r: {:?}", r); + if job.is_err() && !same_worker_job.recoverable { + tracing::error!( + worker = %worker_name, hostname = %hostname, + "failed to fetch same_worker job on a non recoverable job, exiting" + ); + job_completed_tx + .kill() + .await + .expect("send kill to job completed tx"); + break; + } else { + job.map(|x| x.map(NextJob::Sql)) + } + } + Connection::Http(client) => client + .post( + &format!( + "/api/agent_workers/same_worker_job/{}", + same_worker_job.job_id + ), + &same_worker_job, + ) .await - .expect("send kill to job completed tx"); - break; - } else { - job + .map_err(|e| error::Error::InternalErr(e.to_string())) + .map(|x: Option| x.map(|y| NextJob::Http(y))), } } else if let Ok(_) = killpill_rx.try_recv() { if !killed_but_draining_same_worker_jobs { - tracing::info!(worker = %worker_name, hostname = %hostname, "received killpill for worker {}, jobs are not pulled anymore except same_worker jobs", i_worker); killed_but_draining_same_worker_jobs = true; job_completed_tx - .0 - .send(SendResult::Kill) + .kill() .await .expect("send kill to job completed tx"); } @@ -1321,75 +1309,91 @@ pub async fn run_worker( continue; } } else { - let pull_time = Instant::now(); - let likelihood_of_suspend = - (1.0 + last_30jobs_suspended.iter().filter(|&&x| x).count() as f64) / 31.0; - let suspend_first = suspend_first_success - || rand::random::() < likelihood_of_suspend - || last_suspend_first.elapsed().as_secs_f64() > 5.0; + match &conn { + Connection::Sql(db) => { + let pull_time = Instant::now(); + let likelihood_of_suspend = last_30jobs_suspended as f64 / 30.0; + let suspend_first = suspend_first_success + || rand::random::() < likelihood_of_suspend + || last_suspend_first.elapsed().as_secs_f64() > 5.0; - if suspend_first { - last_suspend_first = Instant::now(); + if suspend_first { + last_suspend_first = Instant::now(); + } + + let job = pull( + &db, + suspend_first, + &worker_name, + None, + #[cfg(feature = "benchmark")] + &mut bench, + ) + .await; + + add_time!(bench, "job pulled from DB"); + let duration_pull_s = pull_time.elapsed().as_secs_f64(); + let err_pull = job.is_ok(); + // let empty = job.as_ref().is_ok_and(|x| x.is_none()); + + if duration_pull_s > 0.5 { + let empty = job.as_ref().is_ok_and(|x| x.job.is_none()); + tracing::warn!(worker = %worker_name, hostname = %hostname, "pull took more than 0.5s ({duration_pull_s}), this is a sign that the database is VERY undersized for this load. empty: {empty}, err: {err_pull}"); + #[cfg(feature = "prometheus")] + if empty { + if let Some(wp) = worker_pull_over_500_counter_empty.as_ref() { + wp.inc(); + } + } else if let Some(wp) = worker_pull_over_500_counter.as_ref() { + wp.inc(); + } + } else if duration_pull_s > 0.1 { + let empty = job.as_ref().is_ok_and(|x| x.job.is_none()); + tracing::warn!(worker = %worker_name, hostname = %hostname, "pull took more than 0.1s ({duration_pull_s}) this is a sign that the database is undersized for this load. empty: {empty}, err: {err_pull}"); + #[cfg(feature = "prometheus")] + if empty { + if let Some(wp) = worker_pull_over_100_counter_empty.as_ref() { + wp.inc(); + } + } else if let Some(wp) = worker_pull_over_100_counter.as_ref() { + wp.inc(); + } + } + + if let Ok(j) = job.as_ref() { + let suspend_success = j.suspended; + if suspend_first { + if last_30jobs_suspended < 30 { + last_30jobs_suspended += 1; + } + } else { + last_30jobs_suspended -= 1; + } + suspend_first_success = suspend_first && suspend_success; + #[cfg(feature = "prometheus")] + if j.job.is_some() { + if let Some(wp) = worker_pull_duration_counter.as_ref() { + wp.inc_by(duration_pull_s); + } + if let Some(wp) = worker_pull_duration.as_ref() { + wp.observe(duration_pull_s); + } + } else { + if let Some(wp) = worker_pull_duration_counter_empty.as_ref() { + wp.inc_by(duration_pull_s); + } + if let Some(wp) = worker_pull_duration_empty.as_ref() { + wp.observe(duration_pull_s); + } + } + } + job.map(|x| x.job.map(NextJob::Sql)) + } + Connection::Http(client) => crate::agent_workers::pull_job(&client) + .await + .map_err(|e| error::Error::InternalErr(e.to_string())) + .map(|x| x.map(|y| NextJob::Http(y))), } - - let job = pull(&db, suspend_first, &worker_name).await; - - add_time!(bench, "job pulled from DB"); - let duration_pull_s = pull_time.elapsed().as_secs_f64(); - let err_pull = job.is_ok(); - // let empty = job.as_ref().is_ok_and(|x| x.is_none()); - - if !agent_mode && duration_pull_s > 0.5 { - let empty = job.as_ref().is_ok_and(|x| x.0.is_none()); - tracing::warn!(worker = %worker_name, hostname = %hostname, "pull took more than 0.5s ({duration_pull_s}), this is a sign that the database is VERY undersized for this load. empty: {empty}, err: {err_pull}"); - #[cfg(feature = "prometheus")] - if empty { - if let Some(wp) = worker_pull_over_500_counter_empty.as_ref() { - wp.inc(); - } - } else if let Some(wp) = worker_pull_over_500_counter.as_ref() { - wp.inc(); - } - } else if !agent_mode && duration_pull_s > 0.1 { - let empty = job.as_ref().is_ok_and(|x| x.0.is_none()); - tracing::warn!(worker = %worker_name, hostname = %hostname, "pull took more than 0.1s ({duration_pull_s}) this is a sign that the database is undersized for this load. empty: {empty}, err: {err_pull}"); - #[cfg(feature = "prometheus")] - if empty { - if let Some(wp) = worker_pull_over_100_counter_empty.as_ref() { - wp.inc(); - } - } else if let Some(wp) = worker_pull_over_100_counter.as_ref() { - wp.inc(); - } - } - - if let Ok(j) = job.as_ref() { - let suspend_success = j.1; - if suspend_first { - last_30jobs_suspended.push(suspend_success); - if last_30jobs_suspended.len() > 30 { - last_30jobs_suspended.remove(0); - } - } - suspend_first_success = suspend_first && suspend_success; - #[cfg(feature = "prometheus")] - if j.0.is_some() { - if let Some(wp) = worker_pull_duration_counter.as_ref() { - wp.inc_by(duration_pull_s); - } - if let Some(wp) = worker_pull_duration.as_ref() { - wp.observe(duration_pull_s); - } - } else { - if let Some(wp) = worker_pull_duration_counter_empty.as_ref() { - wp.inc_by(duration_pull_s); - } - if let Some(wp) = worker_pull_duration_empty.as_ref() { - wp.observe(duration_pull_s); - } - } - } - job.map(|x| x.0) } }; @@ -1417,7 +1421,8 @@ 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 { + if let Err(e) = dedicated_worker_tx.send(Arc::new(job.job())).await + { tracing::info!("failed to send jobs to dedicated workers. Likely dedicated worker has been shut down. This is normal: {e:?}"); } @@ -1435,8 +1440,8 @@ pub async fn run_worker( if matches!(job.kind, JobKind::Noop) { add_time!(bench, "send job completed START"); job_completed_tx - .send(JobCompleted { - job: Arc::new(job.job), + .send_job(JobCompleted { + job: Arc::new(job.job()), success: true, result: Arc::new(empty_result()), result_columns: None, @@ -1450,7 +1455,7 @@ pub async fn run_worker( .expect("send job completed END"); add_time!(bench, "sent job completed"); } else { - add_outstanding_wait_time(&job, db, OUTSTANDING_WAIT_TIME_THRESHOLD_MS); + add_outstanding_wait_time(&conn, &job, OUTSTANDING_WAIT_TIME_THRESHOLD_MS); #[cfg(feature = "prometheus")] register_metric( @@ -1504,7 +1509,7 @@ pub async fn run_worker( if job.id == Uuid::nil() { tracing::info!("running warmup job"); } else { - tracing::info!(workspace_id = %job.workspace_id, job_id = %job.id, root_id = %job_root, "fetched job {}, root job: {}", job.id, job_root); + tracing::info!(workspace_id = %job.workspace_id, job_id = %job.id, root_id = %job_root, "fetched job {} (root job: {}, scheduled for: {})", job.id, job_root, job.scheduled_for); } // Here we can't remove the job id, but maybe with the // fields macro we can make a job id that only appears when // the job is defined? @@ -1554,46 +1559,23 @@ pub async fn run_worker( let tag = job.tag.clone(); let is_init_script: bool = job.tag.as_str() == INIT_SCRIPT_TAG; - let PulledJob { + let JobAndPerms { job, raw_code, raw_lock, raw_flow, parent_runnable_path, - permissioned_as_email, - permissioned_as_username, - permissioned_as_is_admin, - permissioned_as_is_operator, - permissioned_as_groups, - permissioned_as_folders, - } = job; - let job_perms = match ( - permissioned_as_email, - permissioned_as_username, - permissioned_as_is_admin, - permissioned_as_is_operator, - permissioned_as_groups, - permissioned_as_folders, - ) { - ( - Some(email), - Some(username), - Some(is_admin), - Some(is_operator), - Some(groups), - Some(folders), - ) => Some(JobPerms { - email, - username, - is_admin, - is_operator, - groups, - folders, - }), - _ => None, + token, + precomputed_agent_info: precomputed_bundle, + } = 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::Http(job), _) => job, }; - let token = create_token(&db, &job, job_perms).await; + // let token = create_token(&db, &job, job_perms).await; let authed_client = AuthedClient { base_internal_url: base_internal_url.to_string(), token, @@ -1642,7 +1624,7 @@ pub async fn run_worker( raw_lock, raw_flow, parent_runnable_path, - db, + conn, &authed_client, &hostname, &worker_name, @@ -1653,6 +1635,7 @@ pub async fn run_worker( job_completed_tx.clone(), &mut occupancy_metrics, &mut killpill_rx2, + precomputed_bundle, #[cfg(feature = "benchmark")] &mut bench, ) @@ -1660,26 +1643,50 @@ pub async fn run_worker( .await { Err(err) => { - handle_job_error( - db, - &authed_client, - arc_job.as_ref(), - 0, - None, - err, - false, - same_worker_tx.clone(), - &worker_dir, - &worker_name, - (&job_completed_tx.0).clone(), - #[cfg(feature = "benchmark")] - &mut bench, - ) - .await; + match conn { + Connection::Sql(db) => { + handle_job_error( + db, + &authed_client, + arc_job.as_ref(), + 0, + None, + err, + false, + same_worker_tx.clone(), + &worker_dir, + &worker_name, + job_completed_tx.clone(), + #[cfg(feature = "benchmark")] + &mut bench, + ) + .await; + } + Connection::Http(_) => { + job_completed_tx + .send_job(JobCompleted { + job: arc_job.clone(), + result: Arc::new( + windmill_common::worker::to_raw_value( + &error_to_value(err), + ), + ), + result_columns: None, + mem_peak: 0, + canceled_by: None, + success: false, + cached_res_path: None, + token: authed_client.token.clone(), + duration: None, + }) + .await + .expect("send job completed"); + } + } if is_init_script { tracing::error!("init script job failed (in handler), exiting"); update_worker_ping_for_failed_init_script( - db, + conn, &worker_name, arc_job.id, ) @@ -1689,8 +1696,12 @@ pub async fn run_worker( } Ok(false) if is_init_script => { tracing::error!("init script job failed, exiting"); - update_worker_ping_for_failed_init_script(db, &worker_name, arc_job.id) - .await; + update_worker_ping_for_failed_init_script( + conn, + &worker_name, + arc_job.id, + ) + .await; break; } _ => {} @@ -1795,126 +1806,42 @@ pub async fn run_worker( drop(job_completed_tx); tracing::info!(worker = %worker_name, hostname = %hostname, "waiting for job_completed_processor to finish processing remaining jobs"); - if let Err(e) = send_result.await { - tracing::error!("error in awaiting send_result process: {e:?}") + if let Some(send_result) = send_result { + if let Err(e) = send_result.await { + tracing::error!("error in awaiting send_result process: {e:?}") + } } tracing::info!(worker = %worker_name, hostname = %hostname, "worker {} exited", worker_name); tracing::info!(worker = %worker_name, hostname = %hostname, "number of jobs executed: {}", jobs_executed); } -async fn get_same_worker_job( - db: &Pool, - same_worker_job: &SameWorkerPayload, -) -> windmill_common::error::Result> { - sqlx::query_as::<_, PulledJob>( - "WITH ping AS ( - UPDATE v2_job_runtime SET ping = NOW() WHERE id = $1 - ), - started_at AS ( - UPDATE v2_job_queue SET started_at = NOW() WHERE id = $1 - ) - SELECT - v2_job_queue.workspace_id, - v2_job_queue.id, - v2_job.args, - v2_job.parent_job, - v2_job.created_by, - v2_job_queue.started_at, - scheduled_for, - v2_job.runnable_path, - v2_job.kind, - v2_job.runnable_id, - v2_job_queue.canceled_reason, - v2_job_queue.canceled_by, - v2_job.permissioned_as, - v2_job.permissioned_as_email, - v2_job_status.flow_status, - v2_job.tag, - v2_job.script_lang, - v2_job.same_worker, - v2_job.pre_run_error, - v2_job.concurrent_limit, - v2_job.concurrency_time_window_s, - v2_job.flow_innermost_root_job, - v2_job.timeout, - v2_job.flow_step_id, - v2_job.cache_ttl, - v2_job_queue.priority, - v2_job.preprocessed, - v2_job.script_entrypoint_override, - v2_job.trigger, - v2_job.trigger_kind, - v2_job.visible_to_owner, - v2_job.raw_code, - v2_job.raw_lock, - v2_job.raw_flow, - pj.runnable_path as parent_runnable_path, - p.email as permissioned_as_email, p.username as permissioned_as_username, p.is_admin as permissioned_as_is_admin, - p.is_operator as permissioned_as_is_operator, p.groups as permissioned_as_groups, p.folders as permissioned_as_folders - FROM v2_job_queue - INNER JOIN v2_job ON v2_job.id = v2_job_queue.id - LEFT JOIN v2_job_status ON v2_job_status.id = v2_job_queue.id - LEFT JOIN job_perms p ON p.job_id = v2_job.id - LEFT JOIN v2_job pj ON v2_job.parent_job = pj.id - WHERE v2_job_queue.id = $1 -", - ) - .bind(same_worker_job.job_id) - .fetch_optional(db) - .await - .map_err(|e| { - Error::internal_err(format!( - "Impossible to fetch same_worker job {}: {}", - same_worker_job.job_id, e - )) - }) -} - async fn queue_init_bash_maybe<'c>( - db: &Pool, + conn: &Connection, same_worker_tx: SameWorkerSender, worker_name: &str, -) -> error::Result { - if let Some(content) = WORKER_CONFIG.read().await.init_bash.clone() { - let tx = PushIsolationLevel::IsolatedRoot(db.clone()); - let ehm = HashMap::new(); - let (uuid, inner_tx) = push( - &db, - tx, - "admins", - windmill_common::jobs::JobPayload::Code(windmill_common::jobs::RawCode { - hash: None, - content: content.clone(), - path: Some(format!("init_script_{worker_name}")), - language: ScriptLang::Bash, - lock: None, - custom_concurrency_key: None, - concurrent_limit: None, - concurrency_time_window_s: None, - cache_ttl: None, - dedicated_worker: None, - }), - PushArgs::from(&ehm), - worker_name, - "worker@windmill.dev", - SUPERADMIN_SECRET_EMAIL.to_string(), - None, - None, - None, - None, - None, - false, - true, - None, - true, - Some("init_script".to_string()), - None, - None, - None, - None, - ) - .await?; - inner_tx.commit().await?; +) -> anyhow::Result { + let uuid_content = match conn { + Connection::Sql(db) => { + if let Some(content) = WORKER_CONFIG.read().await.init_bash.clone() { + Some(( + push_init_job(db, content.clone(), worker_name).await?, + content, + )) + } else { + None + } + } + Connection::Http(client) => { + let init_script = std::env::var("INIT_SCRIPT"); + if init_script.is_ok() { + let content = init_script.unwrap(); + Some((queue_init_job(client, &content).await?, content)) + } else { + None + } + } + }; + if let Some((uuid, content)) = uuid_content { same_worker_tx .send(SameWorkerPayload { job_id: uuid, recoverable: false }) .await @@ -1937,20 +1864,6 @@ pub enum SendResult { stop_early_override: Option, token: String, }, - Kill, -} - -#[derive(Debug, Clone)] -pub struct JobCompleted { - pub job: Arc, - pub result: Arc>, - pub result_columns: Option>, - pub mem_peak: i32, - pub success: bool, - pub cached_res_path: Option, - pub token: String, - pub canceled_by: Option, - pub duration: Option, } async fn do_nativets( @@ -1958,13 +1871,13 @@ async fn do_nativets( client: &AuthedClient, env_code: String, code: String, - db: &Pool, + conn: &Connection, mem_peak: &mut i32, canceled_by: &mut Option, worker_name: &str, occupancy_metrics: &mut OccupancyMetrics, ) -> windmill_common::error::Result> { - let args = build_args_map(job, client, db).await?.map(Json); + let args = build_args_map(job, client, conn).await?.map(Json); let job_args = if args.is_some() { args.as_ref() } else { @@ -1976,9 +1889,10 @@ async fn do_nativets( code.clone(), transpile_ts(code)?, job_args, + None, job.id, job.timeout, - db, + conn, mem_peak, canceled_by, worker_name, @@ -2001,7 +1915,7 @@ async fn handle_queued_job( raw_lock: Option, raw_flow: Option>>, parent_runnable_path: Option, - db: &DB, + conn: &Connection, client: &AuthedClient, hostname: &str, worker_name: &str, @@ -2012,6 +1926,7 @@ async fn handle_queued_job( job_completed_tx: JobCompletedSender, occupancy_metrics: &mut OccupancyMetrics, killpill_rx: &mut tokio::sync::broadcast::Receiver<()>, + precomputed_agent_info: Option, #[cfg(feature = "benchmark")] _bench: &mut BenchmarkIter, ) -> windmill_common::error::Result { // Extract the active span from the context @@ -2024,72 +1939,50 @@ async fn handle_queued_job( } #[cfg(any(not(feature = "enterprise"), feature = "sqlx"))] - if job.parent_job.is_none() && job.created_by.starts_with("email-") { - let daily_count = sqlx::query!( + match conn { + Connection::Sql(db) => { + if job.parent_job.is_none() && job.created_by.starts_with("email-") { + let daily_count = sqlx::query!( "SELECT value FROM metrics WHERE id = 'email_trigger_usage' AND created_at > NOW() - INTERVAL '1 day' ORDER BY created_at DESC LIMIT 1" ).fetch_optional(db) .warn_after_seconds(5) .await?.map(|x| serde_json::from_value::(x.value).unwrap_or(1)); - if let Some(count) = daily_count { - if count >= 100 { - return Err(error::Error::QuotaExceeded(format!( - "Email trigger usage limit of 100 per day has been reached." - ))); - } else { - sqlx::query!( + if let Some(count) = daily_count { + if count >= 100 { + return Err(error::Error::QuotaExceeded(format!( + "Email trigger usage limit of 100 per day has been reached." + ))); + } else { + sqlx::query!( "UPDATE metrics SET value = $1 WHERE id = 'email_trigger_usage' AND created_at > NOW() - INTERVAL '1 day'", serde_json::json!(count + 1) ) .execute(db) .warn_after_seconds(5) .await?; - } - } else { - sqlx::query!( + } + } else { + sqlx::query!( "INSERT INTO metrics (id, value) VALUES ('email_trigger_usage', to_jsonb(1))" ) - .execute(db) - .warn_after_seconds(5) - .await?; + .execute(db) + .warn_after_seconds(5) + .await?; + } + } + } + Connection::Http(_) => { + return Err(Error::internal_err(format!( + "Could not check email trigger usage for job with agent worker {}", + job.id + ))) } } - if job.is_flow_step() { - let _ = update_flow_status_in_progress( - db, - &job.workspace_id, - job.parent_job - .ok_or_else(|| Error::internal_err(format!("expected parent job")))?, - job.id, - ) - .warn_after_seconds(5) - .await?; - } else if let Some(parent_job) = job.parent_job { - let _ = sqlx::query_scalar!( - "UPDATE v2_job_status SET - workflow_as_code_status = jsonb_set( - jsonb_set( - COALESCE(workflow_as_code_status, '{}'::jsonb), - array[$1], - COALESCE(workflow_as_code_status->$1, '{}'::jsonb) - ), - array[$1, 'started_at'], - to_jsonb(now()::text) - ) - WHERE id = $2", - &job.id.to_string(), - parent_job - ) - .execute(db) - .warn_after_seconds(5) - .await - .inspect_err(|e| { - tracing::error!( - "Could not update parent job `started_at` in workflow as code status: {}", - e - ) - }); + // no need to mark job as started if http conn, it's done by the server when pulled + if let Connection::Sql(db) = conn { + job.mark_as_started_if_step(db).await?; } let started = Instant::now(); @@ -2106,7 +1999,7 @@ async fn handle_queued_job( x, ) => match x.map(|x| x.0) { None | Some(PREVIEW_IS_CODEBASE_HASH) | Some(PREVIEW_IS_TAR_CODEBASE_HASH) => { - Some(cache::job::fetch_preview(db, &job.id, raw_lock, raw_code, raw_flow).await?) + Some(cache::job::fetch_preview(conn, &job.id, raw_lock, raw_code, raw_flow).await?) } _ => None, }, @@ -2114,65 +2007,78 @@ async fn handle_queued_job( }; let cached_res_path = if job.cache_ttl.is_some() { - Some(cached_result_path(db, &client, &job, preview_data.as_ref()).await) + match conn { + Connection::Sql(db) => { + Some(cached_result_path(db, &client, &job, preview_data.as_ref()).await) + } + Connection::Http(_) => None, + } } else { None }; - if let Some(cached_res_path) = cached_res_path.as_ref() { - let cached_result_maybe = get_cached_resource_value_if_valid( - db, - &client, - &job.id, - &job.workspace_id, - &cached_res_path, - ) - .warn_after_seconds(5) - .await; - if let Some(result) = cached_result_maybe { - { - let logs = - "Job skipped because args & path found in cache and not expired".to_string(); - append_logs(&job.id, &job.workspace_id, logs, db).await; - } - job_completed_tx - .send(JobCompleted { - job, - result, - result_columns: None, - mem_peak: 0, - canceled_by: None, - success: true, - cached_res_path: None, - token: client.token.clone(), - duration: None, - }) - .await - .expect("send job completed"); + if let Some(db) = conn.as_sql() { + if let Some(cached_res_path) = cached_res_path.as_ref() { + let cached_result_maybe = get_cached_resource_value_if_valid( + db, + &client, + &job.id, + &job.workspace_id, + &cached_res_path, + ) + .warn_after_seconds(5) + .await; + if let Some(result) = cached_result_maybe { + { + let logs = "Job skipped because args & path found in cache and not expired" + .to_string(); + append_logs(&job.id, &job.workspace_id, logs, conn).await; + } + job_completed_tx + .send_job(JobCompleted { + job, + result, + result_columns: None, + mem_peak: 0, + canceled_by: None, + success: true, + cached_res_path: None, + token: client.token.clone(), + duration: None, + }) + .await + .expect("send job completed"); - return Ok(true); - } - }; - if job.is_flow() { - let flow_data = match preview_data { - Some(RawData::Flow(data)) => data, - // Not a preview: fetch from the cache or the database. - _ => cache::job::fetch_flow(db, job.kind, job.runnable_id).await?, + return Ok(true); + } }; - handle_flow( - job, - &flow_data, - db, - &client, - None, - same_worker_tx, - worker_dir, - job_completed_tx.0.clone(), - worker_name, - ) - .warn_after_seconds(10) - .await?; - Ok(true) + } + if job.is_flow() { + if let Some(db) = conn.as_sql() { + let flow_data = match preview_data { + Some(RawData::Flow(data)) => data, + // Not a preview: fetch from the cache or the database. + _ => cache::job::fetch_flow(db, job.kind, job.runnable_id).await?, + }; + handle_flow( + job, + &flow_data, + db, + &client, + None, + same_worker_tx, + worker_dir, + job_completed_tx.clone(), + worker_name, + ) + .warn_after_seconds(10) + .await?; + Ok(true) + } else { + return Err(Error::internal_err( + "Could not handle flow job with agent worker".to_string(), + )); + } } else { let mut logs = "".to_string(); let mut mem_peak: i32 = 0; @@ -2208,15 +2114,60 @@ async fn handle_queued_job( "handling job {}", job.id ); - append_logs(&job.id, &job.workspace_id, logs, db).await; + append_logs(&job.id, &job.workspace_id, logs, conn).await; let mut column_order: Option> = None; let mut new_args: Option>> = None; let result = match job.kind { - JobKind::Dependencies => { - handle_dependency_job( + JobKind::Dependencies => match conn { + Connection::Sql(db) => { + handle_dependency_job( + &job, + preview_data.as_ref(), + &mut mem_peak, + &mut canceled_by, + job_dir, + db, + worker_name, + worker_dir, + base_internal_url, + &client.token, + occupancy_metrics, + ) + .await + } + Connection::Http(_) => { + return Err(Error::internal_err( + "Could not handle dependency job with agent worker".to_string(), + )); + } + }, + JobKind::FlowDependencies => match conn { + Connection::Sql(db) => { + handle_flow_dependency_job( + &job, + preview_data.as_ref(), + &mut mem_peak, + &mut canceled_by, + job_dir, + db, + worker_name, + worker_dir, + base_internal_url, + &client.token, + occupancy_metrics, + ) + .await + } + Connection::Http(_) => { + return Err(Error::internal_err( + "Could not handle flow dependency job with agent worker".to_string(), + )); + } + }, + JobKind::AppDependencies => match conn { + Connection::Sql(db) => handle_app_dependency_job( &job, - preview_data.as_ref(), &mut mem_peak, &mut canceled_by, job_dir, @@ -2228,37 +2179,13 @@ async fn handle_queued_job( occupancy_metrics, ) .await - } - JobKind::FlowDependencies => { - handle_flow_dependency_job( - &job, - preview_data.as_ref(), - &mut mem_peak, - &mut canceled_by, - job_dir, - db, - worker_name, - worker_dir, - base_internal_url, - &client.token, - occupancy_metrics, - ) - .await - } - JobKind::AppDependencies => handle_app_dependency_job( - &job, - &mut mem_peak, - &mut canceled_by, - job_dir, - db, - worker_name, - worker_dir, - base_internal_url, - &client.token, - occupancy_metrics, - ) - .await - .map(|()| serde_json::from_str("{}").unwrap()), + .map(|()| serde_json::from_str("{}").unwrap()), + Connection::Http(_) => { + return Err(Error::internal_err( + "Could not handle app dependency job with agent worker".to_string(), + )); + } + }, JobKind::Identity => Ok(job .args .as_ref() @@ -2275,7 +2202,7 @@ async fn handle_queued_job( let r = handle_code_execution_job( job.as_ref(), preview_data, - db, + conn, client, parent_runnable_path, job_dir, @@ -2288,6 +2215,7 @@ async fn handle_queued_job( &mut new_args, occupancy_metrics, killpill_rx, + precomputed_agent_info, ) .await; occupancy_metrics.total_duration_of_running_jobs += @@ -2319,7 +2247,7 @@ async fn handle_queued_job( &client.token, column_order, new_args, - db, + conn, Some(started.elapsed().as_millis() as i64), ) .await @@ -2384,9 +2312,9 @@ pub async fn get_hub_script_content_and_requirements( pub async fn get_script_content_by_hash( script_hash: &ScriptHash, _w_id: &str, - db: &DB, + conn: &Connection, ) -> error::Result { - let (data, metadata) = cache::script::fetch(db, *script_hash).await?; + let (data, metadata) = cache::script::fetch(conn, *script_hash).await?; Ok(ContentReqLangEnvs { content: data.code.clone(), lockfile: data.lock.clone(), @@ -2403,7 +2331,7 @@ pub async fn get_script_content_by_hash( async fn try_validate_schema( job: &MiniPulledJob, - db: &Pool, + conn: &Connection, schema_validator: Option<&SchemaValidator>, code: &str, language: Option<&ScriptLang>, @@ -2464,7 +2392,7 @@ async fn try_validate_schema( &job.id, &job.workspace_id, "\n--- ARGS VALIDATION ---\nScript contains `schema_validation` annotation, running schema validation for the script arguments...\n", - db, + conn, ) .await; } @@ -2479,7 +2407,7 @@ async fn try_validate_schema( &job.id, &job.workspace_id, "Script arguments were validated!\n\n", - db, + conn, ) .await; } @@ -2493,7 +2421,7 @@ async fn try_validate_schema( async fn handle_code_execution_job( job: &MiniPulledJob, preview: Option>, - db: &sqlx::Pool, + conn: &Connection, client: &AuthedClient, parent_runnable_path: Option, job_dir: &str, @@ -2506,6 +2434,7 @@ async fn handle_code_execution_job( new_args: &mut Option>>, occupancy_metrics: &mut OccupancyMetrics, killpill_rx: &mut tokio::sync::broadcast::Receiver<()>, + precomputed_agent_info: Option, ) -> error::Result> { let script_hash = || { job.runnable_id @@ -2541,7 +2470,7 @@ async fn handle_code_execution_job( } JobKind::Script_Hub => { let ContentReqLangEnvs { content, lockfile, language, envs, codebase, schema } = - get_hub_script_content_and_requirements(job.runnable_path.as_ref(), Some(db)) + get_hub_script_content_and_requirements(job.runnable_path.as_ref(), conn.as_sql()) .await?; data = ScriptData { code: content, lock: lockfile }; @@ -2549,11 +2478,11 @@ async fn handle_code_execution_job( (&data, &metadata) } JobKind::Script => { - (arc_data, arc_metadata) = cache::script::fetch(db, script_hash()?).await?; + (arc_data, arc_metadata) = cache::script::fetch(conn, script_hash()?).await?; (arc_data.as_ref(), arc_metadata.as_ref()) } JobKind::FlowScript => { - arc_data = cache::flow::fetch_script(db, FlowNodeId(script_hash()?.0)).await?; + arc_data = cache::flow::fetch_script(conn, FlowNodeId(script_hash()?.0)).await?; metadata = ScriptMetadata { language: job.script_lang, envs: None, @@ -2564,7 +2493,7 @@ async fn handle_code_execution_job( (arc_data.as_ref(), &metadata) } JobKind::AppScript => { - arc_data = cache::app::fetch_script(db, AppScriptId(script_hash()?.0)).await?; + arc_data = cache::app::fetch_script(conn, AppScriptId(script_hash()?.0)).await?; metadata = ScriptMetadata { language: job.script_lang, envs: None, @@ -2574,33 +2503,41 @@ async fn handle_code_execution_job( }; (arc_data.as_ref(), &metadata) } - JobKind::DeploymentCallback => { - let script_path = job - .runnable_path - .as_ref() - .ok_or_else(|| Error::internal_err("expected script path".to_string()))?; - if script_path.starts_with("hub/") { - let ContentReqLangEnvs { content, lockfile, language, envs, codebase, schema } = - get_hub_script_content_and_requirements(Some(script_path), Some(db)).await?; - data = ScriptData { code: content, lock: lockfile }; - metadata = - ScriptMetadata { language, envs, codebase, schema, schema_validator: None }; - (&data, &metadata) - } else { - let hash = sqlx::query_scalar!( - "SELECT hash FROM script WHERE path = $1 AND workspace_id = $2 AND + JobKind::DeploymentCallback => match conn { + Connection::Sql(db) => { + let script_path = job + .runnable_path + .as_ref() + .ok_or_else(|| Error::internal_err("expected script path".to_string()))?; + if script_path.starts_with("hub/") { + let ContentReqLangEnvs { content, lockfile, language, envs, codebase, schema } = + get_hub_script_content_and_requirements(Some(script_path), conn.as_sql()) + .await?; + data = ScriptData { code: content, lock: lockfile }; + metadata = + ScriptMetadata { language, envs, codebase, schema, schema_validator: None }; + (&data, &metadata) + } else { + let hash = sqlx::query_scalar!( + "SELECT hash FROM script WHERE path = $1 AND workspace_id = $2 AND deleted = false AND lock IS not NULL AND lock_error_logs IS NULL", - script_path, - &job.workspace_id - ) - .fetch_optional(db) - .await? - .ok_or_else(|| Error::internal_err("expected script hash".to_string()))?; + script_path, + &job.workspace_id + ) + .fetch_optional(db) + .await? + .ok_or_else(|| Error::internal_err("expected script hash".to_string()))?; - (arc_data, arc_metadata) = cache::script::fetch(db, ScriptHash(hash)).await?; - (arc_data.as_ref(), arc_metadata.as_ref()) + (arc_data, arc_metadata) = cache::script::fetch(conn, ScriptHash(hash)).await?; + (arc_data.as_ref(), arc_metadata.as_ref()) + } } - } + Connection::Http(_) => { + return Err(Error::internal_err( + "Could not handle deployment callback with agent worker".to_string(), + )); + } + }, _ => unreachable!( "handle_code_execution_job should never be reachable with a non-code execution job" ), @@ -2608,7 +2545,7 @@ async fn handle_code_execution_job( try_validate_schema( job, - db, + conn, schema_validator.as_ref(), code, language.as_ref(), @@ -2622,7 +2559,7 @@ async fn handle_code_execution_job( job, &client, &code, - db, + conn, mem_peak, canceled_by, worker_name, @@ -2641,7 +2578,7 @@ async fn handle_code_execution_job( job, &client, &code, - db, + conn, mem_peak, canceled_by, worker_name, @@ -2671,7 +2608,7 @@ async fn handle_code_execution_job( job, &client, &code, - db, + conn, mem_peak, canceled_by, worker_name, @@ -2694,7 +2631,7 @@ async fn handle_code_execution_job( job, &client, &code, - db, + conn, mem_peak, canceled_by, worker_name, @@ -2725,11 +2662,12 @@ async fn handle_code_execution_job( job, &client, &code, - db, + conn, mem_peak, canceled_by, worker_name, occupancy_metrics, + job_dir, ) .await; } @@ -2755,7 +2693,7 @@ async fn handle_code_execution_job( job, &client, &code, - db, + conn, mem_peak, canceled_by, worker_name, @@ -2769,7 +2707,7 @@ async fn handle_code_execution_job( job, &client, &code, - db, + conn, mem_peak, canceled_by, worker_name, @@ -2781,12 +2719,12 @@ async fn handle_code_execution_job( &job.id, &job.workspace_id, "\n--- FETCH TS EXECUTION ---\n", - db, + conn, ) .await; let reserved_variables = - get_reserved_variables(job, &client.token, db, parent_runnable_path).await?; + get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?; let env_code = format!( "const process = {{ env: {{}} }};\nconst BASE_URL = '{base_internal_url}';\nconst BASE_INTERNAL_URL = '{base_internal_url}';\nprocess.env['BASE_URL'] = BASE_URL;process.env['BASE_INTERNAL_URL'] = BASE_INTERNAL_URL;\n{}", @@ -2801,7 +2739,7 @@ async fn handle_code_execution_job( &client, env_code, code.clone(), - db, + conn, mem_peak, canceled_by, worker_name, @@ -2869,7 +2807,7 @@ mount {{ job, mem_peak, canceled_by, - db, + conn, client, parent_runnable_path, &code, @@ -2878,6 +2816,7 @@ mount {{ envs, new_args, occupancy_metrics, + precomputed_agent_info, ) .await } @@ -2887,7 +2826,7 @@ mount {{ mem_peak, canceled_by, job, - db, + conn, client, parent_runnable_path, job_dir, @@ -2907,7 +2846,7 @@ mount {{ mem_peak, canceled_by, job, - db, + conn, client, parent_runnable_path, job_dir, @@ -2918,6 +2857,7 @@ mount {{ &shared_mount, new_args, occupancy_metrics, + precomputed_agent_info, ) .await } @@ -2926,7 +2866,7 @@ mount {{ mem_peak, canceled_by, job, - db, + conn, client, parent_runnable_path, &code, @@ -2945,7 +2885,7 @@ mount {{ mem_peak, canceled_by, job, - db, + conn, client, parent_runnable_path, &code, @@ -2964,7 +2904,7 @@ mount {{ mem_peak, canceled_by, job, - db, + conn, client, parent_runnable_path, &code, @@ -2989,7 +2929,7 @@ mount {{ mem_peak, canceled_by, job, - db, + conn, client, parent_runnable_path, job_dir, @@ -3013,7 +2953,7 @@ mount {{ mem_peak, canceled_by, job, - db, + conn, client, parent_runnable_path, &code, @@ -3042,7 +2982,7 @@ mount {{ job, mem_peak, canceled_by, - db, + conn, client, parent_runnable_path, &code, @@ -3058,7 +2998,7 @@ mount {{ mem_peak, canceled_by, job, - db, + conn, client, parent_runnable_path, &code, @@ -3079,11 +3019,37 @@ mount {{ ); #[cfg(feature = "nu")] - handle_nu_job(JobHandlerInput { + handle_nu_job(JobHandlerInputNu { mem_peak, canceled_by, job, - db, + conn, + client, + parent_runnable_path, + inner_content: &code, + job_dir, + requirements_o: lock.as_ref(), + shared_mount: &shared_mount, + base_internal_url, + worker_name, + envs, + occupancy_metrics, + }) + .await + } + Some(ScriptLang::Java) => { + #[cfg(not(feature = "java"))] + return Err(anyhow::anyhow!( + "Java is not available because the feature is not enabled" + ) + .into()); + + #[cfg(feature = "java")] + handle_java_job(JobHandlerInputJava { + mem_peak, + canceled_by, + job, + conn, client, parent_runnable_path, inner_content: &code, @@ -3164,6 +3130,11 @@ fn parse_sig_of_lang( ScriptLang::Nu => Some(windmill_parser_nu::parse_nu_signature(code)?), #[cfg(not(feature = "nu"))] ScriptLang::Nu => None, + #[cfg(feature = "java")] + ScriptLang::Java => Some(windmill_parser_java::parse_java_signature(code)?), + #[cfg(not(feature = "java"))] + ScriptLang::Java => None, + // for related places search: ADD_NEW_LANG } } else { None diff --git a/backend/windmill-worker/src/worker_flow.rs b/backend/windmill-worker/src/worker_flow.rs index d8c9a0a410..63cf414c53 100644 --- a/backend/windmill-worker/src/worker_flow.rs +++ b/backend/windmill-worker/src/worker_flow.rs @@ -11,13 +11,10 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::time::Duration; -#[cfg(feature = "benchmark")] -use crate::bench::BenchmarkIter; use crate::common::{cached_result_path, save_in_cache}; use crate::js_eval::{eval_timeout, IdContext}; use crate::{ - AuthedClient, PreviousResult, SameWorkerPayload, SameWorkerSender, SendResult, JOB_TOKEN, - KEEP_JOB_DIR, + AuthedClient, JobCompletedSender, PreviousResult, SameWorkerSender, SendResult, KEEP_JOB_DIR, }; use anyhow::Context; use futures::TryFutureExt; @@ -27,11 +24,12 @@ use serde_json::value::RawValue; use serde_json::{json, Value}; use sqlx::types::Json; use sqlx::{FromRow, Postgres, Transaction}; -use tokio::sync::mpsc::Sender; use tracing::instrument; use uuid::Uuid; use windmill_common::add_time; use windmill_common::auth::JobPerms; +#[cfg(feature = "benchmark")] +use windmill_common::bench::BenchmarkIter; use windmill_common::cache::{self, RawData}; use windmill_common::db::Authed; use windmill_common::flow_status::{ @@ -54,11 +52,12 @@ use windmill_common::{ }, flows::{FlowModule, FlowModuleValue, FlowValue, InputTransform, Retry, Suspend}, }; +use windmill_queue::flow_status::Step; 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, CanceledBy, MiniPulledJob, PushArgs, PushIsolationLevel, - WrappedError, + SameWorkerPayload, WrappedError, }; type DB = sqlx::Pool; @@ -81,7 +80,7 @@ pub async fn update_flow_status_after_job_completion( worker_dir: &str, stop_early_override: Option, worker_name: &str, - job_completed_tx: Sender, + job_completed_tx: JobCompletedSender, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> error::Result>> { // this is manual tailrecursion because async_recursion blows up the stack @@ -200,7 +199,7 @@ pub async fn update_flow_status_after_job_completion_internal( stop_early_override: Option, skip_error_handler: bool, worker_name: &str, - job_completed_tx: Sender, + job_completed_tx: JobCompletedSender, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> error::Result { add_time!(bench, "update flow status internal START"); @@ -1050,7 +1049,7 @@ pub async fn update_flow_status_after_job_completion_internal( } else { "Flow job completed with error\n".to_string() }; - append_logs(&flow_job.id, w_id, logs, db).await; + append_logs(&flow_job.id, w_id, logs, &db.into()).await; } #[cfg(feature = "enterprise")] if flow_job.parent_job.is_none() { @@ -1168,7 +1167,7 @@ pub async fn update_flow_status_after_job_completion_internal( &flow_job.id, w_id, format!("Unexpected error during flow chaining:\n{:#?}", e), - db, + &db.into(), ) .await; let _ = add_completed_job_error(db, &flow_job, 0, None, e, worker_name, true, None) @@ -1388,102 +1387,6 @@ async fn compute_bool_from_expr( } } -pub async fn update_flow_status_in_progress( - db: &DB, - _w_id: &str, - flow: Uuid, - job_in_progress: Uuid, -) -> error::Result { - let step = get_step_of_flow_status(db, flow).await?; - match step { - Step::Step(step) => { - sqlx::query!( - "UPDATE v2_job_status SET - flow_status = jsonb_set( - jsonb_set(flow_status, ARRAY['modules', $3::INTEGER::TEXT, 'job'], to_jsonb($1::UUID::TEXT)), - ARRAY['modules', $3::INTEGER::TEXT, 'type'], - to_jsonb('InProgress'::text) - ) - WHERE id = $2", - job_in_progress, - flow, - step as i32 - ) - .execute(db) - .await?; - } - Step::PreprocessorStep => { - sqlx::query!( - "UPDATE v2_job_status SET - flow_status = jsonb_set( - jsonb_set(flow_status, ARRAY['preprocessor_module', 'job'], to_jsonb($1::UUID::TEXT)), - ARRAY['preprocessor_module', 'type'], - to_jsonb('InProgress'::text) - ) - WHERE id = $2", - job_in_progress, - flow - ) - .execute(db) - .await?; - } - Step::FailureStep => { - sqlx::query!( - "UPDATE v2_job_status SET - flow_status = jsonb_set( - jsonb_set(flow_status, ARRAY['failure_module', 'job'], to_jsonb($1::UUID::TEXT)), - ARRAY['failure_module', 'type'], - to_jsonb('InProgress'::text) - ) - WHERE id = $2", - job_in_progress, - flow - ) - .execute(db) - .await?; - } - } - - Ok(step) -} - -#[derive(Debug, Copy, Clone)] -pub enum Step { - Step(usize), - PreprocessorStep, - FailureStep, -} - -impl Step { - fn from_i32_and_len(step: i32, len: usize) -> Self { - if step < 0 { - Step::PreprocessorStep - } else if (step as usize) < len { - Step::Step(step as usize) - } else { - Step::FailureStep - } - } -} - -#[instrument(level = "trace", skip_all)] -pub async fn get_step_of_flow_status(db: &DB, id: Uuid) -> error::Result { - let r = sqlx::query!( - "SELECT (flow_status->'step')::integer as step, jsonb_array_length(flow_status->'modules') as len - FROM v2_job_status WHERE id = $1", - id - ) - .fetch_one(db) - .await - .map_err(|e| Error::internal_err(format!("fetching step flow status: {e:#}")))?; - - if let Some(step) = r.step { - Ok(Step::from_i32_and_len(step, r.len.unwrap_or(0) as usize)) - } else { - Err(Error::internal_err("step is null".to_string())) - } -} - /// resumes should be in order of timestamp ascending, so that more recent are at the end #[instrument(level = "trace", skip_all)] async fn transform_input( @@ -1548,7 +1451,7 @@ pub async fn handle_flow( last_result: Option>>, same_worker_tx: SameWorkerSender, worker_dir: &str, - job_completed_tx: Sender, + job_completed_tx: JobCompletedSender, worker_name: &str, ) -> anyhow::Result<()> { let flow = flow_data.value(); @@ -1669,7 +1572,7 @@ async fn push_next_flow_job( last_job_result: Option>>, same_worker_tx: SameWorkerSender, worker_dir: &str, - job_completed_tx: Sender, + job_completed_tx: JobCompletedSender, worker_name: &str, ) -> error::Result> { let job_root = flow_job @@ -2105,7 +2008,13 @@ async fn push_next_flow_job( let result: Value = json!({ "error": {"message": logs, "name": error_name}}); - append_logs(&flow_job.id, &flow_job.workspace_id, logs.clone(), db).await; + append_logs( + &flow_job.id, + &flow_job.workspace_id, + logs.clone(), + &db.into(), + ) + .await; job_completed_tx .send(SendResult::UpdateFlow { @@ -2644,7 +2553,7 @@ async fn push_next_flow_job( }; // forward root job permissions to the new job - let job_perms: Option = if JOB_TOKEN.is_none() { + let job_perms: Option = { if let Some(root_job) = &flow_job .flow_innermost_root_job .or_else(|| Some(flow_job.id)) @@ -2661,8 +2570,6 @@ async fn push_next_flow_job( } else { None } - } else { - None }; tracing::debug!(id = %flow_job.id, root_id = %job_root, "computed perms for job {i} of {len}"); diff --git a/backend/windmill-worker/src/worker_lockfiles.rs b/backend/windmill-worker/src/worker_lockfiles.rs index 113d1714d2..6c56f1acef 100644 --- a/backend/windmill-worker/src/worker_lockfiles.rs +++ b/backend/windmill-worker/src/worker_lockfiles.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::collections::HashMap; +use std::fs::{create_dir_all, remove_dir_all}; use std::path::{Component, Path, PathBuf}; use async_recursion::async_recursion; @@ -16,7 +17,7 @@ use windmill_common::jobs::JobPayload; use windmill_common::scripts::ScriptHash; #[cfg(feature = "python")] use windmill_common::worker::PythonAnnotations; -use windmill_common::worker::{to_raw_value, to_raw_value_owned, write_file}; +use windmill_common::worker::{to_raw_value, to_raw_value_owned, write_file, Connection}; use windmill_common::{ apps::AppScriptId, @@ -35,6 +36,9 @@ use windmill_queue::{append_logs, CanceledBy, MiniPulledJob, PushIsolationLevel} use crate::common::OccupancyMetrics; use crate::csharp_executor::generate_nuget_lockfile; +#[cfg(feature = "java")] +use crate::java_executor::resolve; + #[cfg(feature = "php")] use crate::php_executor::{composer_install, parse_php_imports}; #[cfg(feature = "python")] @@ -79,7 +83,7 @@ pub async fn update_script_dependency_map( ) .await?; tx.commit().await?; - append_logs(job_id, w_id, logs, db).await; + append_logs(job_id, w_id, logs, &db.into()).await; } Ok(()) } @@ -222,7 +226,7 @@ pub async fn handle_dependency_job( mem_peak: &mut i32, canceled_by: &mut Option, job_dir: &str, - db: &sqlx::Pool, + db: &DB, worker_name: &str, worker_dir: &str, base_internal_url: &str, @@ -261,7 +265,7 @@ pub async fn handle_dependency_job( // - A saved script `hash` in the `script_hash` column. // - Preview raw lock and code in the `queue` or `job` table. let script_data = &match job.runnable_id { - Some(hash) => match cache::script::fetch(db, hash).await { + Some(hash) => match cache::script::fetch(&Connection::from(db.clone()), hash).await { Ok(d) => Cow::Owned(d.0), Err(e) => { let logs2 = sqlx::query_scalar!( @@ -281,7 +285,9 @@ pub async fn handle_dependency_job( ) .execute(db) .await?; - return Err(Error::ExecutionErr(format!("Error creating schema validator: {e}"))) + return Err(Error::ExecutionErr(format!( + "Error creating schema validator: {e}" + ))); } }, _ => match preview_data { @@ -1056,6 +1062,12 @@ async fn lock_modules<'c>( modified_ids.push(e.id.clone()); + remove_dir_all(job_dir).map_err(|e| { + Error::ExecutionErr(format!("Error removing job dir for flow step lock: {e}")) + })?; + create_dir_all(job_dir).map_err(|e| { + Error::ExecutionErr(format!("Error creating job dir for flow step lock: {e}")) + })?; let new_lock = capture_dependency_job( &job.id, &language, @@ -1109,7 +1121,7 @@ async fn lock_modules<'c>( Some(e.id.clone()), ) .await?; - append_logs(&job.id, &job.workspace_id, logs, db).await; + append_logs(&job.id, &job.workspace_id, logs, &db.into()).await; } if language == ScriptLang::Bun || language == ScriptLang::Bunnative { @@ -1501,7 +1513,7 @@ async fn lock_modules_app( .await; match new_lock { Ok(new_lock) => { - append_logs(&job.id, &job.workspace_id, logs, db).await; + append_logs(&job.id, &job.workspace_id, logs, &db.into()).await; let anns = windmill_common::worker::TypeScriptAnnotations::parse( &content, @@ -1749,7 +1761,7 @@ async fn python_dep( let final_version = annotated_pyv_numeric .and_then(|pyv| PyVersion::from_numeric(pyv)) - .unwrap_or(PyVersion::from_instance_version(job_id, w_id, db).await); + .unwrap_or(PyVersion::from_instance_version(job_id, w_id, &db.into()).await); let req: std::result::Result = uv_pip_compile( job_id, @@ -1757,7 +1769,7 @@ async fn python_dep( mem_peak, canceled_by, job_dir, - db, + &db.into(), worker_name, w_id, occupancy_metrics, @@ -1773,7 +1785,7 @@ async fn python_dep( w_id, mem_peak, canceled_by, - db, + &Connection::Sql(db.clone()), worker_name, job_dir, worker_dir, @@ -1841,6 +1853,7 @@ async fn capture_dependency_job( &mut annotated_pyv_numeric, ) .await? + .0 .join("\n") }; @@ -1906,7 +1919,7 @@ async fn capture_dependency_job( mem_peak, canceled_by, job_dir, - db, + &db.into(), false, false, false, @@ -1928,7 +1941,7 @@ async fn capture_dependency_job( mem_peak, canceled_by, job_dir, - Some(db), + Some(&db.into()), w_id, worker_name, base_internal_url, @@ -1948,7 +1961,7 @@ async fn capture_dependency_job( canceled_by, job_id, w_id, - Some(db), + Some(&db.into()), token, script_path, job_dir, @@ -1971,7 +1984,7 @@ async fn capture_dependency_job( script_path, job_id, w_id, - Some(db.clone()), + Some(&db), &job_dir, base_internal_url, worker_name, @@ -2008,7 +2021,7 @@ async fn capture_dependency_job( canceled_by, job_id, w_id, - db, + &Connection::Sql(db.clone()), job_dir, worker_name, reqs, @@ -2037,7 +2050,7 @@ async fn capture_dependency_job( mem_peak, canceled_by, job_dir, - db, + &Connection::Sql(db.clone()), worker_name, w_id, occupancy_metrics, @@ -2060,23 +2073,31 @@ async fn capture_dependency_job( mem_peak, canceled_by, job_dir, - db, + &Connection::Sql(db.clone()), worker_name, w_id, occupancy_metrics, ) .await } - ScriptLang::Postgresql => Ok("".to_owned()), - ScriptLang::Mysql => Ok("".to_owned()), - ScriptLang::Bigquery => Ok("".to_owned()), - ScriptLang::Snowflake => Ok("".to_owned()), - ScriptLang::Mssql => Ok("".to_owned()), - ScriptLang::Graphql => Ok("".to_owned()), - ScriptLang::OracleDB => Ok("".to_owned()), - ScriptLang::Bash => Ok("".to_owned()), - ScriptLang::Nu => Ok("".to_owned()), - ScriptLang::Powershell => Ok("".to_owned()), - ScriptLang::Nativets => Ok("".to_owned()), + #[cfg(feature = "java")] + ScriptLang::Java => { + if raw_deps { + return Err(Error::ExecutionErr( + "Raw dependencies not supported for Java".to_string(), + )); + } + + resolve( + job_id, + job_raw_code, + job_dir, + &Connection::Sql(db.clone()), + w_id, + ) + .await + } + // for related places search: ADD_NEW_LANG + _ => Ok("".to_owned()), } } diff --git a/backend/windmill-worker/src/worker_utils.rs b/backend/windmill-worker/src/worker_utils.rs new file mode 100644 index 0000000000..4c83448236 --- /dev/null +++ b/backend/windmill-worker/src/worker_utils.rs @@ -0,0 +1,322 @@ +use backon::{BackoffBuilder, ConstantBuilder, Retryable}; +use tracing::Instrument; +use uuid::Uuid; +use windmill_common::{ + agent_workers::{PingJobStatus, PingJobStatusResponse}, + worker::{ + get_memory, get_vcpus, get_windmill_memory_usage, get_worker_memory_usage, + insert_ping_query, update_job_ping_query, update_worker_ping_from_job_query, + update_worker_ping_main_loop_query, Connection, Ping, PingType, WORKER_CONFIG, + WORKER_GROUP, + }, + KillpillSender, +}; + +use crate::{ + agent_workers::UPDATE_PING_URL, + common::{OccupancyMetrics, OccupancyResult}, +}; + +pub(crate) async fn update_worker_ping_full( + conn: &Connection, + read_cgroups: bool, + jobs_executed: i32, + worker_name: &str, + hostname: &str, + occupancy_metrics: &mut OccupancyMetrics, + killpill_tx: &KillpillSender, +) { + let tags = WORKER_CONFIG.read().await.worker_tags.clone(); + + let memory_usage = get_worker_memory_usage(); + let wm_memory_usage = get_windmill_memory_usage(); + + let (vcpus, memory) = if read_cgroups { + (get_vcpus(), get_memory()) + } else { + (None, None) + }; + + let OccupancyResult { + occupancy_rate, + occupancy_rate_15s, + occupancy_rate_5m, + occupancy_rate_30m, + } = occupancy_metrics.update_occupancy_metrics(); + + if let Err(e) = (|| { + update_worker_ping_full_inner( + conn, + jobs_executed, + &worker_name, + &tags, + memory_usage, + wm_memory_usage, + vcpus, + memory, + occupancy_rate, + occupancy_rate_15s, + occupancy_rate_5m, + occupancy_rate_30m, + ) + }) + .retry( + ConstantBuilder::default() + .with_delay(std::time::Duration::from_secs(2)) + .with_max_times(10) + .build(), + ) + .notify(|err, dur| { + tracing::error!( + worker = %worker_name, hostname = %hostname, + "retrying updating worker ping in {dur:#?}, err: {err:#?}" + ); + }) + .sleep(tokio::time::sleep) + .await + { + tracing::error!( + worker = %worker_name, hostname = %hostname, + "failed to update worker ping, exiting: {}", e); + killpill_tx.send(); + } + tracing::info!( + worker = %worker_name, hostname = %hostname, + "ping update, memory: container={}MB, windmill={}MB", + memory_usage.unwrap_or_default() / (1024 * 1024), + wm_memory_usage.unwrap_or_default() / (1024 * 1024) + ); +} + +async fn update_worker_ping_full_inner( + conn: &Connection, + jobs_executed: i32, + worker_name: &str, + tags: &[String], + memory_usage: Option, + wm_memory_usage: Option, + vcpus: Option, + memory: Option, + occupancy_rate: f32, + occupancy_rate_15s: Option, + occupancy_rate_5m: Option, + occupancy_rate_30m: Option, +) -> anyhow::Result<()> { + match conn { + Connection::Sql(db) => { + update_worker_ping_main_loop_query( + worker_name, + tags, + vcpus, + memory, + Some(jobs_executed), + Some(occupancy_rate), + memory_usage, + wm_memory_usage, + occupancy_rate_15s, + occupancy_rate_5m, + occupancy_rate_30m, + db, + ) + .await?; + } + Connection::Http(client) => { + client + .post::<_, ()>( + UPDATE_PING_URL, + &Ping { + last_job_executed: None, + last_job_workspace_id: None, + worker_instance: None, + ip: None, + tags: Some(tags.to_vec()), + dw: None, + jobs_executed: Some(jobs_executed), + occupancy_rate: Some(occupancy_rate), + occupancy_rate_15s: Some(occupancy_rate_15s.unwrap_or(0.0)), + occupancy_rate_5m: Some(occupancy_rate_5m.unwrap_or(0.0)), + occupancy_rate_30m: Some(occupancy_rate_30m.unwrap_or(0.0)), + version: None, + vcpus: vcpus, + memory: memory, + memory_usage: get_worker_memory_usage(), + wm_memory_usage: get_windmill_memory_usage(), + ping_type: PingType::MainLoop, + }, + ) + .await?; + } + } + Ok(()) +} + +pub async fn insert_ping( + worker_instance: &str, + worker_name: &str, + ip: &str, + db: &Connection, +) -> anyhow::Result<()> { + let (tags, dw) = { + let wc = WORKER_CONFIG.read().await.clone(); + ( + wc.worker_tags, + wc.dedicated_worker + .as_ref() + .map(|x| format!("{}:{}", x.workspace_id, x.path)), + ) + }; + + let vcpus = get_vcpus(); + let memory = get_memory(); + + match db { + Connection::Sql(db) => { + insert_ping_query( + worker_instance, + worker_name, + WORKER_GROUP.as_str(), + ip, + tags.as_slice(), + dw, + windmill_common::utils::GIT_VERSION, + vcpus, + memory, + db, + ) + .await?; + } + Connection::Http(client) => { + client + .post::<_, ()>( + UPDATE_PING_URL, + &Ping { + last_job_executed: None, + last_job_workspace_id: None, + worker_instance: Some(worker_instance.to_string()), + ip: Some(ip.to_string()), + tags: Some(tags.to_vec()), + dw: dw, + jobs_executed: None, + occupancy_rate: None, + occupancy_rate_15s: None, + occupancy_rate_5m: None, + occupancy_rate_30m: None, + version: Some(windmill_common::utils::GIT_VERSION.to_string()), + vcpus: vcpus, + memory: memory, + memory_usage: get_worker_memory_usage(), + wm_memory_usage: get_windmill_memory_usage(), + ping_type: PingType::Initial, + }, + ) + .await?; + } + } + Ok(()) +} + +pub async fn update_worker_ping_from_job( + conn: &Connection, + job_id: &Uuid, + w_id: &str, + worker_name: &str, + memory_usage: Option, + wm_memory_usage: Option, + occupancy: Option, +) -> anyhow::Result<()> { + let occupancy_rate = occupancy.as_ref().map(|x| x.occupancy_rate); + let occupancy_rate_15s = occupancy.as_ref().and_then(|x| x.occupancy_rate_15s); + let occupancy_rate_5m = occupancy.as_ref().and_then(|x| x.occupancy_rate_5m); + let occupancy_rate_30m = occupancy.as_ref().and_then(|x| x.occupancy_rate_30m); + match conn.clone() { + Connection::Sql(ref db) => { + update_worker_ping_from_job_query( + job_id, + w_id, + worker_name, + memory_usage, + wm_memory_usage, + occupancy_rate, + occupancy_rate_15s, + occupancy_rate_5m, + occupancy_rate_30m, + db, + ) + .await?; + } + Connection::Http(client) => { + client + .post::( + UPDATE_PING_URL, + &Ping { + last_job_executed: Some(job_id.clone()), + last_job_workspace_id: Some(w_id.to_string()), + ping_type: PingType::Job, + worker_instance: None, + ip: None, + tags: None, + dw: None, + version: None, + vcpus: None, + memory: None, + memory_usage: memory_usage, + wm_memory_usage: wm_memory_usage, + jobs_executed: None, + occupancy_rate: occupancy_rate, + occupancy_rate_15s: occupancy_rate_15s, + occupancy_rate_5m: occupancy_rate_5m, + occupancy_rate_30m: occupancy_rate_30m, + }, + ) + .await?; + } + } + Ok(()) +} + +pub async fn ping_job_status( + conn: &Connection, + job_id: &Uuid, + mem_peak: Option, + current_mem: Option, +) -> anyhow::Result { + match conn { + Connection::Sql(ref db) => update_job_ping_query(job_id, db, mem_peak).await, + Connection::Http(client) => { + client + .post( + &format!("/api/agent_workers/ping_job_status/{}", job_id), + &PingJobStatus { mem_peak, current_mem }, + ) + .await + } + } +} + +pub(crate) async fn queue_vacuum(conn: &Connection, worker_name: &str, hostname: &str) { + match conn { + Connection::Sql(db) => { + let db2 = db.clone(); + let current_span = tracing::Span::current(); + let worker_name = worker_name.to_string(); + let hostname = hostname.to_string(); + tokio::task::spawn( + (async move { + tracing::info!(worker = %worker_name, hostname = %hostname, "vacuuming queue"); + if let Err(e) = sqlx::query!("VACUUM v2_job_queue, v2_job_runtime, v2_job_status") + .execute(&db2) + .await + { + tracing::error!(worker = %worker_name, hostname = %hostname, "failed to vacuum queue: {}", e); + } + tracing::info!(worker = %worker_name, hostname = %hostname, "vacuumed queue"); + }) + .instrument(current_span), + ); + } + Connection::Http(_) => { + // do nothing in http mode + () + } + } +} diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index b79c897c96..a4fc35045b 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.478.1"; +export const VERSION = "v1.481.0"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/bootstrap/script_bootstrap.ts b/cli/bootstrap/script_bootstrap.ts index 5c2247e66b..2ac67bdb83 100644 --- a/cli/bootstrap/script_bootstrap.ts +++ b/cli/bootstrap/script_bootstrap.ts @@ -119,4 +119,12 @@ inventory: debug: msg: "Hello, world!" `, + java: ` +public class Main { + public static void main() { + System.out.println("Hello World"); + } +} +`, +// for related places search: ADD_NEW_LANG }; diff --git a/cli/conf.ts b/cli/conf.ts index b2b7b64f54..14de9bcdda 100644 --- a/cli/conf.ts +++ b/cli/conf.ts @@ -4,6 +4,7 @@ export interface SyncOptions { stateful?: boolean; raw?: boolean; yes?: boolean; + dryRun?: boolean; skipPull?: boolean; failConflicts?: boolean; plainSecrets?: boolean; diff --git a/cli/deno.lock b/cli/deno.lock index b1ff9b9a2b..a0a4c6ce2e 100644 --- a/cli/deno.lock +++ b/cli/deno.lock @@ -14,6 +14,7 @@ "jsr:@std/cli@1.0.0-rc.2": "1.0.0-rc.2", "jsr:@std/encoding@*": "1.0.4", "jsr:@std/encoding@1.0.0-rc.2": "1.0.0-rc.2", + "jsr:@std/encoding@1.0.4": "1.0.4", "jsr:@std/encoding@^1.0.4": "1.0.4", "jsr:@std/fmt@0.223": "0.223.0", "jsr:@std/fmt@1": "1.0.2", diff --git a/cli/deps.ts b/cli/deps.ts index 53e96a4f9c..23fd292365 100644 --- a/cli/deps.ts +++ b/cli/deps.ts @@ -15,7 +15,7 @@ export { CompletionsCommand } from "jsr:@windmill-labs/cliffy-command@1.0.0-rc.5 export { ensureDir } from "jsr:@std/fs"; export { SEPARATOR as SEP } from "jsr:@std/path"; export * as path from "jsr:@std/path"; -export { encodeHex } from "jsr:@std/encoding"; +export { encodeHex } from "jsr:@std/encoding@1.0.4"; export { writeAllSync } from "jsr:@std/io/write-all"; export { copy } from "jsr:@std/io/copy"; export { readAll } from "jsr:@std/io/read-all"; diff --git a/cli/dnt.ts b/cli/dnt.ts index 64d9957499..3820439a7e 100644 --- a/cli/dnt.ts +++ b/cli/dnt.ts @@ -69,6 +69,7 @@ await build({ "rust", "yaml", "csharp", + "java", ]; for (const l of dirs) { diff --git a/cli/gen/core/OpenAPI.ts b/cli/gen/core/OpenAPI.ts index 3aa0d92808..2938820ca7 100644 --- a/cli/gen/core/OpenAPI.ts +++ b/cli/gen/core/OpenAPI.ts @@ -54,7 +54,7 @@ export const OpenAPI: OpenAPIConfig = { PASSWORD: undefined, TOKEN: getEnv("WM_TOKEN"), USERNAME: undefined, - VERSION: '1.477.1', + VERSION: '1.481.0', WITH_CREDENTIALS: true, interceptors: { request: new Interceptors(), diff --git a/cli/gen/services.gen.ts b/cli/gen/services.gen.ts index b3fa22bf66..a94a3a544d 100644 --- a/cli/gen/services.gen.ts +++ b/cli/gen/services.gen.ts @@ -3,7 +3,7 @@ import type { CancelablePromise } from './core/CancelablePromise.ts'; import { OpenAPI } from './core/OpenAPI.ts'; import { request as __request } from './core/request.ts'; -import type { BackendVersionResponse, BackendUptodateResponse, GetLicenseIdResponse, GetOpenApiYamlResponse, GetAuditLogData, GetAuditLogResponse, ListAuditLogsData, ListAuditLogsResponse, LoginData, LoginResponse, LogoutResponse, GetUserData, GetUserResponse, UpdateUserData, UpdateUserResponse, IsOwnerOfPathData, IsOwnerOfPathResponse, SetPasswordData, SetPasswordResponse, SetPasswordForUserData, SetPasswordForUserResponse, SetLoginTypeForUserData, SetLoginTypeForUserResponse, CreateUserGloballyData, CreateUserGloballyResponse, GlobalUserUpdateData, GlobalUserUpdateResponse, GlobalUsernameInfoData, GlobalUsernameInfoResponse, GlobalUserRenameData, GlobalUserRenameResponse, GlobalUserDeleteData, GlobalUserDeleteResponse, GlobalUsersOverwriteData, GlobalUsersOverwriteResponse, GlobalUsersExportResponse, DeleteUserData, DeleteUserResponse, ListWorkspacesResponse, IsDomainAllowedResponse, ListUserWorkspacesResponse, ListWorkspacesAsSuperAdminData, ListWorkspacesAsSuperAdminResponse, CreateWorkspaceData, CreateWorkspaceResponse, ExistsWorkspaceData, ExistsWorkspaceResponse, ExistsUsernameData, ExistsUsernameResponse, GetGlobalData, GetGlobalResponse, SetGlobalData, SetGlobalResponse, GetLocalResponse, TestSmtpData, TestSmtpResponse, TestCriticalChannelsData, TestCriticalChannelsResponse, GetCriticalAlertsData, GetCriticalAlertsResponse, AcknowledgeCriticalAlertData, AcknowledgeCriticalAlertResponse, AcknowledgeAllCriticalAlertsResponse, TestLicenseKeyData, TestLicenseKeyResponse, TestObjectStorageConfigData, TestObjectStorageConfigResponse, SendStatsResponse, GetLatestKeyRenewalAttemptResponse, RenewLicenseKeyData, RenewLicenseKeyResponse, CreateCustomerPortalSessionData, CreateCustomerPortalSessionResponse, TestMetadataData, TestMetadataResponse, ListGlobalSettingsResponse, GetCurrentEmailResponse, RefreshUserTokenData, RefreshUserTokenResponse, GetTutorialProgressResponse, UpdateTutorialProgressData, UpdateTutorialProgressResponse, LeaveInstanceResponse, GetUsageResponse, GetRunnableResponse, GlobalWhoamiResponse, ListWorkspaceInvitesResponse, WhoamiData, WhoamiResponse, AcceptInviteData, AcceptInviteResponse, DeclineInviteData, DeclineInviteResponse, InviteUserData, InviteUserResponse, AddUserData, AddUserResponse, DeleteInviteData, DeleteInviteResponse, ArchiveWorkspaceData, ArchiveWorkspaceResponse, UnarchiveWorkspaceData, UnarchiveWorkspaceResponse, DeleteWorkspaceData, DeleteWorkspaceResponse, LeaveWorkspaceData, LeaveWorkspaceResponse, GetWorkspaceNameData, GetWorkspaceNameResponse, ChangeWorkspaceNameData, ChangeWorkspaceNameResponse, ChangeWorkspaceIdData, ChangeWorkspaceIdResponse, ChangeWorkspaceColorData, ChangeWorkspaceColorResponse, WhoisData, WhoisResponse, UpdateOperatorSettingsData, UpdateOperatorSettingsResponse, ExistsEmailData, ExistsEmailResponse, ListUsersAsSuperAdminData, ListUsersAsSuperAdminResponse, ListPendingInvitesData, ListPendingInvitesResponse, GetSettingsData, GetSettingsResponse, GetDeployToData, GetDeployToResponse, GetIsPremiumData, GetIsPremiumResponse, GetPremiumInfoData, GetPremiumInfoResponse, SetAutomaticBillingData, SetAutomaticBillingResponse, GetThresholdAlertData, GetThresholdAlertResponse, SetThresholdAlertData, SetThresholdAlertResponse, EditSlackCommandData, EditSlackCommandResponse, EditTeamsCommandData, EditTeamsCommandResponse, ListAvailableTeamsIdsData, ListAvailableTeamsIdsResponse, ListAvailableTeamsChannelsData, ListAvailableTeamsChannelsResponse, ConnectTeamsData, ConnectTeamsResponse, RunSlackMessageTestJobData, RunSlackMessageTestJobResponse, RunTeamsMessageTestJobData, RunTeamsMessageTestJobResponse, EditDeployToData, EditDeployToResponse, EditAutoInviteData, EditAutoInviteResponse, EditWebhookData, EditWebhookResponse, EditCopilotConfigData, EditCopilotConfigResponse, GetCopilotInfoData, GetCopilotInfoResponse, EditErrorHandlerData, EditErrorHandlerResponse, EditLargeFileStorageConfigData, EditLargeFileStorageConfigResponse, EditWorkspaceGitSyncConfigData, EditWorkspaceGitSyncConfigResponse, EditWorkspaceDeployUiSettingsData, EditWorkspaceDeployUiSettingsResponse, EditWorkspaceDefaultAppData, EditWorkspaceDefaultAppResponse, EditDefaultScriptsData, EditDefaultScriptsResponse, GetDefaultScriptsData, GetDefaultScriptsResponse, SetEnvironmentVariableData, SetEnvironmentVariableResponse, GetWorkspaceEncryptionKeyData, GetWorkspaceEncryptionKeyResponse, SetWorkspaceEncryptionKeyData, SetWorkspaceEncryptionKeyResponse, GetWorkspaceDefaultAppData, GetWorkspaceDefaultAppResponse, GetLargeFileStorageConfigData, GetLargeFileStorageConfigResponse, GetWorkspaceUsageData, GetWorkspaceUsageResponse, GetUsedTriggersData, GetUsedTriggersResponse, ListUsersData, ListUsersResponse, ListUsersUsageData, ListUsersUsageResponse, ListUsernamesData, ListUsernamesResponse, UsernameToEmailData, UsernameToEmailResponse, CreateTokenData, CreateTokenResponse, CreateTokenImpersonateData, CreateTokenImpersonateResponse, DeleteTokenData, DeleteTokenResponse, ListTokensData, ListTokensResponse, GetOidcTokenData, GetOidcTokenResponse, CreateVariableData, CreateVariableResponse, EncryptValueData, EncryptValueResponse, DeleteVariableData, DeleteVariableResponse, UpdateVariableData, UpdateVariableResponse, GetVariableData, GetVariableResponse, GetVariableValueData, GetVariableValueResponse, ExistsVariableData, ExistsVariableResponse, ListVariableData, ListVariableResponse, ListContextualVariablesData, ListContextualVariablesResponse, WorkspaceGetCriticalAlertsData, WorkspaceGetCriticalAlertsResponse, WorkspaceAcknowledgeCriticalAlertData, WorkspaceAcknowledgeCriticalAlertResponse, WorkspaceAcknowledgeAllCriticalAlertsData, WorkspaceAcknowledgeAllCriticalAlertsResponse, WorkspaceMuteCriticalAlertsUiData, WorkspaceMuteCriticalAlertsUiResponse, LoginWithOauthData, LoginWithOauthResponse, ConnectSlackCallbackData, ConnectSlackCallbackResponse, ConnectSlackCallbackInstanceData, ConnectSlackCallbackInstanceResponse, ConnectCallbackData, ConnectCallbackResponse, CreateAccountData, CreateAccountResponse, RefreshTokenData, RefreshTokenResponse, DisconnectAccountData, DisconnectAccountResponse, DisconnectSlackData, DisconnectSlackResponse, DisconnectTeamsData, DisconnectTeamsResponse, ListOauthLoginsResponse, ListOauthConnectsResponse, GetOauthConnectData, GetOauthConnectResponse, SyncTeamsResponse, SendMessageToConversationData, SendMessageToConversationResponse, CreateResourceData, CreateResourceResponse, DeleteResourceData, DeleteResourceResponse, UpdateResourceData, UpdateResourceResponse, UpdateResourceValueData, UpdateResourceValueResponse, GetResourceData, GetResourceResponse, GetResourceValueInterpolatedData, GetResourceValueInterpolatedResponse, GetResourceValueData, GetResourceValueResponse, ExistsResourceData, ExistsResourceResponse, ListResourceData, ListResourceResponse, ListSearchResourceData, ListSearchResourceResponse, ListResourceNamesData, ListResourceNamesResponse, CreateResourceTypeData, CreateResourceTypeResponse, FileResourceTypeToFileExtMapData, FileResourceTypeToFileExtMapResponse, DeleteResourceTypeData, DeleteResourceTypeResponse, UpdateResourceTypeData, UpdateResourceTypeResponse, GetResourceTypeData, GetResourceTypeResponse, ExistsResourceTypeData, ExistsResourceTypeResponse, ListResourceTypeData, ListResourceTypeResponse, ListResourceTypeNamesData, ListResourceTypeNamesResponse, QueryResourceTypesData, QueryResourceTypesResponse, ListHubIntegrationsData, ListHubIntegrationsResponse, ListHubFlowsResponse, GetHubFlowByIdData, GetHubFlowByIdResponse, ListHubAppsResponse, GetHubAppByIdData, GetHubAppByIdResponse, GetPublicAppByCustomPathData, GetPublicAppByCustomPathResponse, GetHubScriptContentByPathData, GetHubScriptContentByPathResponse, GetHubScriptByPathData, GetHubScriptByPathResponse, GetTopHubScriptsData, GetTopHubScriptsResponse, QueryHubScriptsData, QueryHubScriptsResponse, ListSearchScriptData, ListSearchScriptResponse, ListScriptsData, ListScriptsResponse, ListScriptPathsData, ListScriptPathsResponse, CreateDraftData, CreateDraftResponse, DeleteDraftData, DeleteDraftResponse, CreateScriptData, CreateScriptResponse, ToggleWorkspaceErrorHandlerForScriptData, ToggleWorkspaceErrorHandlerForScriptResponse, GetCustomTagsData, GetCustomTagsResponse, GeDefaultTagsResponse, IsDefaultTagsPerWorkspaceResponse, ArchiveScriptByPathData, ArchiveScriptByPathResponse, ArchiveScriptByHashData, ArchiveScriptByHashResponse, DeleteScriptByHashData, DeleteScriptByHashResponse, DeleteScriptByPathData, DeleteScriptByPathResponse, GetScriptByPathData, GetScriptByPathResponse, GetTriggersCountOfScriptData, GetTriggersCountOfScriptResponse, ListTokensOfScriptData, ListTokensOfScriptResponse, GetScriptByPathWithDraftData, GetScriptByPathWithDraftResponse, GetScriptHistoryByPathData, GetScriptHistoryByPathResponse, GetScriptLatestVersionData, GetScriptLatestVersionResponse, UpdateScriptHistoryData, UpdateScriptHistoryResponse, RawScriptByPathData, RawScriptByPathResponse, RawScriptByPathTokenedData, RawScriptByPathTokenedResponse, ExistsScriptByPathData, ExistsScriptByPathResponse, GetScriptByHashData, GetScriptByHashResponse, RawScriptByHashData, RawScriptByHashResponse, GetScriptDeploymentStatusData, GetScriptDeploymentStatusResponse, RunScriptByPathData, RunScriptByPathResponse, OpenaiSyncScriptByPathData, OpenaiSyncScriptByPathResponse, RunWaitResultScriptByPathData, RunWaitResultScriptByPathResponse, RunWaitResultScriptByPathGetData, RunWaitResultScriptByPathGetResponse, OpenaiSyncFlowByPathData, OpenaiSyncFlowByPathResponse, RunWaitResultFlowByPathData, RunWaitResultFlowByPathResponse, ResultByIdData, ResultByIdResponse, ListFlowPathsData, ListFlowPathsResponse, ListSearchFlowData, ListSearchFlowResponse, ListFlowsData, ListFlowsResponse, GetFlowHistoryData, GetFlowHistoryResponse, GetFlowLatestVersionData, GetFlowLatestVersionResponse, ListFlowPathsFromWorkspaceRunnableData, ListFlowPathsFromWorkspaceRunnableResponse, GetFlowVersionData, GetFlowVersionResponse, UpdateFlowHistoryData, UpdateFlowHistoryResponse, GetFlowByPathData, GetFlowByPathResponse, GetFlowDeploymentStatusData, GetFlowDeploymentStatusResponse, GetTriggersCountOfFlowData, GetTriggersCountOfFlowResponse, ListTokensOfFlowData, ListTokensOfFlowResponse, ToggleWorkspaceErrorHandlerForFlowData, ToggleWorkspaceErrorHandlerForFlowResponse, GetFlowByPathWithDraftData, GetFlowByPathWithDraftResponse, ExistsFlowByPathData, ExistsFlowByPathResponse, CreateFlowData, CreateFlowResponse, UpdateFlowData, UpdateFlowResponse, ArchiveFlowByPathData, ArchiveFlowByPathResponse, DeleteFlowByPathData, DeleteFlowByPathResponse, ListRawAppsData, ListRawAppsResponse, ExistsRawAppData, ExistsRawAppResponse, GetRawAppDataData, GetRawAppDataResponse, ListSearchAppData, ListSearchAppResponse, ListAppsData, ListAppsResponse, CreateAppData, CreateAppResponse, ExistsAppData, ExistsAppResponse, GetAppByPathData, GetAppByPathResponse, GetAppLiteByPathData, GetAppLiteByPathResponse, GetAppByPathWithDraftData, GetAppByPathWithDraftResponse, GetAppHistoryByPathData, GetAppHistoryByPathResponse, GetAppLatestVersionData, GetAppLatestVersionResponse, UpdateAppHistoryData, UpdateAppHistoryResponse, GetPublicAppBySecretData, GetPublicAppBySecretResponse, GetPublicResourceData, GetPublicResourceResponse, GetPublicSecretOfAppData, GetPublicSecretOfAppResponse, GetAppByVersionData, GetAppByVersionResponse, CreateRawAppData, CreateRawAppResponse, UpdateRawAppData, UpdateRawAppResponse, DeleteRawAppData, DeleteRawAppResponse, DeleteAppData, DeleteAppResponse, UpdateAppData, UpdateAppResponse, CustomPathExistsData, CustomPathExistsResponse, ExecuteComponentData, ExecuteComponentResponse, UploadS3FileFromAppData, UploadS3FileFromAppResponse, DeleteS3FileFromAppData, DeleteS3FileFromAppResponse, RunFlowByPathData, RunFlowByPathResponse, RestartFlowAtStepData, RestartFlowAtStepResponse, RunScriptByHashData, RunScriptByHashResponse, RunScriptPreviewData, RunScriptPreviewResponse, RunCodeWorkflowTaskData, RunCodeWorkflowTaskResponse, RunRawScriptDependenciesData, RunRawScriptDependenciesResponse, RunFlowPreviewData, RunFlowPreviewResponse, ListQueueData, ListQueueResponse, GetQueueCountData, GetQueueCountResponse, GetCompletedCountData, GetCompletedCountResponse, CountCompletedJobsData, CountCompletedJobsResponse, ListFilteredUuidsData, ListFilteredUuidsResponse, CancelSelectionData, CancelSelectionResponse, ListCompletedJobsData, ListCompletedJobsResponse, ListJobsData, ListJobsResponse, GetDbClockResponse, CountJobsByTagData, CountJobsByTagResponse, GetJobData, GetJobResponse, GetRootJobIdData, GetRootJobIdResponse, GetJobLogsData, GetJobLogsResponse, GetJobArgsData, GetJobArgsResponse, GetJobUpdatesData, GetJobUpdatesResponse, GetLogFileFromStoreData, GetLogFileFromStoreResponse, GetFlowDebugInfoData, GetFlowDebugInfoResponse, GetCompletedJobData, GetCompletedJobResponse, GetCompletedJobResultData, GetCompletedJobResultResponse, GetCompletedJobResultMaybeData, GetCompletedJobResultMaybeResponse, DeleteCompletedJobData, DeleteCompletedJobResponse, CancelQueuedJobData, CancelQueuedJobResponse, CancelPersistentQueuedJobsData, CancelPersistentQueuedJobsResponse, ForceCancelQueuedJobData, ForceCancelQueuedJobResponse, CreateJobSignatureData, CreateJobSignatureResponse, GetResumeUrlsData, GetResumeUrlsResponse, GetSlackApprovalPayloadData, GetSlackApprovalPayloadResponse, ResumeSuspendedJobGetData, ResumeSuspendedJobGetResponse, ResumeSuspendedJobPostData, ResumeSuspendedJobPostResponse, SetFlowUserStateData, SetFlowUserStateResponse, GetFlowUserStateData, GetFlowUserStateResponse, ResumeSuspendedFlowAsOwnerData, ResumeSuspendedFlowAsOwnerResponse, CancelSuspendedJobGetData, CancelSuspendedJobGetResponse, CancelSuspendedJobPostData, CancelSuspendedJobPostResponse, GetSuspendedJobFlowData, GetSuspendedJobFlowResponse, PreviewScheduleData, PreviewScheduleResponse, CreateScheduleData, CreateScheduleResponse, UpdateScheduleData, UpdateScheduleResponse, SetScheduleEnabledData, SetScheduleEnabledResponse, DeleteScheduleData, DeleteScheduleResponse, GetScheduleData, GetScheduleResponse, ExistsScheduleData, ExistsScheduleResponse, ListSchedulesData, ListSchedulesResponse, ListSchedulesWithJobsData, ListSchedulesWithJobsResponse, SetDefaultErrorOrRecoveryHandlerData, SetDefaultErrorOrRecoveryHandlerResponse, CreateHttpTriggerData, CreateHttpTriggerResponse, UpdateHttpTriggerData, UpdateHttpTriggerResponse, DeleteHttpTriggerData, DeleteHttpTriggerResponse, GetHttpTriggerData, GetHttpTriggerResponse, ListHttpTriggersData, ListHttpTriggersResponse, ExistsHttpTriggerData, ExistsHttpTriggerResponse, ExistsRouteData, ExistsRouteResponse, CreateWebsocketTriggerData, CreateWebsocketTriggerResponse, UpdateWebsocketTriggerData, UpdateWebsocketTriggerResponse, DeleteWebsocketTriggerData, DeleteWebsocketTriggerResponse, GetWebsocketTriggerData, GetWebsocketTriggerResponse, ListWebsocketTriggersData, ListWebsocketTriggersResponse, ExistsWebsocketTriggerData, ExistsWebsocketTriggerResponse, SetWebsocketTriggerEnabledData, SetWebsocketTriggerEnabledResponse, TestWebsocketConnectionData, TestWebsocketConnectionResponse, CreateKafkaTriggerData, CreateKafkaTriggerResponse, UpdateKafkaTriggerData, UpdateKafkaTriggerResponse, DeleteKafkaTriggerData, DeleteKafkaTriggerResponse, GetKafkaTriggerData, GetKafkaTriggerResponse, ListKafkaTriggersData, ListKafkaTriggersResponse, ExistsKafkaTriggerData, ExistsKafkaTriggerResponse, SetKafkaTriggerEnabledData, SetKafkaTriggerEnabledResponse, TestKafkaConnectionData, TestKafkaConnectionResponse, CreateNatsTriggerData, CreateNatsTriggerResponse, UpdateNatsTriggerData, UpdateNatsTriggerResponse, DeleteNatsTriggerData, DeleteNatsTriggerResponse, GetNatsTriggerData, GetNatsTriggerResponse, ListNatsTriggersData, ListNatsTriggersResponse, ExistsNatsTriggerData, ExistsNatsTriggerResponse, SetNatsTriggerEnabledData, SetNatsTriggerEnabledResponse, TestNatsConnectionData, TestNatsConnectionResponse, CreateSqsTriggerData, CreateSqsTriggerResponse, UpdateSqsTriggerData, UpdateSqsTriggerResponse, DeleteSqsTriggerData, DeleteSqsTriggerResponse, GetSqsTriggerData, GetSqsTriggerResponse, ListSqsTriggersData, ListSqsTriggersResponse, ExistsSqsTriggerData, ExistsSqsTriggerResponse, SetSqsTriggerEnabledData, SetSqsTriggerEnabledResponse, TestSqsConnectionData, TestSqsConnectionResponse, CreateMqttTriggerData, CreateMqttTriggerResponse, UpdateMqttTriggerData, UpdateMqttTriggerResponse, DeleteMqttTriggerData, DeleteMqttTriggerResponse, GetMqttTriggerData, GetMqttTriggerResponse, ListMqttTriggersData, ListMqttTriggersResponse, ExistsMqttTriggerData, ExistsMqttTriggerResponse, SetMqttTriggerEnabledData, SetMqttTriggerEnabledResponse, TestMqttConnectionData, TestMqttConnectionResponse, IsValidPostgresConfigurationData, IsValidPostgresConfigurationResponse, CreateTemplateScriptData, CreateTemplateScriptResponse, GetTemplateScriptData, GetTemplateScriptResponse, ListPostgresReplicationSlotData, ListPostgresReplicationSlotResponse, CreatePostgresReplicationSlotData, CreatePostgresReplicationSlotResponse, DeletePostgresReplicationSlotData, DeletePostgresReplicationSlotResponse, ListPostgresPublicationData, ListPostgresPublicationResponse, GetPostgresPublicationData, GetPostgresPublicationResponse, CreatePostgresPublicationData, CreatePostgresPublicationResponse, UpdatePostgresPublicationData, UpdatePostgresPublicationResponse, DeletePostgresPublicationData, DeletePostgresPublicationResponse, CreatePostgresTriggerData, CreatePostgresTriggerResponse, UpdatePostgresTriggerData, UpdatePostgresTriggerResponse, DeletePostgresTriggerData, DeletePostgresTriggerResponse, GetPostgresTriggerData, GetPostgresTriggerResponse, ListPostgresTriggersData, ListPostgresTriggersResponse, ExistsPostgresTriggerData, ExistsPostgresTriggerResponse, SetPostgresTriggerEnabledData, SetPostgresTriggerEnabledResponse, TestPostgresConnectionData, TestPostgresConnectionResponse, ListInstanceGroupsResponse, GetInstanceGroupData, GetInstanceGroupResponse, CreateInstanceGroupData, CreateInstanceGroupResponse, UpdateInstanceGroupData, UpdateInstanceGroupResponse, DeleteInstanceGroupData, DeleteInstanceGroupResponse, AddUserToInstanceGroupData, AddUserToInstanceGroupResponse, RemoveUserFromInstanceGroupData, RemoveUserFromInstanceGroupResponse, ExportInstanceGroupsResponse, OverwriteInstanceGroupsData, OverwriteInstanceGroupsResponse, ListGroupsData, ListGroupsResponse, ListGroupNamesData, ListGroupNamesResponse, CreateGroupData, CreateGroupResponse, UpdateGroupData, UpdateGroupResponse, DeleteGroupData, DeleteGroupResponse, GetGroupData, GetGroupResponse, AddUserToGroupData, AddUserToGroupResponse, RemoveUserToGroupData, RemoveUserToGroupResponse, ListFoldersData, ListFoldersResponse, ListFolderNamesData, ListFolderNamesResponse, CreateFolderData, CreateFolderResponse, UpdateFolderData, UpdateFolderResponse, DeleteFolderData, DeleteFolderResponse, GetFolderData, GetFolderResponse, ExistsFolderData, ExistsFolderResponse, GetFolderUsageData, GetFolderUsageResponse, AddOwnerToFolderData, AddOwnerToFolderResponse, RemoveOwnerToFolderData, RemoveOwnerToFolderResponse, ListWorkersData, ListWorkersResponse, ExistsWorkerWithTagData, ExistsWorkerWithTagResponse, GetQueueMetricsResponse, GetCountsOfJobsWaitingPerTagResponse, ListWorkerGroupsResponse, GetConfigData, GetConfigResponse, UpdateConfigData, UpdateConfigResponse, DeleteConfigData, DeleteConfigResponse, ListConfigsResponse, ListAutoscalingEventsData, ListAutoscalingEventsResponse, GetGranularAclsData, GetGranularAclsResponse, AddGranularAclsData, AddGranularAclsResponse, RemoveGranularAclsData, RemoveGranularAclsResponse, SetCaptureConfigData, SetCaptureConfigResponse, PingCaptureConfigData, PingCaptureConfigResponse, GetCaptureConfigsData, GetCaptureConfigsResponse, ListCapturesData, ListCapturesResponse, MoveCapturesAndConfigsData, MoveCapturesAndConfigsResponse, GetCaptureData, GetCaptureResponse, DeleteCaptureData, DeleteCaptureResponse, StarData, StarResponse, UnstarData, UnstarResponse, GetInputHistoryData, GetInputHistoryResponse, GetArgsFromHistoryOrSavedInputData, GetArgsFromHistoryOrSavedInputResponse, ListInputsData, ListInputsResponse, CreateInputData, CreateInputResponse, UpdateInputData, UpdateInputResponse, DeleteInputData, DeleteInputResponse, DuckdbConnectionSettingsData, DuckdbConnectionSettingsResponse, DuckdbConnectionSettingsV2Data, DuckdbConnectionSettingsV2Response, PolarsConnectionSettingsData, PolarsConnectionSettingsResponse, PolarsConnectionSettingsV2Data, PolarsConnectionSettingsV2Response, S3ResourceInfoData, S3ResourceInfoResponse, DatasetStorageTestConnectionData, DatasetStorageTestConnectionResponse, ListStoredFilesData, ListStoredFilesResponse, LoadFileMetadataData, LoadFileMetadataResponse, LoadFilePreviewData, LoadFilePreviewResponse, LoadParquetPreviewData, LoadParquetPreviewResponse, LoadTableRowCountData, LoadTableRowCountResponse, LoadCsvPreviewData, LoadCsvPreviewResponse, DeleteS3FileData, DeleteS3FileResponse, MoveS3FileData, MoveS3FileResponse, FileUploadData, FileUploadResponse, FileDownloadData, FileDownloadResponse, FileDownloadParquetAsCsvData, FileDownloadParquetAsCsvResponse, GetJobMetricsData, GetJobMetricsResponse, SetJobProgressData, SetJobProgressResponse, GetJobProgressData, GetJobProgressResponse, ListLogFilesData, ListLogFilesResponse, GetLogFileData, GetLogFileResponse, ListConcurrencyGroupsResponse, DeleteConcurrencyGroupData, DeleteConcurrencyGroupResponse, GetConcurrencyKeyData, GetConcurrencyKeyResponse, ListExtendedJobsData, ListExtendedJobsResponse, SearchJobsIndexData, SearchJobsIndexResponse, SearchLogsIndexData, SearchLogsIndexResponse, CountSearchLogsIndexData, CountSearchLogsIndexResponse, ClearIndexData, ClearIndexResponse } from './types.gen.ts'; +import type { BackendVersionResponse, BackendUptodateResponse, GetLicenseIdResponse, GetOpenApiYamlResponse, GetAuditLogData, GetAuditLogResponse, ListAuditLogsData, ListAuditLogsResponse, LoginData, LoginResponse, LogoutResponse, GetUserData, GetUserResponse, UpdateUserData, UpdateUserResponse, IsOwnerOfPathData, IsOwnerOfPathResponse, SetPasswordData, SetPasswordResponse, SetPasswordForUserData, SetPasswordForUserResponse, SetLoginTypeForUserData, SetLoginTypeForUserResponse, CreateUserGloballyData, CreateUserGloballyResponse, GlobalUserUpdateData, GlobalUserUpdateResponse, GlobalUsernameInfoData, GlobalUsernameInfoResponse, GlobalUserRenameData, GlobalUserRenameResponse, GlobalUserDeleteData, GlobalUserDeleteResponse, GlobalUsersOverwriteData, GlobalUsersOverwriteResponse, GlobalUsersExportResponse, DeleteUserData, DeleteUserResponse, GetGlobalConnectedRepositoriesResponse, ListWorkspacesResponse, IsDomainAllowedResponse, ListUserWorkspacesResponse, ListWorkspacesAsSuperAdminData, ListWorkspacesAsSuperAdminResponse, CreateWorkspaceData, CreateWorkspaceResponse, ExistsWorkspaceData, ExistsWorkspaceResponse, ExistsUsernameData, ExistsUsernameResponse, GetGlobalData, GetGlobalResponse, SetGlobalData, SetGlobalResponse, GetLocalResponse, TestSmtpData, TestSmtpResponse, TestCriticalChannelsData, TestCriticalChannelsResponse, GetCriticalAlertsData, GetCriticalAlertsResponse, AcknowledgeCriticalAlertData, AcknowledgeCriticalAlertResponse, AcknowledgeAllCriticalAlertsResponse, TestLicenseKeyData, TestLicenseKeyResponse, TestObjectStorageConfigData, TestObjectStorageConfigResponse, SendStatsResponse, GetLatestKeyRenewalAttemptResponse, RenewLicenseKeyData, RenewLicenseKeyResponse, CreateCustomerPortalSessionData, CreateCustomerPortalSessionResponse, TestMetadataData, TestMetadataResponse, ListGlobalSettingsResponse, GetCurrentEmailResponse, RefreshUserTokenData, RefreshUserTokenResponse, GetTutorialProgressResponse, UpdateTutorialProgressData, UpdateTutorialProgressResponse, LeaveInstanceResponse, GetUsageResponse, GetRunnableResponse, GlobalWhoamiResponse, ListWorkspaceInvitesResponse, WhoamiData, WhoamiResponse, GetGithubAppTokenData, GetGithubAppTokenResponse, InstallFromWorkspaceData, InstallFromWorkspaceResponse, DeleteFromWorkspaceData, DeleteFromWorkspaceResponse, ExportInstallationData, ExportInstallationResponse, ImportInstallationData, ImportInstallationResponse, AcceptInviteData, AcceptInviteResponse, DeclineInviteData, DeclineInviteResponse, InviteUserData, InviteUserResponse, AddUserData, AddUserResponse, DeleteInviteData, DeleteInviteResponse, ArchiveWorkspaceData, ArchiveWorkspaceResponse, UnarchiveWorkspaceData, UnarchiveWorkspaceResponse, DeleteWorkspaceData, DeleteWorkspaceResponse, LeaveWorkspaceData, LeaveWorkspaceResponse, GetWorkspaceNameData, GetWorkspaceNameResponse, ChangeWorkspaceNameData, ChangeWorkspaceNameResponse, ChangeWorkspaceIdData, ChangeWorkspaceIdResponse, ChangeWorkspaceColorData, ChangeWorkspaceColorResponse, WhoisData, WhoisResponse, UpdateOperatorSettingsData, UpdateOperatorSettingsResponse, ExistsEmailData, ExistsEmailResponse, ListUsersAsSuperAdminData, ListUsersAsSuperAdminResponse, ListPendingInvitesData, ListPendingInvitesResponse, GetSettingsData, GetSettingsResponse, GetDeployToData, GetDeployToResponse, GetIsPremiumData, GetIsPremiumResponse, GetPremiumInfoData, GetPremiumInfoResponse, GetThresholdAlertData, GetThresholdAlertResponse, SetThresholdAlertData, SetThresholdAlertResponse, EditSlackCommandData, EditSlackCommandResponse, EditTeamsCommandData, EditTeamsCommandResponse, ListAvailableTeamsIdsData, ListAvailableTeamsIdsResponse, ListAvailableTeamsChannelsData, ListAvailableTeamsChannelsResponse, ConnectTeamsData, ConnectTeamsResponse, RunSlackMessageTestJobData, RunSlackMessageTestJobResponse, RunTeamsMessageTestJobData, RunTeamsMessageTestJobResponse, EditDeployToData, EditDeployToResponse, EditAutoInviteData, EditAutoInviteResponse, EditWebhookData, EditWebhookResponse, EditCopilotConfigData, EditCopilotConfigResponse, GetCopilotInfoData, GetCopilotInfoResponse, EditErrorHandlerData, EditErrorHandlerResponse, EditLargeFileStorageConfigData, EditLargeFileStorageConfigResponse, EditWorkspaceGitSyncConfigData, EditWorkspaceGitSyncConfigResponse, EditWorkspaceDeployUiSettingsData, EditWorkspaceDeployUiSettingsResponse, EditWorkspaceDefaultAppData, EditWorkspaceDefaultAppResponse, EditDefaultScriptsData, EditDefaultScriptsResponse, GetDefaultScriptsData, GetDefaultScriptsResponse, SetEnvironmentVariableData, SetEnvironmentVariableResponse, GetWorkspaceEncryptionKeyData, GetWorkspaceEncryptionKeyResponse, SetWorkspaceEncryptionKeyData, SetWorkspaceEncryptionKeyResponse, GetWorkspaceDefaultAppData, GetWorkspaceDefaultAppResponse, GetLargeFileStorageConfigData, GetLargeFileStorageConfigResponse, GetWorkspaceUsageData, GetWorkspaceUsageResponse, GetUsedTriggersData, GetUsedTriggersResponse, ListUsersData, ListUsersResponse, ListUsersUsageData, ListUsersUsageResponse, ListUsernamesData, ListUsernamesResponse, UsernameToEmailData, UsernameToEmailResponse, CreateTokenData, CreateTokenResponse, CreateTokenImpersonateData, CreateTokenImpersonateResponse, DeleteTokenData, DeleteTokenResponse, ListTokensData, ListTokensResponse, GetOidcTokenData, GetOidcTokenResponse, CreateVariableData, CreateVariableResponse, EncryptValueData, EncryptValueResponse, DeleteVariableData, DeleteVariableResponse, UpdateVariableData, UpdateVariableResponse, GetVariableData, GetVariableResponse, GetVariableValueData, GetVariableValueResponse, ExistsVariableData, ExistsVariableResponse, ListVariableData, ListVariableResponse, ListContextualVariablesData, ListContextualVariablesResponse, WorkspaceGetCriticalAlertsData, WorkspaceGetCriticalAlertsResponse, WorkspaceAcknowledgeCriticalAlertData, WorkspaceAcknowledgeCriticalAlertResponse, WorkspaceAcknowledgeAllCriticalAlertsData, WorkspaceAcknowledgeAllCriticalAlertsResponse, WorkspaceMuteCriticalAlertsUiData, WorkspaceMuteCriticalAlertsUiResponse, LoginWithOauthData, LoginWithOauthResponse, ConnectSlackCallbackData, ConnectSlackCallbackResponse, ConnectSlackCallbackInstanceData, ConnectSlackCallbackInstanceResponse, ConnectCallbackData, ConnectCallbackResponse, CreateAccountData, CreateAccountResponse, RefreshTokenData, RefreshTokenResponse, DisconnectAccountData, DisconnectAccountResponse, DisconnectSlackData, DisconnectSlackResponse, DisconnectTeamsData, DisconnectTeamsResponse, ListOauthLoginsResponse, ListOauthConnectsResponse, GetOauthConnectData, GetOauthConnectResponse, SyncTeamsResponse, SendMessageToConversationData, SendMessageToConversationResponse, CreateResourceData, CreateResourceResponse, DeleteResourceData, DeleteResourceResponse, UpdateResourceData, UpdateResourceResponse, UpdateResourceValueData, UpdateResourceValueResponse, GetResourceData, GetResourceResponse, GetResourceValueInterpolatedData, GetResourceValueInterpolatedResponse, GetResourceValueData, GetResourceValueResponse, ExistsResourceData, ExistsResourceResponse, ListResourceData, ListResourceResponse, ListSearchResourceData, ListSearchResourceResponse, ListResourceNamesData, ListResourceNamesResponse, CreateResourceTypeData, CreateResourceTypeResponse, FileResourceTypeToFileExtMapData, FileResourceTypeToFileExtMapResponse, DeleteResourceTypeData, DeleteResourceTypeResponse, UpdateResourceTypeData, UpdateResourceTypeResponse, GetResourceTypeData, GetResourceTypeResponse, ExistsResourceTypeData, ExistsResourceTypeResponse, ListResourceTypeData, ListResourceTypeResponse, ListResourceTypeNamesData, ListResourceTypeNamesResponse, QueryResourceTypesData, QueryResourceTypesResponse, ListHubIntegrationsData, ListHubIntegrationsResponse, ListHubFlowsResponse, GetHubFlowByIdData, GetHubFlowByIdResponse, ListHubAppsResponse, GetHubAppByIdData, GetHubAppByIdResponse, GetPublicAppByCustomPathData, GetPublicAppByCustomPathResponse, GetHubScriptContentByPathData, GetHubScriptContentByPathResponse, GetHubScriptByPathData, GetHubScriptByPathResponse, GetTopHubScriptsData, GetTopHubScriptsResponse, QueryHubScriptsData, QueryHubScriptsResponse, ListSearchScriptData, ListSearchScriptResponse, ListScriptsData, ListScriptsResponse, ListScriptPathsData, ListScriptPathsResponse, CreateDraftData, CreateDraftResponse, DeleteDraftData, DeleteDraftResponse, CreateScriptData, CreateScriptResponse, ToggleWorkspaceErrorHandlerForScriptData, ToggleWorkspaceErrorHandlerForScriptResponse, GetCustomTagsData, GetCustomTagsResponse, GeDefaultTagsResponse, IsDefaultTagsPerWorkspaceResponse, ArchiveScriptByPathData, ArchiveScriptByPathResponse, ArchiveScriptByHashData, ArchiveScriptByHashResponse, DeleteScriptByHashData, DeleteScriptByHashResponse, DeleteScriptByPathData, DeleteScriptByPathResponse, GetScriptByPathData, GetScriptByPathResponse, GetTriggersCountOfScriptData, GetTriggersCountOfScriptResponse, ListTokensOfScriptData, ListTokensOfScriptResponse, GetScriptByPathWithDraftData, GetScriptByPathWithDraftResponse, GetScriptHistoryByPathData, GetScriptHistoryByPathResponse, ListScriptPathsFromWorkspaceRunnableData, ListScriptPathsFromWorkspaceRunnableResponse, GetScriptLatestVersionData, GetScriptLatestVersionResponse, UpdateScriptHistoryData, UpdateScriptHistoryResponse, RawScriptByPathData, RawScriptByPathResponse, RawScriptByPathTokenedData, RawScriptByPathTokenedResponse, ExistsScriptByPathData, ExistsScriptByPathResponse, GetScriptByHashData, GetScriptByHashResponse, RawScriptByHashData, RawScriptByHashResponse, GetScriptDeploymentStatusData, GetScriptDeploymentStatusResponse, RunScriptByPathData, RunScriptByPathResponse, OpenaiSyncScriptByPathData, OpenaiSyncScriptByPathResponse, RunWaitResultScriptByPathData, RunWaitResultScriptByPathResponse, RunWaitResultScriptByPathGetData, RunWaitResultScriptByPathGetResponse, OpenaiSyncFlowByPathData, OpenaiSyncFlowByPathResponse, RunWaitResultFlowByPathData, RunWaitResultFlowByPathResponse, ResultByIdData, ResultByIdResponse, ListFlowPathsData, ListFlowPathsResponse, ListSearchFlowData, ListSearchFlowResponse, ListFlowsData, ListFlowsResponse, GetFlowHistoryData, GetFlowHistoryResponse, GetFlowLatestVersionData, GetFlowLatestVersionResponse, ListFlowPathsFromWorkspaceRunnableData, ListFlowPathsFromWorkspaceRunnableResponse, GetFlowVersionData, GetFlowVersionResponse, UpdateFlowHistoryData, UpdateFlowHistoryResponse, GetFlowByPathData, GetFlowByPathResponse, GetFlowDeploymentStatusData, GetFlowDeploymentStatusResponse, GetTriggersCountOfFlowData, GetTriggersCountOfFlowResponse, ListTokensOfFlowData, ListTokensOfFlowResponse, ToggleWorkspaceErrorHandlerForFlowData, ToggleWorkspaceErrorHandlerForFlowResponse, GetFlowByPathWithDraftData, GetFlowByPathWithDraftResponse, ExistsFlowByPathData, ExistsFlowByPathResponse, CreateFlowData, CreateFlowResponse, UpdateFlowData, UpdateFlowResponse, ArchiveFlowByPathData, ArchiveFlowByPathResponse, DeleteFlowByPathData, DeleteFlowByPathResponse, ListRawAppsData, ListRawAppsResponse, ExistsRawAppData, ExistsRawAppResponse, GetRawAppDataData, GetRawAppDataResponse, ListSearchAppData, ListSearchAppResponse, ListAppsData, ListAppsResponse, CreateAppData, CreateAppResponse, ExistsAppData, ExistsAppResponse, GetAppByPathData, GetAppByPathResponse, GetAppLiteByPathData, GetAppLiteByPathResponse, GetAppByPathWithDraftData, GetAppByPathWithDraftResponse, GetAppHistoryByPathData, GetAppHistoryByPathResponse, GetAppLatestVersionData, GetAppLatestVersionResponse, ListAppPathsFromWorkspaceRunnableData, ListAppPathsFromWorkspaceRunnableResponse, UpdateAppHistoryData, UpdateAppHistoryResponse, GetPublicAppBySecretData, GetPublicAppBySecretResponse, GetPublicResourceData, GetPublicResourceResponse, GetPublicSecretOfAppData, GetPublicSecretOfAppResponse, GetAppByVersionData, GetAppByVersionResponse, CreateRawAppData, CreateRawAppResponse, UpdateRawAppData, UpdateRawAppResponse, DeleteRawAppData, DeleteRawAppResponse, DeleteAppData, DeleteAppResponse, UpdateAppData, UpdateAppResponse, CustomPathExistsData, CustomPathExistsResponse, ExecuteComponentData, ExecuteComponentResponse, UploadS3FileFromAppData, UploadS3FileFromAppResponse, DeleteS3FileFromAppData, DeleteS3FileFromAppResponse, RunFlowByPathData, RunFlowByPathResponse, RestartFlowAtStepData, RestartFlowAtStepResponse, RunScriptByHashData, RunScriptByHashResponse, RunScriptPreviewData, RunScriptPreviewResponse, RunCodeWorkflowTaskData, RunCodeWorkflowTaskResponse, RunRawScriptDependenciesData, RunRawScriptDependenciesResponse, RunFlowPreviewData, RunFlowPreviewResponse, ListQueueData, ListQueueResponse, GetQueueCountData, GetQueueCountResponse, GetCompletedCountData, GetCompletedCountResponse, CountCompletedJobsData, CountCompletedJobsResponse, ListFilteredUuidsData, ListFilteredUuidsResponse, CancelSelectionData, CancelSelectionResponse, ListCompletedJobsData, ListCompletedJobsResponse, ListJobsData, ListJobsResponse, GetDbClockResponse, CountJobsByTagData, CountJobsByTagResponse, GetJobData, GetJobResponse, GetRootJobIdData, GetRootJobIdResponse, GetJobLogsData, GetJobLogsResponse, GetJobArgsData, GetJobArgsResponse, GetJobUpdatesData, GetJobUpdatesResponse, GetLogFileFromStoreData, GetLogFileFromStoreResponse, GetFlowDebugInfoData, GetFlowDebugInfoResponse, GetCompletedJobData, GetCompletedJobResponse, GetCompletedJobResultData, GetCompletedJobResultResponse, GetCompletedJobResultMaybeData, GetCompletedJobResultMaybeResponse, DeleteCompletedJobData, DeleteCompletedJobResponse, CancelQueuedJobData, CancelQueuedJobResponse, CancelPersistentQueuedJobsData, CancelPersistentQueuedJobsResponse, ForceCancelQueuedJobData, ForceCancelQueuedJobResponse, CreateJobSignatureData, CreateJobSignatureResponse, GetResumeUrlsData, GetResumeUrlsResponse, GetSlackApprovalPayloadData, GetSlackApprovalPayloadResponse, ResumeSuspendedJobGetData, ResumeSuspendedJobGetResponse, ResumeSuspendedJobPostData, ResumeSuspendedJobPostResponse, SetFlowUserStateData, SetFlowUserStateResponse, GetFlowUserStateData, GetFlowUserStateResponse, ResumeSuspendedFlowAsOwnerData, ResumeSuspendedFlowAsOwnerResponse, CancelSuspendedJobGetData, CancelSuspendedJobGetResponse, CancelSuspendedJobPostData, CancelSuspendedJobPostResponse, GetSuspendedJobFlowData, GetSuspendedJobFlowResponse, PreviewScheduleData, PreviewScheduleResponse, CreateScheduleData, CreateScheduleResponse, UpdateScheduleData, UpdateScheduleResponse, SetScheduleEnabledData, SetScheduleEnabledResponse, DeleteScheduleData, DeleteScheduleResponse, GetScheduleData, GetScheduleResponse, ExistsScheduleData, ExistsScheduleResponse, ListSchedulesData, ListSchedulesResponse, ListSchedulesWithJobsData, ListSchedulesWithJobsResponse, SetDefaultErrorOrRecoveryHandlerData, SetDefaultErrorOrRecoveryHandlerResponse, CreateHttpTriggerData, CreateHttpTriggerResponse, UpdateHttpTriggerData, UpdateHttpTriggerResponse, DeleteHttpTriggerData, DeleteHttpTriggerResponse, GetHttpTriggerData, GetHttpTriggerResponse, ListHttpTriggersData, ListHttpTriggersResponse, ExistsHttpTriggerData, ExistsHttpTriggerResponse, ExistsRouteData, ExistsRouteResponse, CreateWebsocketTriggerData, CreateWebsocketTriggerResponse, UpdateWebsocketTriggerData, UpdateWebsocketTriggerResponse, DeleteWebsocketTriggerData, DeleteWebsocketTriggerResponse, GetWebsocketTriggerData, GetWebsocketTriggerResponse, ListWebsocketTriggersData, ListWebsocketTriggersResponse, ExistsWebsocketTriggerData, ExistsWebsocketTriggerResponse, SetWebsocketTriggerEnabledData, SetWebsocketTriggerEnabledResponse, TestWebsocketConnectionData, TestWebsocketConnectionResponse, CreateKafkaTriggerData, CreateKafkaTriggerResponse, UpdateKafkaTriggerData, UpdateKafkaTriggerResponse, DeleteKafkaTriggerData, DeleteKafkaTriggerResponse, GetKafkaTriggerData, GetKafkaTriggerResponse, ListKafkaTriggersData, ListKafkaTriggersResponse, ExistsKafkaTriggerData, ExistsKafkaTriggerResponse, SetKafkaTriggerEnabledData, SetKafkaTriggerEnabledResponse, TestKafkaConnectionData, TestKafkaConnectionResponse, CreateNatsTriggerData, CreateNatsTriggerResponse, UpdateNatsTriggerData, UpdateNatsTriggerResponse, DeleteNatsTriggerData, DeleteNatsTriggerResponse, GetNatsTriggerData, GetNatsTriggerResponse, ListNatsTriggersData, ListNatsTriggersResponse, ExistsNatsTriggerData, ExistsNatsTriggerResponse, SetNatsTriggerEnabledData, SetNatsTriggerEnabledResponse, TestNatsConnectionData, TestNatsConnectionResponse, CreateSqsTriggerData, CreateSqsTriggerResponse, UpdateSqsTriggerData, UpdateSqsTriggerResponse, DeleteSqsTriggerData, DeleteSqsTriggerResponse, GetSqsTriggerData, GetSqsTriggerResponse, ListSqsTriggersData, ListSqsTriggersResponse, ExistsSqsTriggerData, ExistsSqsTriggerResponse, SetSqsTriggerEnabledData, SetSqsTriggerEnabledResponse, TestSqsConnectionData, TestSqsConnectionResponse, CreateMqttTriggerData, CreateMqttTriggerResponse, UpdateMqttTriggerData, UpdateMqttTriggerResponse, DeleteMqttTriggerData, DeleteMqttTriggerResponse, GetMqttTriggerData, GetMqttTriggerResponse, ListMqttTriggersData, ListMqttTriggersResponse, ExistsMqttTriggerData, ExistsMqttTriggerResponse, SetMqttTriggerEnabledData, SetMqttTriggerEnabledResponse, TestMqttConnectionData, TestMqttConnectionResponse, CreateGcpTriggerData, CreateGcpTriggerResponse, UpdateGcpTriggerData, UpdateGcpTriggerResponse, DeleteGcpTriggerData, DeleteGcpTriggerResponse, GetGcpTriggerData, GetGcpTriggerResponse, ListGcpTriggersData, ListGcpTriggersResponse, ExistsGcpTriggerData, ExistsGcpTriggerResponse, SetGcpTriggerEnabledData, SetGcpTriggerEnabledResponse, TestGcpConnectionData, TestGcpConnectionResponse, DeleteGcpSubscriptionData, DeleteGcpSubscriptionResponse, ListGoogleTopicsData, ListGoogleTopicsResponse, ListAllTgoogleTopicSubscriptionsData, ListAllTgoogleTopicSubscriptionsResponse, IsValidPostgresConfigurationData, IsValidPostgresConfigurationResponse, CreateTemplateScriptData, CreateTemplateScriptResponse, GetTemplateScriptData, GetTemplateScriptResponse, ListPostgresReplicationSlotData, ListPostgresReplicationSlotResponse, CreatePostgresReplicationSlotData, CreatePostgresReplicationSlotResponse, DeletePostgresReplicationSlotData, DeletePostgresReplicationSlotResponse, ListPostgresPublicationData, ListPostgresPublicationResponse, GetPostgresPublicationData, GetPostgresPublicationResponse, CreatePostgresPublicationData, CreatePostgresPublicationResponse, UpdatePostgresPublicationData, UpdatePostgresPublicationResponse, DeletePostgresPublicationData, DeletePostgresPublicationResponse, CreatePostgresTriggerData, CreatePostgresTriggerResponse, UpdatePostgresTriggerData, UpdatePostgresTriggerResponse, DeletePostgresTriggerData, DeletePostgresTriggerResponse, GetPostgresTriggerData, GetPostgresTriggerResponse, ListPostgresTriggersData, ListPostgresTriggersResponse, ExistsPostgresTriggerData, ExistsPostgresTriggerResponse, SetPostgresTriggerEnabledData, SetPostgresTriggerEnabledResponse, TestPostgresConnectionData, TestPostgresConnectionResponse, ListInstanceGroupsResponse, GetInstanceGroupData, GetInstanceGroupResponse, CreateInstanceGroupData, CreateInstanceGroupResponse, UpdateInstanceGroupData, UpdateInstanceGroupResponse, DeleteInstanceGroupData, DeleteInstanceGroupResponse, AddUserToInstanceGroupData, AddUserToInstanceGroupResponse, RemoveUserFromInstanceGroupData, RemoveUserFromInstanceGroupResponse, ExportInstanceGroupsResponse, OverwriteInstanceGroupsData, OverwriteInstanceGroupsResponse, ListGroupsData, ListGroupsResponse, ListGroupNamesData, ListGroupNamesResponse, CreateGroupData, CreateGroupResponse, UpdateGroupData, UpdateGroupResponse, DeleteGroupData, DeleteGroupResponse, GetGroupData, GetGroupResponse, AddUserToGroupData, AddUserToGroupResponse, RemoveUserToGroupData, RemoveUserToGroupResponse, ListFoldersData, ListFoldersResponse, ListFolderNamesData, ListFolderNamesResponse, CreateFolderData, CreateFolderResponse, UpdateFolderData, UpdateFolderResponse, DeleteFolderData, DeleteFolderResponse, GetFolderData, GetFolderResponse, ExistsFolderData, ExistsFolderResponse, GetFolderUsageData, GetFolderUsageResponse, AddOwnerToFolderData, AddOwnerToFolderResponse, RemoveOwnerToFolderData, RemoveOwnerToFolderResponse, ListWorkersData, ListWorkersResponse, ExistsWorkerWithTagData, ExistsWorkerWithTagResponse, GetQueueMetricsResponse, GetCountsOfJobsWaitingPerTagResponse, ListWorkerGroupsResponse, GetConfigData, GetConfigResponse, UpdateConfigData, UpdateConfigResponse, DeleteConfigData, DeleteConfigResponse, ListConfigsResponse, ListAutoscalingEventsData, ListAutoscalingEventsResponse, GetGranularAclsData, GetGranularAclsResponse, AddGranularAclsData, AddGranularAclsResponse, RemoveGranularAclsData, RemoveGranularAclsResponse, SetCaptureConfigData, SetCaptureConfigResponse, PingCaptureConfigData, PingCaptureConfigResponse, GetCaptureConfigsData, GetCaptureConfigsResponse, ListCapturesData, ListCapturesResponse, MoveCapturesAndConfigsData, MoveCapturesAndConfigsResponse, GetCaptureData, GetCaptureResponse, DeleteCaptureData, DeleteCaptureResponse, StarData, StarResponse, UnstarData, UnstarResponse, GetInputHistoryData, GetInputHistoryResponse, GetArgsFromHistoryOrSavedInputData, GetArgsFromHistoryOrSavedInputResponse, ListInputsData, ListInputsResponse, CreateInputData, CreateInputResponse, UpdateInputData, UpdateInputResponse, DeleteInputData, DeleteInputResponse, DuckdbConnectionSettingsData, DuckdbConnectionSettingsResponse, DuckdbConnectionSettingsV2Data, DuckdbConnectionSettingsV2Response, PolarsConnectionSettingsData, PolarsConnectionSettingsResponse, PolarsConnectionSettingsV2Data, PolarsConnectionSettingsV2Response, S3ResourceInfoData, S3ResourceInfoResponse, DatasetStorageTestConnectionData, DatasetStorageTestConnectionResponse, ListStoredFilesData, ListStoredFilesResponse, LoadFileMetadataData, LoadFileMetadataResponse, LoadFilePreviewData, LoadFilePreviewResponse, LoadParquetPreviewData, LoadParquetPreviewResponse, LoadTableRowCountData, LoadTableRowCountResponse, LoadCsvPreviewData, LoadCsvPreviewResponse, DeleteS3FileData, DeleteS3FileResponse, MoveS3FileData, MoveS3FileResponse, FileUploadData, FileUploadResponse, FileDownloadData, FileDownloadResponse, FileDownloadParquetAsCsvData, FileDownloadParquetAsCsvResponse, GetJobMetricsData, GetJobMetricsResponse, SetJobProgressData, SetJobProgressResponse, GetJobProgressData, GetJobProgressResponse, ListLogFilesData, ListLogFilesResponse, GetLogFileData, GetLogFileResponse, ListConcurrencyGroupsResponse, DeleteConcurrencyGroupData, DeleteConcurrencyGroupResponse, GetConcurrencyKeyData, GetConcurrencyKeyResponse, ListExtendedJobsData, ListExtendedJobsResponse, SearchJobsIndexData, SearchJobsIndexResponse, SearchLogsIndexData, SearchLogsIndexResponse, CountSearchLogsIndexData, CountSearchLogsIndexResponse, ClearIndexData, ClearIndexResponse } from './types.gen.ts'; /** * get backend version @@ -351,6 +351,16 @@ export const deleteUser = (data: DeleteUserData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/github_app/connected_repositories' +}); }; + /** * list all workspaces visible to me * @returns Workspace all workspaces @@ -771,6 +781,97 @@ export const whoami = (data: WhoamiData): CancelablePromise => { } }); }; +/** + * get github app token + * @param data The data for the request. + * @param data.workspace + * @param data.requestBody jwt job token + * @returns unknown github app token + * @throws ApiError + */ +export const getGithubAppToken = (data: GetGithubAppTokenData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/github_app/token', + path: { + workspace: data.workspace + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * Install a GitHub installation from another workspace + * @param data The data for the request. + * @param data.workspace + * @param data.requestBody + * @returns unknown Installation successfully copied + * @throws ApiError + */ +export const installFromWorkspace = (data: InstallFromWorkspaceData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/github_app/install_from_workspace', + path: { + workspace: data.workspace + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * Delete a GitHub installation from a workspace + * Removes a GitHub installation from the specified workspace. Requires admin privileges. + * @param data The data for the request. + * @param data.workspace + * @param data.installationId The ID of the GitHub installation to delete + * @returns unknown Installation successfully deleted + * @throws ApiError + */ +export const deleteFromWorkspace = (data: DeleteFromWorkspaceData): CancelablePromise => { return __request(OpenAPI, { + method: 'DELETE', + url: '/w/{workspace}/github_app/installation/{installation_id}', + path: { + workspace: data.workspace, + installation_id: data.installationId + } +}); }; + +/** + * Export GitHub installation JWT token + * Exports the JWT token for a specific GitHub installation in the workspace + * @param data The data for the request. + * @param data.workspace + * @param data.installationId + * @returns unknown Successfully exported the JWT token + * @throws ApiError + */ +export const exportInstallation = (data: ExportInstallationData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/github_app/export/{installationId}', + path: { + workspace: data.workspace, + installationId: data.installationId + } +}); }; + +/** + * Import GitHub installation from JWT token + * Imports a GitHub installation from a JWT token exported from another instance + * @param data The data for the request. + * @param data.workspace + * @param data.requestBody + * @returns unknown Successfully imported the installation + * @throws ApiError + */ +export const importInstallation = (data: ImportInstallationData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/github_app/import', + path: { + workspace: data.workspace + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + /** * accept invite to workspace * @param data The data for the request. @@ -1127,24 +1228,6 @@ export const getPremiumInfo = (data: GetPremiumInfoData): CancelablePromise => { return __request(OpenAPI, { - method: 'POST', - url: '/w/{workspace}/workspaces/set_automatic_billing', - path: { - workspace: data.workspace - }, - body: data.requestBody, - mediaType: 'application/json' -}); }; - /** * get threshold alert info * @param data The data for the request. @@ -1374,7 +1457,7 @@ export const editCopilotConfig = (data: EditCopilotConfigData): CancelablePromis * get copilot info * @param data The data for the request. * @param data.workspace - * @returns unknown status + * @returns AIConfig status * @throws ApiError */ export const getCopilotInfo = (data: GetCopilotInfoData): CancelablePromise => { return __request(OpenAPI, { @@ -3120,6 +3203,23 @@ export const getScriptHistoryByPath = (data: GetScriptHistoryByPathData): Cancel } }); }; +/** + * list script paths using provided script as a relative import + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @returns string list of script paths + * @throws ApiError + */ +export const listScriptPathsFromWorkspaceRunnable = (data: ListScriptPathsFromWorkspaceRunnableData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/scripts/list_paths_from_workspace_runnable/{path}', + path: { + workspace: data.workspace, + path: data.path + } +}); }; + /** * get scripts's latest version (hash) * @param data The data for the request. @@ -4119,6 +4219,25 @@ export const getAppLatestVersion = (data: GetAppLatestVersionData): CancelablePr } }); }; +/** + * list app paths from workspace runnable + * @param data The data for the request. + * @param data.workspace + * @param data.runnableKind + * @param data.path + * @returns string list of app paths + * @throws ApiError + */ +export const listAppPathsFromWorkspaceRunnable = (data: ListAppPathsFromWorkspaceRunnableData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/apps/list_paths_from_workspace_runnable/{runnable_kind}/{path}', + path: { + workspace: data.workspace, + runnable_kind: data.runnableKind, + path: data.path + } +}); }; + /** * update app history * @param data The data for the request. @@ -4634,6 +4753,7 @@ export const runFlowPreview = (data: RunFlowPreviewData): CancelablePromise in postgres) * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.tag filter on jobs with a given tag/worker group * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) @@ -4666,6 +4786,7 @@ export const listQueue = (data: ListQueueData): CancelablePromise in postgres) * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.tag filter on jobs with a given tag/worker group * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) @@ -4785,6 +4907,7 @@ export const listFilteredUuids = (data: ListFilteredUuidsData): CancelablePromis running: data.running, args: data.args, result: data.result, + allow_wildcards: data.allowWildcards, tag: data.tag, page: data.page, per_page: data.perPage, @@ -4831,6 +4954,7 @@ export const cancelSelection = (data: CancelSelectionData): CancelablePromise in postgres) * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.tag filter on jobs with a given tag/worker group * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) @@ -4863,6 +4987,7 @@ export const listCompletedJobs = (data: ListCompletedJobsData): CancelablePromis job_kinds: data.jobKinds, args: data.args, result: data.result, + allow_wildcards: data.allowWildcards, tag: data.tag, page: data.page, per_page: data.perPage, @@ -4899,6 +5024,7 @@ export const listCompletedJobs = (data: ListCompletedJobsData): CancelablePromis * @param data.args filter on jobs containing those args as a json subset (@> in postgres) * @param data.tag filter on jobs with a given tag/worker group * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) * @param data.isSkipped is the job skipped @@ -4939,6 +5065,7 @@ export const listJobs = (data: ListJobsData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/create', + path: { + workspace: data.workspace + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * update gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @param data.requestBody updated trigger + * @returns string gcp trigger updated + * @throws ApiError + */ +export const updateGcpTrigger = (data: UpdateGcpTriggerData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/update/{path}', + path: { + workspace: data.workspace, + path: data.path + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * delete gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @returns string gcp trigger deleted + * @throws ApiError + */ +export const deleteGcpTrigger = (data: DeleteGcpTriggerData): CancelablePromise => { return __request(OpenAPI, { + method: 'DELETE', + url: '/w/{workspace}/gcp_triggers/delete/{path}', + path: { + workspace: data.workspace, + path: data.path + } +}); }; + +/** + * get gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @returns GcpTrigger gcp trigger deleted + * @throws ApiError + */ +export const getGcpTrigger = (data: GetGcpTriggerData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/gcp_triggers/get/{path}', + path: { + workspace: data.workspace, + path: data.path + } +}); }; + +/** + * list gcp triggers + * @param data The data for the request. + * @param data.workspace + * @param data.page which page to return (start at 1, default 1) + * @param data.perPage number of items to return for a given page (default 30, max 100) + * @param data.path filter by path + * @param data.isFlow + * @param data.pathStart + * @returns GcpTrigger gcp trigger list + * @throws ApiError + */ +export const listGcpTriggers = (data: ListGcpTriggersData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/gcp_triggers/list', + path: { + workspace: data.workspace + }, + query: { + page: data.page, + per_page: data.perPage, + path: data.path, + is_flow: data.isFlow, + path_start: data.pathStart + } +}); }; + +/** + * does gcp trigger exists + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @returns boolean gcp trigger exists + * @throws ApiError + */ +export const existsGcpTrigger = (data: ExistsGcpTriggerData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/gcp_triggers/exists/{path}', + path: { + workspace: data.workspace, + path: data.path + } +}); }; + +/** + * set enabled gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @param data.requestBody updated gcp trigger enable + * @returns string gcp trigger enabled set + * @throws ApiError + */ +export const setGcpTriggerEnabled = (data: SetGcpTriggerEnabledData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/setenabled/{path}', + path: { + workspace: data.workspace, + path: data.path + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * test gcp connection + * @param data The data for the request. + * @param data.workspace + * @param data.requestBody test gcp connection + * @returns string try to connect to a gcp broker + * @throws ApiError + */ +export const testGcpConnection = (data: TestGcpConnectionData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/test', + path: { + workspace: data.workspace + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * delete gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @param data.requestBody args to delete subscription from google cloud + * @returns string gcp trigger deleted + * @throws ApiError + */ +export const deleteGcpSubscription = (data: DeleteGcpSubscriptionData): CancelablePromise => { return __request(OpenAPI, { + method: 'DELETE', + url: '/w/{workspace}/gcp_triggers/subscriptions/delete/{path}', + path: { + workspace: data.workspace, + path: data.path + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * list all topics of google cloud service + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @returns string get all google topics + * @throws ApiError + */ +export const listGoogleTopics = (data: ListGoogleTopicsData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/gcp_triggers/topics/list/{path}', + path: { + workspace: data.workspace, + path: data.path + } +}); }; + +/** + * list all subscription of a give topic from google cloud service + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @param data.requestBody args to get subscription's topic from google cloud + * @returns string get all google topic subscriptions name + * @throws ApiError + */ +export const listAllTgoogleTopicSubscriptions = (data: ListAllTgoogleTopicSubscriptionsData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/subscriptions/list/{path}', + path: { + workspace: data.workspace, + path: data.path + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + /** * check if postgres configuration is set to logical * @param data The data for the request. @@ -8527,6 +8865,7 @@ export const getConcurrencyKey = (data: GetConcurrencyKeyData): CancelablePromis * @param data.args filter on jobs containing those args as a json subset (@> in postgres) * @param data.tag filter on jobs with a given tag/worker group * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) * @param data.isSkipped is the job skipped @@ -8565,6 +8904,7 @@ export const listExtendedJobs = (data: ListExtendedJobsData): CancelablePromise< args: data.args, tag: data.tag, result: data.result, + allow_wildcards: data.allowWildcards, page: data.page, per_page: data.perPage, is_skipped: data.isSkipped, diff --git a/cli/gen/types.gen.ts b/cli/gen/types.gen.ts index 13d30a5967..a7924d0b90 100644 --- a/cli/gen/types.gen.ts +++ b/cli/gen/types.gen.ts @@ -1,12 +1,25 @@ // This file is auto-generated by @hey-api/openapi-ts -export type AIProvider = 'openai' | 'anthropic' | 'mistral' | 'deepseek' | 'googleai' | 'groq' | 'openrouter' | 'customai'; +export type AIProvider = 'openai' | 'azure_openai' | 'anthropic' | 'mistral' | 'deepseek' | 'googleai' | 'groq' | 'openrouter' | 'togetherai' | 'customai'; -export type AIResource = { - path: string; +export type AIProviderModel = { + model: string; provider: AIProvider; }; +export type AIProviderConfig = { + resource_path: string; + models: Array<(string)>; +}; + +export type AIConfig = { + providers?: { + [key: string]: AIProviderConfig; + }; + default_model?: AIProviderModel; + code_completion_model?: AIProviderModel; +}; + export type Script = { workspace_id?: string; hash: string; @@ -376,7 +389,7 @@ export type MainArgSignature = { export type type2 = 'Valid' | 'Invalid'; -export type ScriptLang = 'python3' | 'deno' | 'go' | 'bash' | 'powershell' | 'postgresql' | 'mysql' | 'bigquery' | 'snowflake' | 'mssql' | 'oracledb' | 'graphql' | 'nativets' | 'bun' | 'php' | 'rust' | 'ansible' | 'csharp' | 'nu'; +export type ScriptLang = 'python3' | 'deno' | 'go' | 'bash' | 'powershell' | 'postgresql' | 'mysql' | 'bigquery' | 'snowflake' | 'mssql' | 'oracledb' | 'graphql' | 'nativets' | 'bun' | 'php' | 'rust' | 'ansible' | 'csharp' | 'nu' | 'java'; export type Preview = { content?: string; @@ -494,6 +507,7 @@ export type Schedule = { ws_error_handler_muted?: boolean; retry?: Retry; summary?: string; + description?: string; no_flow_overlap?: boolean; tag?: string; paused_until?: string; @@ -529,6 +543,7 @@ export type NewSchedule = { retry?: Retry; no_flow_overlap?: boolean; summary?: string; + description?: string; tag?: string; paused_until?: string; cron_version?: string; @@ -551,6 +566,7 @@ export type EditSchedule = { retry?: Retry; no_flow_overlap?: boolean; summary?: string; + description?: string; tag?: string; paused_until?: string; cron_version?: string; @@ -569,6 +585,8 @@ export type TriggerExtraProperty = { is_flow: boolean; }; +export type AuthenticationMethod = 'none' | 'windmill' | 'api_key' | 'basic_http' | 'custom_script' | 'signature'; + export type HttpTrigger = TriggerExtraProperty & { route_path: string; static_asset_config?: { @@ -577,8 +595,9 @@ export type HttpTrigger = TriggerExtraProperty & { filename?: string; }; http_method: 'get' | 'post' | 'put' | 'delete' | 'patch'; + authentication_resource_path?: string; is_async: boolean; - requires_auth: boolean; + authentication_method: AuthenticationMethod; is_static_website: boolean; workspaced_route: boolean; wrap_body: boolean; @@ -599,8 +618,9 @@ export type NewHttpTrigger = { }; is_flow: boolean; http_method: 'get' | 'post' | 'put' | 'delete' | 'patch'; + authentication_resource_path?: string; is_async: boolean; - requires_auth: boolean; + authentication_method: AuthenticationMethod; is_static_website: boolean; wrap_body?: boolean; raw_string?: boolean; @@ -616,10 +636,11 @@ export type EditHttpTrigger = { storage?: string; filename?: string; }; + authentication_resource_path?: string; is_flow: boolean; http_method: 'get' | 'post' | 'put' | 'delete' | 'patch'; is_async: boolean; - requires_auth: boolean; + authentication_method: AuthenticationMethod; is_static_website: boolean; wrap_body?: boolean; raw_string?: boolean; @@ -638,6 +659,7 @@ export type TriggersCount = { kafka_count?: number; nats_count?: number; mqtt_count?: number; + gcp_count?: number; sqs_count?: number; }; @@ -753,6 +775,80 @@ export type EditMqttTrigger = { enabled: boolean; }; +export type DeliveryType = 'push' | 'pull'; + +export type PushConfig = { + audience?: string; + authenticate: boolean; + base_endpoint: string; +}; + +export type GcpTrigger = TriggerExtraProperty & { + gcp_resource_path: string; + topic_id: string; + subscription_id: string; + server_id?: string; + delivery_type: DeliveryType; + delivery_config?: PushConfig; + last_server_ping?: string; + error?: string; + enabled: boolean; +}; + +/** + * The mode of subscription. 'existing' means using an existing GCP subscription, while 'create_update' involves creating or updating a new subscription. + */ +export type SubscriptionMode = 'existing' | 'create_update'; + +export type GcpExistingSubscription = { + subscription_id: string; + base_endpoint: string; +}; + +export type GcpCreateUpdateSubscription = { + subscription_id?: string; + delivery_type: DeliveryType; + delivery_config?: PushConfig; +}; + +/** + * "This is a union type representing the subscription mode. + * - 'existing': Represents an existing GCP subscription, and should be accompanied by an 'ExistingGcpSubscription' object. + * - 'create_update': Represents a new or updated GCP subscription, and should be accompanied by a 'CreateUpdateConfig' object." + * + */ +export type GcpSubscriptionModeConfig = (GcpExistingSubscription | GcpCreateUpdateSubscription) & { + subscription_mode: SubscriptionMode; +}; + +export type NewGcpTrigger = { + gcp_resource_path: string; + topic_id: string; + subscription_mode: GcpSubscriptionModeConfig; + path: string; + script_path: string; + is_flow: boolean; + enabled?: boolean; +}; + +export type EditGcpTrigger = { + gcp_resource_path?: string; + topic_id: string; + subscription_mode: GcpSubscriptionModeConfig; + path: string; + script_path: string; + is_flow: boolean; + enabled: boolean; +}; + +export type GetAllTopicSubscription = { + topic_id: string; +}; + +export type DeleteGcpSubscription = { + subscription_id: string; +}; + export type SqsTrigger = TriggerExtraProperty & { queue_url: string; aws_resource_path: string; @@ -1363,7 +1459,7 @@ export type CriticalAlert = { workspace_id?: (string) | null; }; -export type CaptureTriggerKind = 'webhook' | 'http' | 'websocket' | 'kafka' | 'email' | 'nats' | 'postgres' | 'sqs' | 'mqtt'; +export type CaptureTriggerKind = 'webhook' | 'http' | 'websocket' | 'kafka' | 'email' | 'nats' | 'postgres' | 'sqs' | 'mqtt' | 'gcp'; export type Capture = { trigger_kind: CaptureTriggerKind; @@ -1453,6 +1549,21 @@ export type ChannelInfo = { service_url: string; }; +export type GithubInstallations = Array<{ + workspace_id?: string; + installation_id: number; + account_id: string; + repositories: Array<{ + name: string; + url: string; + }>; +}>; + +export type WorkspaceGithubInstallation = { + account_id: string; + installation_id: number; +}; + export type OpenFlow = { summary: string; description?: string; @@ -1853,6 +1964,11 @@ export type ParameterSuspended = boolean; */ export type ParameterRunning = boolean; +/** + * allow wildcards (*) in the filter of label, tag, worker + */ +export type ParameterAllowWildcards = boolean; + /** * filter on jobs containing those args as a json subset (@> in postgres) */ @@ -2123,6 +2239,8 @@ export type DeleteUserData = { export type DeleteUserResponse = (string); +export type GetGlobalConnectedRepositoriesResponse = (GithubInstallations); + export type ListWorkspacesResponse = (Array); export type IsDomainAllowedResponse = (boolean); @@ -2351,6 +2469,64 @@ export type WhoamiData = { export type WhoamiResponse = (User); +export type GetGithubAppTokenData = { + /** + * jwt job token + */ + requestBody: { + job_token: string; + }; + workspace: string; +}; + +export type GetGithubAppTokenResponse = ({ + token: string; +}); + +export type InstallFromWorkspaceData = { + requestBody: { + /** + * The ID of the workspace containing the installation to copy + */ + source_workspace_id: string; + /** + * The ID of the GitHub installation to copy + */ + installation_id: number; + }; + workspace: string; +}; + +export type InstallFromWorkspaceResponse = (unknown); + +export type DeleteFromWorkspaceData = { + /** + * The ID of the GitHub installation to delete + */ + installationId: number; + workspace: string; +}; + +export type DeleteFromWorkspaceResponse = (unknown); + +export type ExportInstallationData = { + installationId: number; + workspace: string; +}; + +export type ExportInstallationResponse = ({ + jwt_token?: string; +}); + +export type ImportInstallationData = { + requestBody: { + jwt_token: string; + }; + workspace: string; +}; + +export type ImportInstallationResponse = (unknown); + export type AcceptInviteData = { /** * accept invite @@ -2534,13 +2710,10 @@ export type GetSettingsResponse = ({ auto_invite_operator?: boolean; auto_add?: boolean; plan?: string; - automatic_billing: boolean; customer_id?: string; webhook?: string; deploy_to?: string; - ai_resource?: AIResource; - code_completion_model?: string; - ai_models: Array<(string)>; + ai_config?: AIConfig; error_handler?: string; error_handler_extra_args?: ScriptArgs; error_handler_muted_on_cancel: boolean; @@ -2575,24 +2748,10 @@ export type GetPremiumInfoData = { export type GetPremiumInfoResponse = ({ premium: boolean; usage?: number; - seats?: number; - automatic_billing: boolean; owner: string; + status?: string; }); -export type SetAutomaticBillingData = { - /** - * automatic billing - */ - requestBody: { - automatic_billing: boolean; - seats?: number; - }; - workspace: string; -}; - -export type SetAutomaticBillingResponse = (string); - export type GetThresholdAlertData = { workspace: string; }; @@ -2742,11 +2901,7 @@ export type EditCopilotConfigData = { /** * WorkspaceCopilotConfig */ - requestBody: { - ai_resource?: AIResource; - code_completion_model?: string; - ai_models: Array<(string)>; - }; + requestBody: AIConfig; workspace: string; }; @@ -2756,12 +2911,7 @@ export type GetCopilotInfoData = { workspace: string; }; -export type GetCopilotInfoResponse = ({ - ai_provider?: AIProvider; - exists_ai_resource: boolean; - code_completion_model?: string; - ai_models: Array<(string)>; -}); +export type GetCopilotInfoResponse = (AIConfig); export type EditErrorHandlerData = { /** @@ -2906,6 +3056,7 @@ export type GetUsedTriggersResponse = ({ nats_used: boolean; postgres_used: boolean; mqtt_used: boolean; + gcp_used: boolean; sqs_used: boolean; }); @@ -3832,6 +3983,13 @@ export type GetScriptHistoryByPathData = { export type GetScriptHistoryByPathResponse = (Array); +export type ListScriptPathsFromWorkspaceRunnableData = { + path: string; + workspace: string; +}; + +export type ListScriptPathsFromWorkspaceRunnableResponse = (Array<(string)>); + export type GetScriptLatestVersionData = { path: string; workspace: string; @@ -4508,6 +4666,14 @@ export type GetAppLatestVersionData = { export type GetAppLatestVersionResponse = (AppHistory); +export type ListAppPathsFromWorkspaceRunnableData = { + path: string; + runnableKind: 'script' | 'flow'; + workspace: string; +}; + +export type ListAppPathsFromWorkspaceRunnableResponse = (Array<(string)>); + export type UpdateAppHistoryData = { id: number; /** @@ -4898,6 +5064,10 @@ export type RunFlowPreviewData = { export type RunFlowPreviewResponse = (string); export type ListQueueData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * get jobs from all workspaces (only valid if request come from the `admins` workspace) */ @@ -5023,6 +5193,10 @@ export type CountCompletedJobsData = { export type CountCompletedJobsResponse = (number); export type ListFilteredUuidsData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * get jobs from all workspaces (only valid if request come from the `admins` workspace) */ @@ -5124,6 +5298,10 @@ export type CancelSelectionData = { export type CancelSelectionResponse = (Array<(string)>); export type ListCompletedJobsData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * filter on jobs containing those args as a json subset (@> in postgres) */ @@ -5218,6 +5396,10 @@ export type ListCompletedJobsData = { export type ListCompletedJobsResponse = (Array); export type ListJobsData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * get jobs from all workspaces (only valid if request come from the `admins` workspace) */ @@ -6281,6 +6463,124 @@ export type TestMqttConnectionData = { export type TestMqttConnectionResponse = (string); +export type CreateGcpTriggerData = { + /** + * new gcp trigger + */ + requestBody: NewGcpTrigger; + workspace: string; +}; + +export type CreateGcpTriggerResponse = (string); + +export type UpdateGcpTriggerData = { + path: string; + /** + * updated trigger + */ + requestBody: EditGcpTrigger; + workspace: string; +}; + +export type UpdateGcpTriggerResponse = (string); + +export type DeleteGcpTriggerData = { + path: string; + workspace: string; +}; + +export type DeleteGcpTriggerResponse = (string); + +export type GetGcpTriggerData = { + path: string; + workspace: string; +}; + +export type GetGcpTriggerResponse = (GcpTrigger); + +export type ListGcpTriggersData = { + isFlow?: boolean; + /** + * which page to return (start at 1, default 1) + */ + page?: number; + /** + * filter by path + */ + path?: string; + pathStart?: string; + /** + * number of items to return for a given page (default 30, max 100) + */ + perPage?: number; + workspace: string; +}; + +export type ListGcpTriggersResponse = (Array); + +export type ExistsGcpTriggerData = { + path: string; + workspace: string; +}; + +export type ExistsGcpTriggerResponse = (boolean); + +export type SetGcpTriggerEnabledData = { + path: string; + /** + * updated gcp trigger enable + */ + requestBody: { + enabled: boolean; + }; + workspace: string; +}; + +export type SetGcpTriggerEnabledResponse = (string); + +export type TestGcpConnectionData = { + /** + * test gcp connection + */ + requestBody: { + connection: { + [key: string]: unknown; + }; + }; + workspace: string; +}; + +export type TestGcpConnectionResponse = (string); + +export type DeleteGcpSubscriptionData = { + path: string; + /** + * args to delete subscription from google cloud + */ + requestBody: DeleteGcpSubscription; + workspace: string; +}; + +export type DeleteGcpSubscriptionResponse = (string); + +export type ListGoogleTopicsData = { + path: string; + workspace: string; +}; + +export type ListGoogleTopicsResponse = (Array<(string)>); + +export type ListAllTgoogleTopicSubscriptionsData = { + path: string; + /** + * args to get subscription's topic from google cloud + */ + requestBody: GetAllTopicSubscription; + workspace: string; +}; + +export type ListAllTgoogleTopicSubscriptionsResponse = (Array<(string)>); + export type IsValidPostgresConfigurationData = { path: string; workspace: string; @@ -6822,7 +7122,7 @@ export type ListAutoscalingEventsData = { export type ListAutoscalingEventsResponse = (Array); export type GetGranularAclsData = { - kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'sqs_trigger'; + kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'gcp_trigger' | 'sqs_trigger'; path: string; workspace: string; }; @@ -6832,7 +7132,7 @@ export type GetGranularAclsResponse = ({ }); export type AddGranularAclsData = { - kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'sqs_trigger'; + kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'gcp_trigger' | 'sqs_trigger'; path: string; /** * acl to add @@ -6847,7 +7147,7 @@ export type AddGranularAclsData = { export type AddGranularAclsResponse = (string); export type RemoveGranularAclsData = { - kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'sqs_trigger'; + kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'gcp_trigger' | 'sqs_trigger'; path: string; /** * acl to add @@ -6875,7 +7175,9 @@ export type SetCaptureConfigData = { workspace: string; }; -export type SetCaptureConfigResponse = (unknown); +export type SetCaptureConfigResponse = ({ + [key: string]: unknown; +}); export type PingCaptureConfigData = { path: string; @@ -7347,6 +7649,10 @@ export type GetConcurrencyKeyData = { export type GetConcurrencyKeyResponse = (string); export type ListExtendedJobsData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * get jobs from all workspaces (only valid if request come from the `admins` workspace) */ diff --git a/cli/hub.ts b/cli/hub.ts index 915acadf88..6943369ec0 100644 --- a/cli/hub.ts +++ b/cli/hub.ts @@ -7,6 +7,16 @@ import { pushResourceType } from "./resource-type.ts"; import { GlobalOptions } from "./types.ts"; import { deepEqual } from "./utils.ts"; +const DEFAULT_HUB_BASE_URL = "https://hub.windmill.dev"; + +interface HubResourceType { + id: number; + name: string; + schema: string; + app: string; + description: string; +} + export async function pull(opts: GlobalOptions) { const workspace = await resolveWorkspace(opts); @@ -25,8 +35,8 @@ export async function pull(opts: GlobalOptions) { const hubBaseUrl = (await wmill.getGlobal({ - key: "hubBaseUrl", - })) ?? "https://hub.windmill.dev"; + key: "hub_base_url", + })) ?? DEFAULT_HUB_BASE_URL; const headers: Record = { Accept: "application/json", @@ -37,44 +47,15 @@ export async function pull(opts: GlobalOptions) { headers["X-uid"] = uid; } - const list: { - id: number; - name: string; - schema: string; - approved: boolean; - app: string; - description: string; - created_by: string; - created_at: Date; - comments: never[]; - }[] = await fetch(hubBaseUrl + "/resource_types/list", { + let list = await fetch(hubBaseUrl + "/resource_types/list", { headers, - }) - .then((r) => r.json() as Promise<{ id: number; name: string }[]>) - .then((list: { id: number; name: string }[]) => - list.map((x) => - fetch(hubBaseUrl + "/resource_types/" + x.id + "/" + x.name, { - headers: { - Accept: "application/json", - }, - }) - ) - ) - .then((x) => Promise.all(x)) - .then((x) => - x.map((x) => - x.json().catch((e) => { - log.info(e); - return undefined; - }) - ) - ) - .then((x) => Promise.all(x)) - .then((x) => - (x as { resource_type: any }[]) - .filter((x) => x) - .map((x) => x.resource_type) - ); + }).then((r) => r.json() as Promise); + + if (list && list.length === 0 && hubBaseUrl !== DEFAULT_HUB_BASE_URL) { + list = await fetch(DEFAULT_HUB_BASE_URL + "/resource_types/list", { + headers, + }).then((r) => r.json() as Promise); + } const resourceTypes = await wmill.listResourceType({ workspace: workspace.workspaceId, diff --git a/cli/instance.ts b/cli/instance.ts index 5a68f29c30..e3abdb4eaa 100644 --- a/cli/instance.ts +++ b/cli/instance.ts @@ -36,7 +36,6 @@ import { type SimplifiedSettings, } from "./settings.ts"; import { deepEqual } from "./utils.ts"; -import { GlobalOptions } from "./types.ts"; import { getActiveWorkspace } from "./workspace.ts"; export interface Instance { @@ -182,6 +181,7 @@ export type InstanceSyncOptions = { baseUrl?: string; token?: string; folderPerInstance?: boolean; + dryRun?: boolean; yes?: boolean; prefix?: string; prefixSettings?: boolean; @@ -290,6 +290,10 @@ async function instancePull(opts: InstanceSyncOptions) { if (totalChanges > 0) { let confirm = true; + if (opts.dryRun) { + log.info(colors.gray(`Dry run complete.`)); + return; + } if (opts.yes !== true) { confirm = await Confirm.prompt({ message: `Do you want to pull these ${totalChanges} instance-level changes?`, @@ -368,6 +372,7 @@ async function instancePull(opts: InstanceSyncOptions) { includeUsers: true, includeKey: true, yes: opts.yes, + dryRun: opts.dryRun, }); } @@ -535,6 +540,7 @@ async function instancePush(opts: InstanceSyncOptions) { includeUsers: true, includeKey: true, yes: opts.yes, + dryRun: opts.dryRun, }); } @@ -711,6 +717,7 @@ const command = new Command() "Pull instance settings, users, configs, instance groups and overwrite local" ) .option("--yes", "Pull without needing confirmation") + .option("--dry-run", "Perform a dry run without making changes") .option("--skip-users", "Skip pulling users") .option("--skip-settings", "Skip pulling settings") .option("--skip-configs", "Skip pulling configs (worker groups and SMTP)") @@ -735,6 +742,7 @@ const command = new Command() "Push instance settings, users, configs, group and overwrite remote" ) .option("--yes", "Push without needing confirmation") + .option("--dry-run", "Perform a dry run without making changes") .option("--skip-users", "Skip pushing users") .option("--skip-settings", "Skip pushing settings") .option("--skip-configs", "Skip pushing configs (worker groups and SMTP)") diff --git a/cli/main.ts b/cli/main.ts index 969f2c2528..92131ce63b 100644 --- a/cli/main.ts +++ b/cli/main.ts @@ -33,6 +33,7 @@ import { pull, push } from "./sync.ts"; import { add as workspaceAdd } from "./workspace.ts"; import workers from "./workers.ts"; import queues from "./queues.ts"; +import { readLockfile } from "./metadata.ts"; export { flow, @@ -62,7 +63,7 @@ export { // } // }); -export const VERSION = "1.478.1"; +export const VERSION = "1.481.0"; const command = new Command() .name("wmill") @@ -96,24 +97,25 @@ const command = new Command() .command("init", "Bootstrap a windmill project with a wmill.yaml file") .action(async () => { if (await Deno.stat("wmill.yaml").catch(() => null)) { - log.error(colors.red("wmill.yaml already exists")); - return; + log.error(colors.green("wmill.yaml already exists")); + } else { + await Deno.writeTextFile( + "wmill.yaml", + yamlStringify({ + defaultTs: "bun", + includes: ["f/**"], + excludes: [], + codebases: [], + skipVariables: true, + skipResources: true, + skipSecrets: true, + includeSchedules: false, + includeTriggers: false, + }) + ); + log.info(colors.green("wmill.yaml created")); } - await Deno.writeTextFile( - "wmill.yaml", - yamlStringify({ - defaultTs: "bun", - includes: ["f/**"], - excludes: [], - codebases: [], - skipVariables: true, - skipResources: true, - skipSecrets: true, - includeSchedules: false, - includeTriggers: false, - }) - ); - log.info(colors.green("wmill.yaml created")); + await readLockfile(); }) .command("app", app) .command("flow", flow) diff --git a/cli/metadata.ts b/cli/metadata.ts index 2f5e536595..3a83143182 100644 --- a/cli/metadata.ts +++ b/cli/metadata.ts @@ -12,8 +12,6 @@ import { ScriptMetadata, defaultScriptMetadata, } from "./bootstrap/script_bootstrap.ts"; - - import { Workspace } from "./workspace.ts"; import { SchemaProperty } from "./bootstrap/common.ts"; import { ScriptLanguage } from "./script_common.ts"; @@ -35,11 +33,11 @@ import { FlowValue } from "./gen/types.gen.ts"; export class LockfileGenerationError extends Error { constructor(message: string) { super(message); - this.name = 'LockfileGenerationError'; + this.name = "LockfileGenerationError"; } } -export async function generateAllMetadata() { } +export async function generateAllMetadata() {} function findClosestRawReqs( lang: "bun" | "python3" | "php" | undefined, @@ -261,7 +259,7 @@ export async function generateScriptMetadataInternal( rawReqs ); } else { - metadataParsedContent.lock = ''; + metadataParsedContent.lock = ""; } } else { metadataParsedContent.lock = @@ -371,11 +369,7 @@ async function updateScriptLock( ); } throw new LockfileGenerationError( - `Failed to generate lockfile: ${JSON.stringify( - response, - null, - 2 - )}` + `Failed to generate lockfile: ${JSON.stringify(response, null, 2)}` ); } const lockPath = remotePath + ".script.lock"; @@ -387,7 +381,7 @@ async function updateScriptLock( if (await Deno.stat(lockPath)) { await Deno.remove(lockPath); } - } catch { } + } catch {} metadataContent.lock = ""; } } catch (e) { @@ -429,7 +423,7 @@ export async function updateFlow( | { error: { message: string } } | undefined; if (rawResponse.status != 200) { - const msg = (res as any)?.["error"]?.["message"] + const msg = (res as any)?.["error"]?.["message"]; if (msg) { throw new LockfileGenerationError( `Failed to generate lockfile: ${msg}` @@ -443,7 +437,7 @@ export async function updateFlow( } catch (e) { try { responseText = await rawResponse.text(); - } catch { } + } catch {} throw new Error( `Failed to generate lockfile. Status was: ${rawResponse.statusText}, ${responseText}, ${e}` ); @@ -465,22 +459,26 @@ export async function inferSchema( }> { let inferedSchema: any; if (language === "python3") { - const { parse_python } = await import('./wasm/python/windmill_parser_wasm.js') + const { parse_python } = await import( + "./wasm/python/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_python(content)); } else if (language === "nativets") { - const { parse_deno } = await import('./wasm/ts/windmill_parser_wasm.js') + const { parse_deno } = await import("./wasm/ts/windmill_parser_wasm.js"); inferedSchema = JSON.parse(parse_deno(content)); } else if (language === "bun") { - const { parse_deno } = await import('./wasm/ts/windmill_parser_wasm.js') + const { parse_deno } = await import("./wasm/ts/windmill_parser_wasm.js"); inferedSchema = JSON.parse(parse_deno(content)); } else if (language === "deno") { - const { parse_deno } = await import('./wasm/ts/windmill_parser_wasm.js') + const { parse_deno } = await import("./wasm/ts/windmill_parser_wasm.js"); inferedSchema = JSON.parse(parse_deno(content)); } else if (language === "go") { const { parse_go } = await import("./wasm/go/windmill_parser_wasm.js"); inferedSchema = JSON.parse(parse_go(content)); } else if (language === "mysql") { - const { parse_mysql } = await import("./wasm/regex/windmill_parser_wasm.js"); + const { parse_mysql } = await import( + "./wasm/regex/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_mysql(content)); inferedSchema.args = [ @@ -488,28 +486,36 @@ export async function inferSchema( ...inferedSchema.args, ]; } else if (language === "bigquery") { - const { parse_bigquery } = await import("./wasm/regex/windmill_parser_wasm.js"); + const { parse_bigquery } = await import( + "./wasm/regex/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_bigquery(content)); inferedSchema.args = [ { name: "database", typ: { resource: "bigquery" } }, ...inferedSchema.args, ]; } else if (language === "oracledb") { - const { parse_oracledb } = await import("./wasm/regex/windmill_parser_wasm.js"); + const { parse_oracledb } = await import( + "./wasm/regex/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_oracledb(content)); inferedSchema.args = [ { name: "database", typ: { resource: "oracledb" } }, ...inferedSchema.args, ]; } else if (language === "snowflake") { - const { parse_snowflake } = await import("./wasm/regex/windmill_parser_wasm.js"); + const { parse_snowflake } = await import( + "./wasm/regex/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_snowflake(content)); inferedSchema.args = [ { name: "database", typ: { resource: "snowflake" } }, ...inferedSchema.args, ]; } else if (language === "mssql") { - const { parse_mssql } = await import("./wasm/regex/windmill_parser_wasm.js"); + const { parse_mssql } = await import( + "./wasm/regex/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_mssql(content)); inferedSchema.args = [ { name: "database", typ: { resource: "ms_sql_server" } }, @@ -523,7 +529,9 @@ export async function inferSchema( ...inferedSchema.args, ]; } else if (language === "graphql") { - const { parse_graphql } = await import("./wasm/regex/windmill_parser_wasm.js"); + const { parse_graphql } = await import( + "./wasm/regex/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_graphql(content)); inferedSchema.args = [ { name: "api", typ: { resource: "graphql" } }, @@ -533,7 +541,9 @@ export async function inferSchema( const { parse_bash } = await import("./wasm/regex/windmill_parser_wasm.js"); inferedSchema = JSON.parse(parse_bash(content)); } else if (language === "powershell") { - const { parse_powershell } = await import("./wasm/regex/windmill_parser_wasm.js"); + const { parse_powershell } = await import( + "./wasm/regex/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_powershell(content)); } else if (language === "php") { const { parse_php } = await import("./wasm/php/windmill_parser_wasm.js"); @@ -542,14 +552,22 @@ export async function inferSchema( const { parse_rust } = await import("./wasm/rust/windmill_parser_wasm.js"); inferedSchema = JSON.parse(parse_rust(content)); } else if (language === "csharp") { - const { parse_csharp } = await import("./wasm/csharp/windmill_parser_wasm.js"); + const { parse_csharp } = await import( + "./wasm/csharp/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_csharp(content)); } else if (language === "nu") { const { parse_nu } = await import("./wasm/nu/windmill_parser_wasm.js"); inferedSchema = JSON.parse(parse_nu(content)); } else if (language === "ansible") { - const { parse_ansible } = await import("./wasm/yaml/windmill_parser_wasm.js"); + const { parse_ansible } = await import( + "./wasm/yaml/windmill_parser_wasm.js" + ); inferedSchema = JSON.parse(parse_ansible(content)); + } else if (language === "java") { + const { parse_java } = await import("./wasm/java/windmill_parser_wasm.js"); + inferedSchema = JSON.parse(parse_java(content)); + // for related places search: ADD_NEW_LANG } else { throw new Error("Invalid language: " + language); } @@ -567,10 +585,12 @@ export async function inferSchema( } if (!currentSchema) { - currentSchema = {} + currentSchema = {}; } currentSchema.required = []; - const oldProperties = JSON.parse(JSON.stringify(currentSchema?.properties ?? {})); + const oldProperties = JSON.parse( + JSON.stringify(currentSchema?.properties ?? {}) + ); currentSchema.properties = {}; for (const arg of inferedSchema.args) { @@ -592,7 +612,6 @@ export async function inferSchema( } } - return { schema: currentSchema, has_preprocessor: inferedSchema.has_preprocessor, @@ -618,23 +637,23 @@ export function argSigToJsonSchemaType( | string | { resource: string | null } | { - list: - | (string | { object: { key: string; typ: any }[] }) - | { str: any } - | { object: { key: string; typ: any }[] } - | null; - } + list: + | (string | { object: { key: string; typ: any }[] }) + | { str: any } + | { object: { key: string; typ: any }[] } + | null; + } | { dynselect: string } | { str: string[] | null } | { object: { key: string; typ: any }[] } | { - oneof: [ - { - label: string; - properties: { key: string; typ: any }[]; - } - ]; - }, + oneof: [ + { + label: string; + properties: { key: string; typ: any }[]; + } + ]; + }, oldS: SchemaProperty ): void { const newS: SchemaProperty = { type: "" }; @@ -837,10 +856,10 @@ export async function parseMetadataFile( scriptPath: string, generateMetadataIfMissing: | (GlobalOptions & { - path: string; - workspaceRemote: Workspace; - schemaOnly?: boolean; - }) + path: string; + workspaceRemote: Workspace; + schemaOnly?: boolean; + }) | undefined, globalDeps: GlobalDeps, codebases: SyncCodebase[] @@ -930,7 +949,7 @@ const WMILL_LOCKFILE = "wmill-lock.yaml"; export async function readLockfile(): Promise { try { const read = await yamlParseFile(WMILL_LOCKFILE); - if (typeof read == "object") { + if (typeof read == "object" && read != null) { return read as Lock; } else { throw new Error("Invalid lockfile"); @@ -938,6 +957,8 @@ export async function readLockfile(): Promise { } catch { const lock = { locks: {} }; await Deno.writeTextFile(WMILL_LOCKFILE, yamlStringify(lock, yamlOptions)); + log.info(colors.green("wmill-lock.yaml created")); + return lock; } } diff --git a/cli/schedule.ts b/cli/schedule.ts index 25ffdd5b49..77052e371d 100644 --- a/cli/schedule.ts +++ b/cli/schedule.ts @@ -18,6 +18,7 @@ export interface ScheduleFile { args: any; timezone: string; is_flow: boolean; + enabled: boolean; } async function list(opts: GlobalOptions) { @@ -59,8 +60,11 @@ export async function pushSchedule( log.debug(`Schedule ${path} is up to date`); return; } - log.debug(`Schedule ${path} is not up-to-date, updating...`); + log.debug(`Updating schedule ${path}`); try { + log.info(colors.bold.yellow( + `Updating schedule ${path}` + )); await wmill.updateSchedule({ workspace: workspace, path, @@ -68,12 +72,24 @@ export async function pushSchedule( ...localSchedule, }, }); + if (localSchedule.enabled != schedule.enabled) { + log.info(colors.bold.yellow( + `Schedule ${path} is ${localSchedule.enabled ? "enabled" : "disabled"} locally but not on remote, updating remote` + )); + await wmill.setScheduleEnabled({ + workspace: workspace, + path, + requestBody: { + enabled: localSchedule.enabled, + }, + }); + } } catch (e) { console.error(e.body); throw e; } } else { - console.log(colors.bold.yellow("Creating new schedule: " + path)); + console.log(colors.bold.yellow("Creating new schedule " + path)); try { await wmill.createSchedule({ workspace: workspace, diff --git a/cli/script.ts b/cli/script.ts index 7adbae0837..3896d19c5c 100644 --- a/cli/script.ts +++ b/cli/script.ts @@ -119,7 +119,7 @@ export async function findResourceFile(path: string) { if (validCandidates.length > 1) { throw new Error( "Found two resource files for the same resource" + - validCandidates.join(", ") + validCandidates.join(", ") ); } if (validCandidates.length < 1) { @@ -249,20 +249,20 @@ export async function handleFile( let typed = opts?.skipScriptsMetadata ? undefined : ( - await parseMetadataFile( - remotePath, - opts - ? { - ...opts, - path, - workspaceRemote: workspace, - schemaOnly: codebase ? true : undefined, - } - : undefined, - globalDeps, - codebases - ) - )?.payload; + await parseMetadataFile( + remotePath, + opts + ? { + ...opts, + path, + workspaceRemote: workspace, + schemaOnly: codebase ? true : undefined, + } + : undefined, + globalDeps, + codebases + ) + )?.payload; const workspaceId = workspace.workspaceId; @@ -347,19 +347,19 @@ export async function handleFile( deepEqual(typed.schema, remote.schema) && typed.tag == remote.tag && (typed.ws_error_handler_muted ?? false) == - remote.ws_error_handler_muted && + remote.ws_error_handler_muted && typed.dedicated_worker == remote.dedicated_worker && typed.cache_ttl == remote.cache_ttl && typed.concurrency_time_window_s == - remote.concurrency_time_window_s && + remote.concurrency_time_window_s && typed.concurrent_limit == remote.concurrent_limit && Boolean(typed.restart_unless_cancelled) == - Boolean(remote.restart_unless_cancelled) && + Boolean(remote.restart_unless_cancelled) && Boolean(typed.visible_to_runner_only) == - Boolean(remote.visible_to_runner_only) && + Boolean(remote.visible_to_runner_only) && Boolean(typed.no_main_func) == Boolean(remote.no_main_func) && Boolean(typed.has_preprocessor) == - Boolean(remote.has_preprocessor) && + Boolean(remote.has_preprocessor) && typed.priority == Boolean(remote.priority) && typed.timeout == remote.timeout && //@ts-ignore @@ -450,7 +450,8 @@ async function createScript( }); } catch (e: any) { throw Error( - `Script creation for ${body.path} with parent ${body.parent_hash + `Script creation for ${body.path} with parent ${ + body.parent_hash } was not successful: ${e.body ?? e.message} ` ); } @@ -476,7 +477,8 @@ async function createScript( }); if (req.status != 201) { throw Error( - `Script snapshot creation was not successful: ${req.status} - ${req.statusText + `Script snapshot creation was not successful: ${req.status} - ${ + req.statusText } - ${await req.text()} ` ); } @@ -488,8 +490,8 @@ export async function findContentFile(filePath: string) { const candidates = filePath.endsWith("script.json") ? exts.map((x) => filePath.replace(".script.json", x)) : filePath.endsWith("script.lock") - ? exts.map((x) => filePath.replace(".script.lock", x)) - : exts.map((x) => filePath.replace(".script.yaml", x)); + ? exts.map((x) => filePath.replace(".script.lock", x)) + : exts.map((x) => filePath.replace(".script.yaml", x)); const validCandidates = ( await Promise.all( @@ -508,7 +510,7 @@ export async function findContentFile(filePath: string) { if (validCandidates.length > 1) { throw new Error( "No content path given and more than one candidate found: " + - validCandidates.join(", ") + validCandidates.join(", ") ); } if (validCandidates.length < 1) { @@ -569,6 +571,9 @@ export function filePathExtensionFromContentType( return ".cs"; } else if (language === "nu") { return ".nu"; + } else if (language === "java") { + return ".java"; + // for related places search: ADD_NEW_LANG } else { throw new Error("Invalid language: " + language); } @@ -596,6 +601,9 @@ export const exts = [ ".cs", ".nu", ".playbook.yml", + ".java" + // for related places search: ADD_NEW_LANG + ]; export function removeExtensionToPath(path: string): string { @@ -958,6 +966,10 @@ async function generateMetadata( } } if (hasAny) { + if (opts.dryRun) { + log.info(colors.gray(`Dry run complete.`)); + return; + } if ( !opts.yes && !(await Confirm.prompt({ @@ -1021,6 +1033,7 @@ const command = new Command() ) .arguments("[script:file]") .option("--yes", "Skip confirmation prompt") + .option("--dry-run", "Perform a dry run without making changes") .option("--lock-only", "re-generate only the lock") .option("--schema-only", "re-generate only script schema") .option( diff --git a/cli/script_common.ts b/cli/script_common.ts index 6fbd96ecf1..a41d7dee8c 100644 --- a/cli/script_common.ts +++ b/cli/script_common.ts @@ -17,7 +17,9 @@ export type ScriptLanguage = | "rust" | "csharp" | "nu" - | "ansible"; + | "ansible" + | "java"; + // for related places search: ADD_NEW_LANG export function inferContentTypeFromFilePath( contentPath: string, @@ -63,6 +65,9 @@ export function inferContentTypeFromFilePath( return "ansible"; } else if (contentPath.endsWith(".nu")) { return "nu"; + } else if (contentPath.endsWith(".java")) { + return "java"; + // for related places search: ADD_NEW_LANG } else { throw new Error( "Invalid language: " + contentPath.substring(contentPath.lastIndexOf(".")) diff --git a/cli/settings.ts b/cli/settings.ts index 054763a16b..b31af79d15 100644 --- a/cli/settings.ts +++ b/cli/settings.ts @@ -1,7 +1,7 @@ import process from "node:process"; import { colors, Confirm, log, yamlParseFile, yamlStringify } from "./deps.ts"; import * as wmill from "./gen/services.gen.ts"; -import { AIResource, Config, GlobalSetting } from "./gen/types.gen.ts"; +import { AIConfig, Config, GlobalSetting } from "./gen/types.gen.ts"; import { compareInstanceObjects, InstanceSyncOptions } from "./instance.ts"; import { isSuperset } from "./types.ts"; import { deepEqual } from "./utils.ts"; @@ -20,9 +20,7 @@ export interface SimplifiedSettings { error_handler?: string; error_handler_extra_args?: any; error_handler_muted_on_cancel?: boolean; - ai_resource?: AIResource; - code_completion_model?: string; - ai_models: string[]; + ai_config?: AIConfig; large_file_storage?: any; git_sync?: any; default_app?: string; @@ -80,9 +78,7 @@ export async function pushWorkspaceSettings( error_handler_extra_args: remoteSettings.error_handler_extra_args, error_handler_muted_on_cancel: remoteSettings.error_handler_muted_on_cancel, - ai_resource: remoteSettings.ai_resource, - code_completion_model: remoteSettings.code_completion_model, - ai_models: remoteSettings.ai_models, + ai_config: remoteSettings.ai_config, large_file_storage: remoteSettings.large_file_storage, git_sync: remoteSettings.git_sync, default_app: remoteSettings.default_app, @@ -156,19 +152,11 @@ export async function pushWorkspaceSettings( }); } } - if ( - localSettings.ai_resource != settings.ai_resource || - localSettings.code_completion_model != settings.code_completion_model || - !deepEqual(localSettings.ai_models, settings.ai_models) - ) { + if (!deepEqual(localSettings.ai_config, settings.ai_config)) { log.debug(`Updating copilot settings...`); await wmill.editCopilotConfig({ workspace, - requestBody: { - ai_resource: localSettings.ai_resource, - code_completion_model: localSettings.code_completion_model, - ai_models: localSettings.ai_models, - }, + requestBody: localSettings.ai_config ?? {}, }); } if ( diff --git a/cli/sync.ts b/cli/sync.ts index 6832136e06..f31cf3f328 100644 --- a/cli/sync.ts +++ b/cli/sync.ts @@ -41,6 +41,7 @@ import { SyncCodebase, listSyncCodebases } from "./codebase.ts"; import { generateFlowLockInternal, generateScriptMetadataInternal, + readLockfile, } from "./metadata.ts"; import { FlowModule, OpenFlow, RawScript } from "./gen/types.gen.ts"; import { pushResource } from "./resource.ts"; @@ -117,7 +118,7 @@ async function addCodebaseDigestIfRelevant( const parsed: any = yamlParseContent(path, content); if (parsed && typeof parsed == "object") { if (ignoreCodebaseChanges) { - parsed["codebase"] = undefined + parsed["codebase"] = undefined; } else { parsed["codebase"] = await c.getDigest(); } @@ -342,6 +343,8 @@ export function newPathAssigner(defaultTs: "bun" | "deno"): PathAssigner { else if (language == "csharp") ext = "cs"; else if (language == "nu") ext = "nu"; else if (language == "ansible") ext = "playbook.yml"; + else if (language == "java") ext = "java"; + // for related places search: ADD_NEW_LANG else ext = "no_ext"; return [`${name}.inline_script.`, ext]; @@ -365,12 +368,12 @@ function ZipFSElement( ) ? "flow" : p.endsWith("app.json") - ? "app" - : p.endsWith("script.json") - ? "script" - : p.endsWith("resource.json") - ? "resource" - : "other"; + ? "app" + : p.endsWith("script.json") + ? "script" + : p.endsWith("resource.json") + ? "resource" + : "other"; const isJson = p.endsWith(".json"); @@ -400,7 +403,7 @@ function ZipFSElement( yield { isDirectory: false, path: path.join(finalPath, s.path), - async *getChildren() { }, + async *getChildren() {}, // deno-lint-ignore require-await async getContentText() { return s.content; @@ -411,7 +414,7 @@ function ZipFSElement( yield { isDirectory: false, path: path.join(finalPath, "flow.yaml"), - async *getChildren() { }, + async *getChildren() {}, // deno-lint-ignore require-await async getContentText() { return yamlStringify(flow, yamlOptions); @@ -427,7 +430,7 @@ function ZipFSElement( yield { isDirectory: false, path: path.join(finalPath, s.path), - async *getChildren() { }, + async *getChildren() {}, // deno-lint-ignore require-await async getContentText() { return s.content; @@ -438,7 +441,7 @@ function ZipFSElement( yield { isDirectory: false, path: path.join(finalPath, "app.yaml"), - async *getChildren() { }, + async *getChildren() {}, // deno-lint-ignore require-await async getContentText() { return yamlStringify(app, yamlOptions); @@ -506,7 +509,7 @@ function ZipFSElement( r.push({ isDirectory: false, path: removeSuffix(finalPath, ".json") + ".lock", - async *getChildren() { }, + async *getChildren() {}, // deno-lint-ignore require-await async getContentText() { return lock; @@ -529,7 +532,7 @@ function ZipFSElement( removeSuffix(finalPath, ".resource.json") + ".resource.file." + formatExtension, - async *getChildren() { }, + async *getChildren() {}, // deno-lint-ignore require-await async getContentText() { return fileContent; @@ -590,19 +593,19 @@ export async function* readDirRecursiveWithIgnore( // getContentBytes(): Promise; getContentText(): Promise; }[] = [ - { - path: root.path, - ignored: ignore(root.path, root.isDirectory), - isDirectory: root.isDirectory, - c: root.getChildren, - // getContentBytes(): Promise { - // throw undefined; - // }, - getContentText(): Promise { - throw undefined; - }, + { + path: root.path, + ignored: ignore(root.path, root.isDirectory), + isDirectory: root.isDirectory, + c: root.getChildren, + // getContentBytes(): Promise { + // throw undefined; + // }, + getContentText(): Promise { + throw undefined; }, - ]; + }, + ]; while (stack.length > 0) { const e = stack.pop()!; @@ -657,7 +660,8 @@ export async function elementsToMap( path.endsWith(".nats_trigger" + ext) || path.endsWith(".postgres_trigger" + ext) || path.endsWith(".mqtt_trigger" + ext) || - path.endsWith(".sqs_trigger" + ext)) + path.endsWith(".sqs_trigger" + ext) || + path.endsWith(".gcp_trigger" + ext)) ) continue; if (!skips.includeUsers && path.endsWith(".user" + ext)) continue; @@ -665,7 +669,8 @@ export async function elementsToMap( if (!skips.includeSettings && path === "settings" + ext) continue; if (!skips.includeKey && path === "encryption_key") continue; if (skips.skipResources && path.endsWith(".resource" + ext)) continue; - if (skips.skipResourceTypes && path.endsWith(".resource-type" + ext)) continue; + if (skips.skipResourceTypes && path.endsWith(".resource-type" + ext)) + continue; if (skips.skipVariables && path.endsWith(".variable" + ext)) continue; @@ -689,6 +694,8 @@ export async function elementsToMap( "cs", "yml", "nu", + "java", + // for related places search: ADD_NEW_LANG ].includes(path.split(".").pop() ?? "") && !isFileResource(path) ) @@ -741,9 +748,9 @@ async function compareDynFSElement( ): Promise { const [m1, m2] = els2 ? await Promise.all([ - elementsToMap(els1, ignore, json, skips), - elementsToMap(els2, ignore, json, skips), - ]) + elementsToMap(els1, ignore, json, skips), + elementsToMap(els2, ignore, json, skips), + ]) : [await elementsToMap(els1, ignore, json, skips), {}]; const changes: Change[] = []; @@ -804,7 +811,6 @@ async function compareDynFSElement( continue; } if (!ignoreCodebaseChanges) { - if (before.codebase != undefined) { delete before.codebase; m2[k] = yamlStringify(before, yamlOptions); @@ -831,7 +837,6 @@ async function compareDynFSElement( } } - const remoteCodebase: Record = {}; for (const [k] of Object.entries(m2)) { if (m1[k] === undefined) { @@ -860,7 +865,7 @@ async function compareDynFSElement( continue; } const c = findCodebase(tsFile, codebases); - if (await c?.getDigest() != v) { + if ((await c?.getDigest()) != v) { changes.push({ name: "edited", path: tsFile, @@ -918,7 +923,8 @@ function getOrderFromPath(p: string) { typ == "nats_trigger" || typ == "postgres_trigger" || typ == "mqtt_trigger" || - typ == "sqs_trigger" + typ == "sqs_trigger" || + typ == "gcp_trigger" ) { return 8; } else if (typ == "variable") { @@ -1122,7 +1128,7 @@ export async function pull(opts: GlobalOptions & SyncOptions) { opts.includeGroups, opts.includeSettings, opts.includeKey, - opts.defaultTs, + opts.defaultTs ))!, !opts.json, opts.defaultTs ?? "bun", @@ -1148,6 +1154,10 @@ export async function pull(opts: GlobalOptions & SyncOptions) { ); if (changes.length > 0) { prettyChanges(changes); + if (opts.dryRun) { + log.info(colors.gray(`Dry run complete.`)); + return; + } if ( !opts.yes && !(await Confirm.prompt({ @@ -1263,7 +1273,7 @@ export async function pull(opts: GlobalOptions & SyncOptions) { } } log.info("All local changes pulled, now updating wmill-lock.yaml"); - + await readLockfile(); // ensure wmill-lock.yaml exists const globalDeps = await findGlobalDeps(); const tracker: ChangeTracker = await buildTracker(changes); @@ -1313,8 +1323,8 @@ function prettyChanges(changes: Change[]) { log.info( colors.yellow( `~ ${getTypeStrFromPath(change.path)} ` + - change.path + - (change.codebase ? ` (codebase changed)` : "") + change.path + + (change.codebase ? ` (codebase changed)` : "") ) ); if (change.before != change.after) { @@ -1397,7 +1407,7 @@ export async function push(opts: GlobalOptions & SyncOptions) { opts.includeGroups, opts.includeSettings, opts.includeKey, - opts.defaultTs, + opts.defaultTs ))!, !opts.json, opts.defaultTs ?? "bun", @@ -1405,7 +1415,7 @@ export async function push(opts: GlobalOptions & SyncOptions) { false ); - const local = await FSFSElement(path.join(Deno.cwd(), "",), codebases, false); + const local = await FSFSElement(path.join(Deno.cwd(), ""), codebases, false); const changes = await compareDynFSElement( local, remote, @@ -1419,7 +1429,6 @@ export async function push(opts: GlobalOptions & SyncOptions) { const globalDeps = await findGlobalDeps(); - const tracker: ChangeTracker = await buildTracker(changes); const staleScripts: string[] = []; @@ -1485,6 +1494,10 @@ export async function push(opts: GlobalOptions & SyncOptions) { if (changes.length > 0) { prettyChanges(changes); + if (opts.dryRun) { + log.info(colors.gray(`Dry run complete.`)); + return; + } if ( !opts.yes && !(await Confirm.prompt({ @@ -1523,7 +1536,8 @@ export async function push(opts: GlobalOptions & SyncOptions) { } const groupedChangesArray = Array.from(groupedChanges.entries()); log.info( - `found changes for ${groupedChangesArray.length + `found changes for ${ + groupedChangesArray.length } items with a total of ${groupedChangesArray.reduce( (acc, [_, changes]) => acc + changes.length, 0 @@ -1776,6 +1790,12 @@ export async function push(opts: GlobalOptions & SyncOptions) { path: removeSuffix(target, ".sqs_trigger.json"), }); break; + case "gcp_trigger": + await wmill.deleteGcpTrigger({ + workspace: workspaceId, + path: removeSuffix(target, ".gcp_trigger.json"), + }); + break; case "variable": await wmill.deleteVariable({ workspace: workspaceId, @@ -1836,7 +1856,8 @@ export async function push(opts: GlobalOptions & SyncOptions) { } log.info( colors.bold.green.underline( - `\nDone! All ${changes.length} changes pushed to the remote workspace ${workspace.workspaceId + `\nDone! All ${changes.length} changes pushed to the remote workspace ${ + workspace.workspaceId } named ${workspace.name} (${(performance.now() - start).toFixed(0)}ms)` ) ); @@ -1854,6 +1875,10 @@ const command = new Command() .command("pull") .description("Pull any remote changes and apply them locally.") .option("--yes", "Pull without needing confirmation") + .option( + "--dry-run", + "Show changes that would be pulled without actually pushing" + ) .option("--plain-secrets", "Pull secrets as plain text") .option("--json", "Use JSON instead of YAML") .option("--skip-variables", "Skip syncing variables (including secrets)") @@ -1884,6 +1909,10 @@ const command = new Command() .command("push") .description("Push any local changes and apply them remotely.") .option("--yes", "Push without needing confirmation") + .option( + "--dry-run", + "Show changes that would be pushed without actually pushing" + ) .option("--plain-secrets", "Push secrets as plain text") .option("--json", "Use JSON instead of YAML") .option("--skip-variables", "Skip syncing variables (including secrets)") diff --git a/cli/trigger.ts b/cli/trigger.ts index 15e165e1c8..f099885615 100644 --- a/cli/trigger.ts +++ b/cli/trigger.ts @@ -1,5 +1,6 @@ import * as wmill from "./gen/services.gen.ts"; import { + GcpTrigger, HttpTrigger, KafkaTrigger, MqttTrigger, @@ -27,6 +28,7 @@ type Trigger = { postgres: PostgresTrigger; mqtt: MqttTrigger; sqs: SqsTrigger; + gcp: GcpTrigger }; type TriggerFile = Omit< @@ -60,6 +62,7 @@ async function getTrigger( postgres: wmill.getPostgresTrigger, mqtt: wmill.getMqttTrigger, sqs: wmill.getSqsTrigger, + gcp: wmill.getGcpTrigger }; const triggerFunction = triggerFunctions[triggerType]; @@ -87,6 +90,7 @@ async function updateTrigger( postgres: wmill.updatePostgresTrigger, mqtt: wmill.updateMqttTrigger, sqs: wmill.updateSqsTrigger, + gcp: wmill.updateGcpTrigger }; const triggerFunction = triggerFunctions[triggerType]; await triggerFunction({ workspace, path, requestBody: trigger }); @@ -112,6 +116,7 @@ async function createTrigger( postgres: wmill.createPostgresTrigger, mqtt: wmill.createMqttTrigger, sqs: wmill.createSqsTrigger, + gcp: wmill.createGcpTrigger }; const triggerFunction = triggerFunctions[triggerType]; await triggerFunction({ workspace, path, requestBody: trigger }); @@ -191,7 +196,9 @@ async function list(opts: GlobalOptions) { const sqsTriggers = await wmill.listSqsTriggers({ workspace: workspace.workspaceId, }); - + const gcpTriggers = await wmill.listGcpTriggers({ + workspace: workspace.workspaceId + }) const triggers = [ ...httpTriggers.map((x) => ({ path: x.path, kind: "http" })), ...websocketTriggers.map((x) => ({ path: x.path, kind: "websocket" })), @@ -200,6 +207,7 @@ async function list(opts: GlobalOptions) { ...postgresTriggers.map((x) => ({ path: x.path, kind: "postgres" })), ...mqttTriggers.map((x) => ({ path: x.path, kind: "mqtt" })), ...sqsTriggers.map((x) => ({ path: x.path, kind: "sqs" })), + ...gcpTriggers.map((x) => ({ path: x.path, kind: "gcp" })) ]; new Table() @@ -213,7 +221,7 @@ async function list(opts: GlobalOptions) { function checkIfValidTrigger(kind: string | undefined): kind is TriggerType { if ( kind && - ["http", "websocket", "kafka", "nats", "postgres", "mqtt", "sqs"].includes(kind) + ["http", "websocket", "kafka", "nats", "postgres", "mqtt", "sqs", "gcp"].includes(kind) ) { return true; } else { diff --git a/cli/types.ts b/cli/types.ts index 4ee23508c1..a95be8da98 100644 --- a/cli/types.ts +++ b/cli/types.ts @@ -154,6 +154,8 @@ export async function pushObj( await pushTrigger("mqtt", workspace, p, befObj, newObj); } else if (typeEnding === "sqs_trigger") { await pushTrigger("sqs", workspace, p, befObj, newObj); + } else if (typeEnding === "gcp_trigger") { + await pushTrigger("gcp", workspace, p, befObj, newObj); } else if (typeEnding === "user") { await pushWorkspaceUser(workspace, p, befObj, newObj); } else if (typeEnding === "group") { @@ -203,6 +205,7 @@ export function getTypeStrFromPath( | "postgres_trigger" | "mqtt_trigger" | "sqs_trigger" + | "gcp_trigger" | "user" | "group" | "settings" @@ -227,6 +230,8 @@ export function getTypeStrFromPath( parsed.ext == ".rs" || parsed.ext == ".cs" || parsed.ext == ".nu" || + parsed.ext == ".java" || + // for related places search: ADD_NEW_LANG (parsed.ext == ".yml" && parsed.name.split(".").pop() == "playbook") ) { return "script"; @@ -251,6 +256,7 @@ export function getTypeStrFromPath( typeEnding === "postgres_trigger" || typeEnding === "mqtt_trigger" || typeEnding === "sqs_trigger" || + typeEnding === "gcp_trigger" || typeEnding === "user" || typeEnding === "group" || typeEnding === "settings" || diff --git a/cli/wasm/java/windmill_parser_wasm.d.ts b/cli/wasm/java/windmill_parser_wasm.d.ts new file mode 100644 index 0000000000..bf4d583e0c --- /dev/null +++ b/cli/wasm/java/windmill_parser_wasm.d.ts @@ -0,0 +1,3 @@ +/* tslint:disable */ +/* eslint-disable */ +export function parse_java(code: string): string; diff --git a/cli/wasm/java/windmill_parser_wasm.js b/cli/wasm/java/windmill_parser_wasm.js new file mode 100644 index 0000000000..8dd745d243 --- /dev/null +++ b/cli/wasm/java/windmill_parser_wasm.js @@ -0,0 +1,121 @@ + + +let WASM_VECTOR_LEN = 0; + +let cachedUint8ArrayMemory0 = null; + +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8ArrayMemory0; +} + +const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); + +const encodeString = function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); +}; + +function passStringToWasm0(arg, malloc, realloc) { + + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8ArrayMemory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); + +if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); +} +/** + * @param {string} code + * @returns {string} + */ +export function parse_java(code) { + let deferred2_0; + let deferred2_1; + try { + const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len0 = WASM_VECTOR_LEN; + const ret = wasm.parse_java(ptr0, len0); + deferred2_0 = ret[0]; + deferred2_1 = ret[1]; + return getStringFromWasm0(ret[0], ret[1]); + } finally { + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +const imports = { + __wbindgen_placeholder__: { + __wbindgen_init_externref_table: function() { + const table = wasm.__wbindgen_export_0; + const offset = table.grow(4); + table.set(0, undefined); + table.set(offset + 0, undefined); + table.set(offset + 1, null); + table.set(offset + 2, true); + table.set(offset + 3, false); + ; + }, + }, + +}; + +const wasm_url = new URL('windmill_parser_wasm_bg.wasm', import.meta.url); +let wasmCode = ''; +switch (wasm_url.protocol) { + case 'file:': + wasmCode = await Deno.readFile(wasm_url); + break + case 'https:': + case 'http:': + wasmCode = await (await fetch(wasm_url)).arrayBuffer(); + break + default: + throw new Error(`Unsupported protocol: ${wasm_url.protocol}`); +} + +const wasmInstance = (await WebAssembly.instantiate(wasmCode, imports)).instance; +const wasm = wasmInstance.exports; +export const __wasm = wasm; + +wasm.__wbindgen_start(); + diff --git a/cli/wasm/java/windmill_parser_wasm_bg.wasm b/cli/wasm/java/windmill_parser_wasm_bg.wasm new file mode 100644 index 0000000000..5395c1e789 Binary files /dev/null and b/cli/wasm/java/windmill_parser_wasm_bg.wasm differ diff --git a/cli/wasm/java/windmill_parser_wasm_bg.wasm.d.ts b/cli/wasm/java/windmill_parser_wasm_bg.wasm.d.ts new file mode 100644 index 0000000000..6128cc38c6 --- /dev/null +++ b/cli/wasm/java/windmill_parser_wasm_bg.wasm.d.ts @@ -0,0 +1,29 @@ +/* tslint:disable */ +/* eslint-disable */ +export const memory: WebAssembly.Memory; +export const parse_java: (a: number, b: number) => [number, number]; +export const abort: () => void; +export const malloc: (a: number) => number; +export const calloc: (a: number, b: number) => number; +export const realloc: (a: number, b: number) => number; +export const free: (a: number) => void; +export const strncmp: (a: number, b: number, c: number) => number; +export const iswspace: (a: number) => number; +export const iswalnum: (a: number) => number; +export const clock: () => bigint; +export const isprint: (a: number) => number; +export const fprintf: (a: number, b: number, c: number) => number; +export const fputs: (a: number, b: number) => number; +export const fputc: (a: number, b: number) => number; +export const fdopen: (a: number, b: number) => number; +export const fclose: (a: number) => number; +export const fwrite: (a: number, b: number, c: number, d: number) => number; +export const vsnprintf: (a: number, b: number, c: number, d: number) => number; +export const clock_gettime: (a: number, b: number) => void; +export const snprintf: () => void; +export const __assert_fail: (a: number, b: number, c: number, d: number) => void; +export const __wbindgen_export_0: WebAssembly.Table; +export const __wbindgen_malloc: (a: number, b: number) => number; +export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; +export const __wbindgen_free: (a: number, b: number, c: number) => void; +export const __wbindgen_start: () => void; diff --git a/docker-compose.yml b/docker-compose.yml index a8ac7ba565..82c66a9e69 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -135,9 +135,9 @@ services: replicas: 0 # set to 1 to enable full-text job and log search restart: unless-stopped expose: - - 8001 + - 8002 environment: - - PORT=8001 + - PORT=8002 - DATABASE_URL=${DATABASE_URL} - MODE=indexer depends_on: diff --git a/docker/DockerfileFull b/docker/DockerfileFull index 7f904b01b7..c36682c4e9 100644 --- a/docker/DockerfileFull +++ b/docker/DockerfileFull @@ -14,3 +14,10 @@ ENV DOTNET_ROOT="/opt/dotnet-sdk/bin" # Nushell COPY --from=ghcr.io/nushell/nushell:0.101.0-bookworm /usr/bin/nu /usr/bin/nu + +# Java +RUN apt-get -y update && apt-get install -y default-jdk +RUN curl -fLo coursier https://github.com/coursier/coursier/releases/download/v2.1.24/coursier \ + && mv ./coursier /usr/bin/coursier \ + && chmod +x /usr/bin/coursier +RUN /usr/bin/java -jar /usr/bin/coursier about diff --git a/docker/DockerfileFullEe b/docker/DockerfileFullEe index b074bb4ecf..25cc47b2dd 100644 --- a/docker/DockerfileFullEe +++ b/docker/DockerfileFullEe @@ -37,3 +37,10 @@ RUN echo /opt/oracle/23/lib > /etc/ld.so.conf.d/oracle-instantclient.conf && ldc # Nushell COPY --from=ghcr.io/nushell/nushell:0.101.0-bookworm /usr/bin/nu /usr/bin/nu + +# Java +RUN apt-get -y update && apt-get install -y default-jdk +RUN curl -fLo coursier https://github.com/coursier/coursier/releases/download/v2.1.24/coursier \ + && mv ./coursier /usr/bin/coursier \ + && chmod +x /usr/bin/coursier +RUN /usr/bin/java -jar /usr/bin/coursier about diff --git a/docker/DockerfileNsjail b/docker/DockerfileNsjail index d667b15722..e51e73a3ea 100644 --- a/docker/DockerfileNsjail +++ b/docker/DockerfileNsjail @@ -62,4 +62,12 @@ RUN echo /opt/oracle/23/lib > /etc/ld.so.conf.d/oracle-instantclient.conf && ldc # Nushell COPY --from=ghcr.io/nushell/nushell:0.101.0-bookworm /usr/bin/nu /usr/bin/nu +# Java +RUN apt-get install -y default-jdk +RUN curl -fLo coursier https://github.com/coursier/coursier/releases/download/v2.1.24/coursier \ + && mv ./coursier /usr/bin/coursier \ + && chmod +x /usr/bin/coursier +RUN /usr/bin/java -jar /usr/bin/coursier about + COPY --from=nsjail /nsjail/nsjail /bin/nsjail + diff --git a/flake.nix b/flake.nix index 209a756a31..e8e91c9391 100644 --- a/flake.nix +++ b/flake.nix @@ -31,6 +31,13 @@ pkg-config cmake ]; + coursier = pkgs.fetchFromGitHub { + owner = "coursier"; + repo = "launchers"; + rev = "79d927f7586c09ca6d8cd01862adb0d9f9d88dff"; + hash = "sha256-8E0WtDFc7RcqmftDigMyy1xXUkjgL4X4kpf7h1GdE48="; + }; + PKG_CONFIG_PATH = pkgs.lib.makeSearchPath "lib/pkgconfig" (with pkgs; [ openssl.dev libxml2.dev xmlsec.dev libxslt.dev ]); RUSTY_V8_ARCHIVE = let @@ -75,6 +82,7 @@ sqlx-cli flock sccache + nsjail deno python3 python3Packages.pip @@ -84,8 +92,10 @@ nushell dotnet-sdk_9 oracle-instantclient + # LSP/Local dev svelte-language-server ansible + taplo ]); packages = [ (pkgs.writeScriptBin "wm-caddy" '' @@ -127,6 +137,25 @@ cd ./frontend npm run dev $* '') + (pkgs.writeScriptBin "wm-minio" '' + set -e + cd ./backend + mkdir -p .minio-data/wmill + ${pkgs.minio}/bin/minio server ./.minio-data + '') + # Generate keys + # TODO: Do not set new keys if ran multiple times + (pkgs.writeScriptBin "wm-minio-keys" '' + set -e + cd ./backend + ${pkgs.minio-client}/bin/mc alias set 'wmill-minio-dev' 'http://localhost:9000' 'minioadmin' 'minioadmin' + ${pkgs.minio-client}/bin/mc admin accesskey create myminio | tee .minio-data/secrets.txt + echo "" + echo 'Saving to: ./backend/.minio-data/secrets.txt' + echo "bucket: wmill" + echo "endpoint: http://localhost:9000" + '') + ]; inherit PKG_CONFIG_PATH RUSTY_V8_ARCHIVE; @@ -141,6 +170,10 @@ BUN_PATH = "${pkgs.bun}/bin/bun"; UV_PATH = "${pkgs.uv}/bin/uv"; NU_PATH = "${pkgs.nushell}/bin/nu"; + JAVA_PATH = "${pkgs.jdk21}/bin/java"; + JAVAC_PATH = "${pkgs.jdk21}/bin/javac"; + COURSIER_PATH = "${coursier}/coursier"; + # for related places search: ADD_NEW_LANG FLOCK_PATH = "${pkgs.flock}/bin/flock"; CARGO_PATH = "${rust}/bin/cargo"; DOTNET_PATH = "${pkgs.dotnet-sdk_9}/bin/dotnet"; @@ -148,6 +181,7 @@ ORACLE_LIB_DIR = "${pkgs.oracle-instantclient.lib}/lib"; ANSIBLE_PLAYBOOK_PATH = "${pkgs.ansible}/bin/ansible-playbook"; ANSIBLE_GALAXY_PATH = "${pkgs.ansible}/bin/ansible-galaxy"; + RUST_LOG = "debug"; }; packages.default = self.packages.${system}.windmill; packages.windmill-client = pkgs.buildNpmPackage { @@ -221,7 +255,6 @@ "cloud" "jemalloc" "tantivy" - "deno_core" "license" "http_trigger" "zip" @@ -229,16 +262,10 @@ "kafka" "otel" "dind" - "php" - "mysql" - "mssql" - "bigquery" "websocket" - "python" "smtp" - "csharp" "static_frontend" - "rust" + "all_languages" ]; doCheck = false; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 819d7a117e..207f5b22f5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,46 +1,46 @@ { "name": "windmill-components", - "version": "1.478.1", + "version": "1.481.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.478.1", + "version": "1.481.0", "license": "AGPL-3.0", "dependencies": { - "@anthropic-ai/sdk": "^0.37.0", "@aws-crypto/sha256-js": "^4.0.0", "@codingame/monaco-vscode-configuration-service-override": "~11.1.2", "@codingame/monaco-vscode-standalone-css-language-features": "~11.1.2", + "@codingame/monaco-vscode-standalone-html-language-features": "^11.1.2", "@codingame/monaco-vscode-standalone-json-language-features": "~11.1.2", "@codingame/monaco-vscode-standalone-languages": "~11.1.2", "@codingame/monaco-vscode-standalone-typescript-language-features": "~11.1.2", "@json2csv/plainjs": "^7.0.6", "@leeoniya/ufuzzy": "^1.0.8", - "@mistralai/mistralai": "^1.3.0", "@popperjs/core": "^2.11.6", "@redocly/json-to-json-schema": "^0.0.1", - "@tanstack/svelte-table": "^8.9.9", - "@windmill-labs/svelte-dnd-action": "latest", + "@tanstack/svelte-table": "npm:tanstack-table-8-svelte-5@^0.1", + "@windmill-labs/svelte-dnd-action": "^0.9.48", "@xyflow/svelte": "^0.1.15", "ag-charts-community": "^9.0.1", "ag-charts-enterprise": "^9.0.1", - "ag-grid-community": "^31.0.0", - "ag-grid-enterprise": "^31.0.0", + "ag-grid-community": "^31.3.4", + "ag-grid-enterprise": "^31.3.4", "ansi_up": "^5.2.1", "chart.js": "^4.4.6", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.0", "d3-zoom": "^3.0.0", "date-fns": "^2.30.0", - "diff": "^5.1.0", + "diff": "^7.0.0", "driver.js": "^1.3.0", "esm-env": "^1.0.0", "fast-equals": "^5.0.1", "graphql": "^16.7.1", "hash-sum": "^2.0.0", "highlight.js": "^11.8.0", + "idb": "^8.0.2", "lucide-svelte": "^0.399.0", "minimatch": "^10.0.1", "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~11.1.2", @@ -49,7 +49,7 @@ "monaco-languageclient": "9.1.1", "monaco-vim": "^0.4.1", "ol": "^7.4.0", - "openai": "^4.57.2", + "openai": "^4.87.1", "p-limit": "^6.1.0", "panzoom": "^9.4.3", "pdfjs-dist": "4.8.69", @@ -58,8 +58,7 @@ "rehype-raw": "^7.0.0", "rfc4648": "^1.5.3", "svelte-carousel": "^1.0.25", - "svelte-chartjs": "^3.1.5", - "svelte-exmarkdown": "^3.0.5", + "svelte-exmarkdown": "^5.0.0", "svelte-infinite-loading": "^1.4.0", "svelte-tiny-virtual-list": "^2.0.5", "tailwind-merge": "^1.13.2", @@ -69,10 +68,11 @@ "vscode-ws-jsonrpc": "~3.4.0", "windmill-parser-wasm-csharp": "^1.437.1", "windmill-parser-wasm-go": "^1.429.0", + "windmill-parser-wasm-java": "^1.478.1", "windmill-parser-wasm-nu": "^1.474.1", "windmill-parser-wasm-php": "^1.429.0", "windmill-parser-wasm-py": "^1.477.1", - "windmill-parser-wasm-regex": "^1.478.2", + "windmill-parser-wasm-regex": "^1.481.0", "windmill-parser-wasm-rust": "^1.429.0", "windmill-parser-wasm-ts": "^1.429.0", "windmill-parser-wasm-yaml": "^1.429.0", @@ -80,7 +80,8 @@ "y-monaco": "^0.1.4", "y-websocket": "^1.5.4", "yaml": "^2.3.4", - "yjs": "^13.6.7" + "yjs": "^13.6.7", + "zod": "^3.24.2" }, "devDependencies": { "@floating-ui/core": "^1.3.1", @@ -88,84 +89,67 @@ "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.2", "@playwright/test": "^1.34.3", - "@rgossiaux/svelte-headlessui": "^2.0.0", "@sveltejs/adapter-static": "^3.0.6", - "@sveltejs/kit": "^2.9.0", - "@sveltejs/package": "^2.2.2", - "@sveltejs/vite-plugin-svelte": "^3.1.2", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/package": "^2.3.7", + "@sveltejs/vite-plugin-svelte": "^5.0.0", "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.8", "@types/d3": "^7.4.0", "@types/d3-zoom": "^3.0.3", + "@types/diff": "^7.0.1", "@types/lodash": "^4.14.195", "@types/node": "^20.3.3", "@types/vscode": "^1.83.5", "@typescript-eslint/eslint-plugin": "^5.59.8", "@typescript-eslint/parser": "^5.60.0", "@windmill-labs/esbuild-import-meta-url-plugin": "0.0.0-semantic-release", - "@zerodevx/svelte-toast": "^0.9.5", + "@zerodevx/svelte-toast": "^0.9.6", "autoprefixer": "^10.4.13", "cssnano": "^6.0.1", "d3-dag": "^0.11.5", "eslint": "^8.47.0", "eslint-config-prettier": "^8.6.0", - "eslint-plugin-svelte": "^2.33.1", + "eslint-plugin-svelte": "^2.45.1", "path-browserify": "^1.0.1", "postcss": "^8.4.49", "postcss-load-config": "^4.0.1", - "prettier": "^2.8.8", - "prettier-plugin-svelte": "^2.10.1", + "prettier": "^3.1.0", + "prettier-plugin-svelte": "^3.3.3", "simple-svelte-autocomplete": "^2.5.1", "style-to-object": "^0.4.1", "stylelint-config-recommended": "^13.0.0", - "svelte": "^4.2.19", + "svelte": "^5.0.0", "svelte-awesome-color-picker": "^3.0.4", - "svelte-check": "^3.4.3", + "svelte-check": "^4.0.0", "svelte-floating-ui": "^1.5.8", "svelte-highlight": "^7.6.0", - "svelte-multiselect": "^10.0.0", + "svelte-multiselect": "^11.0.0-rc.1", "svelte-popperjs": "^1.3.2", - "svelte-preprocess": "^5.0.1", + "svelte-preprocess": "^6.0.0", "svelte-range-slider-pips": "^2.3.1", - "svelte-splitpanes": "^0.8.0", + "svelte-splitpanes": "^8.0.9", "svelte2tsx": "^0.6.16", "tailwindcss": "^3.4.1", "tslib": "^2.6.1", - "typescript": "^5.1.3", - "vite": "^5.4.11", + "typescript": "^5.5.0", + "vite": "^6.2.1", "vite-plugin-circular-dependency": "^0.2.1", "vite-plugin-mkcert": "^1.17.5", "yootils": "^0.3.1" }, "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "^4.35.0", "fsevents": "^2.3.3" }, "peerDependencies": { "svelte": "^4.0.0" } }, - "../backend/parsers/windmill-parser-wasm/pkg-csharp": { - "name": "windmill-parser-wasm-csharp", - "version": "1.411.1", - "extraneous": true - }, - "../svelte-dnd-action": { - "extraneous": true - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -174,46 +158,20 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, - "node_modules/@anthropic-ai/sdk": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.37.0.tgz", - "integrity": "sha512-tHjX2YbkUBwEgg0JZU3EFSSAQPoK4qQR/NFYa8Vtzd5UAyXzZksCw2In69Rml4R/TyHPBfRYaLK35XiOe33pjw==", - "license": "MIT", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - } - }, - "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { - "version": "18.19.64", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.64.tgz", - "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/@apidevtools/json-schema-ref-parser": { "version": "11.6.1", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.6.1.tgz", - "integrity": "sha512-DxjgKBCoyReu4p5HMvpmgSOfRhhBcuf5V5soDDRgOTZMwsA4KSFzol1abFZgiCTE11L2kKGca5Md9GwDdXVBwQ==", "dev": true, + "license": "MIT", "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", @@ -228,8 +186,7 @@ }, "node_modules/@aws-crypto/sha256-js": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-4.0.0.tgz", - "integrity": "sha512-MHGJyjE7TX9aaqXj7zk2ppnFUOhaDs5sP+HtNS0evOxn72c+5njUmyJmpGd7TfyoDznZlHMmdo/xGUdu2NIjNQ==", + "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^4.0.0", "@aws-sdk/types": "^3.222.0", @@ -238,13 +195,11 @@ }, "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "license": "0BSD" }, "node_modules/@aws-crypto/util": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-4.0.0.tgz", - "integrity": "sha512-2EnmPy2gsFZ6m8bwUQN4jq+IyXV3quHAcwPOS6ZA3k+geujiqI8aRokO2kFJe+idJ/P3v4qWI186rVMo0+zLDQ==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", @@ -253,65 +208,33 @@ }, "node_modules/@aws-crypto/util/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "license": "0BSD" }, "node_modules/@aws-sdk/types": { - "version": "3.451.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.451.0.tgz", - "integrity": "sha512-rhK+qeYwCIs+laJfWCcrYEjay2FR/9VABZJ2NRM89jV/fKqGVQR52E5DQqrI+oEIL5JHMhhnr4N4fyECMS35lw==", + "version": "3.734.0", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.5.0", - "tslib": "^2.5.0" + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/util-utf8-browser": { "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.3.1" } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.26.2", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", + "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, @@ -319,95 +242,18 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", "dev": true, "license": "MIT", "peer": true, "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, "node_modules/@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "version": "7.26.9", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -417,8 +263,6 @@ }, "node_modules/@codingame/monaco-vscode-api": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-api/-/monaco-vscode-api-11.1.2.tgz", - "integrity": "sha512-8UHz2uH103P+8eXDRAWo1e1PRfMN5F5dR4s/Mb9fX18Qzr8+/GkpWJHhT1t1cd5xY8XwIiH7YyMz6pL0aDOikw==", "license": "MIT", "peer": true, "dependencies": { @@ -436,16 +280,13 @@ }, "node_modules/@codingame/monaco-vscode-base-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-base-service-override/-/monaco-vscode-base-service-override-11.1.2.tgz", - "integrity": "sha512-3HENz4IktHaqkaG3bieb+LDuybnT90z9orMmwxvRMtZeExLiMh9/ImiToyQI6sF56s4Eac7Us4dMaaWQsHvenw==", + "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-bulk-edit-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-bulk-edit-service-override/-/monaco-vscode-bulk-edit-service-override-11.1.2.tgz", - "integrity": "sha512-2Bi6luOe7+KNCwbph/Q96z+8nX8FEdMB/dK0IL7FRJmlIwzso6FiMy40/jExrBCb6n4/3rqOg1mh/vmdydwGKA==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -453,16 +294,14 @@ }, "node_modules/@codingame/monaco-vscode-chat-comments-extensions-interactive-notebook-search-common": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-chat-comments-extensions-interactive-notebook-search-common/-/monaco-vscode-chat-comments-extensions-interactive-notebook-search-common-11.1.2.tgz", - "integrity": "sha512-WUveAa38ZFpZLZklm7DdjO6ywZFp+lRX7svWb/pB7tNgLyxdbMawL9yK3y/RKQ1Usx4OVEQSAhI5V8IWnTeoJg==", + "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-chat-extensions-interactive-notebook-search-terminal-common": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-chat-extensions-interactive-notebook-search-terminal-common/-/monaco-vscode-chat-extensions-interactive-notebook-search-terminal-common-11.1.2.tgz", - "integrity": "sha512-yHM2IVGYamskWfsp9et1CQONqZ/MJYHHmJ5w+ne8bsV3gNW3DVw4YRX0P52QPVJpp/l9kdAFrvWkpNVM+IroXA==", + "license": "MIT", "dependencies": { "marked": "~14.0.0", "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -470,8 +309,7 @@ }, "node_modules/@codingame/monaco-vscode-chat-extensions-notebook-common": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-chat-extensions-notebook-common/-/monaco-vscode-chat-extensions-notebook-common-11.1.2.tgz", - "integrity": "sha512-yHzxewsY+bZHhpQtFhGDHCbXy82uvD+3yF0oP79uPZWaPgRJTqlNLj7IB2/VlrszpmLPBolZik25k2GOL6sI1Q==", + "license": "MIT", "dependencies": { "@codingame/monaco-vscode-chat-extensions-interactive-notebook-search-terminal-common": "11.1.2", "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -479,8 +317,6 @@ }, "node_modules/@codingame/monaco-vscode-chat-extensions-notebook-task-terminal-testing-common": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-chat-extensions-notebook-task-terminal-testing-common/-/monaco-vscode-chat-extensions-notebook-task-terminal-testing-common-11.1.2.tgz", - "integrity": "sha512-aDGr6tPwQiyGJMCI8kdMDkl+V21TBXt3jDJJq7RXH5pAjhDsf7JtR2CgJLOVHSvc9EZE/43KuUQpSsYOvkHRGg==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -488,8 +324,7 @@ }, "node_modules/@codingame/monaco-vscode-comments-extensions-common": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-comments-extensions-common/-/monaco-vscode-comments-extensions-common-11.1.2.tgz", - "integrity": "sha512-bQvEYaCgzwyjFEP4zEHHxj3vQBMoG3dt0cJDVKb+b9UkU06LUPhTIwRaMF9GiA3j+KvGRIaVulOkLB/vpEoBxg==", + "license": "MIT", "dependencies": { "@codingame/monaco-vscode-chat-comments-extensions-interactive-notebook-search-common": "11.1.2", "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -497,8 +332,7 @@ }, "node_modules/@codingame/monaco-vscode-configuration-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-configuration-service-override/-/monaco-vscode-configuration-service-override-11.1.2.tgz", - "integrity": "sha512-dzsl3q4i9AsTSIH7nA8N6VjrXyZlCsuAMz5wL9dqbDy06ddfU9nUm/kVYFeAO3ueCEH7xt5R0uV3YZtLhqh3xw==", + "license": "MIT", "dependencies": { "@codingame/monaco-vscode-files-service-override": "11.1.2", "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -506,8 +340,6 @@ }, "node_modules/@codingame/monaco-vscode-editor-api": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-editor-api/-/monaco-vscode-editor-api-11.1.2.tgz", - "integrity": "sha512-RYnk0VpL0uSvrFD9k1Oka+K4dP3rhptBzIFVKwjlvCxL0n/mdbECbrcTLKn7wpR11wfMMWvFDHqlNH7ri3rsXg==", "license": "MIT", "peer": true, "dependencies": { @@ -516,8 +348,6 @@ }, "node_modules/@codingame/monaco-vscode-editor-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-editor-service-override/-/monaco-vscode-editor-service-override-11.1.2.tgz", - "integrity": "sha512-BquPLRk2SCkeofyW8e41Ix2DdbZLlazXUUgFiYNvUczqiAojwzuY5lW8ZpboIA78LrekLgGbynqws9T+G5I3OA==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -525,16 +355,13 @@ }, "node_modules/@codingame/monaco-vscode-environment-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-environment-service-override/-/monaco-vscode-environment-service-override-11.1.2.tgz", - "integrity": "sha512-2MohnDywpFLGVw4afgxSO2vrXyZptppnnkF3im9PF5wx+pC5NhjZb14tjcrZFl5pVQmZby6tQUzhZOPjdAVyJw==", + "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-explorer-outline-timeline-view-common-views-workbench-common": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-explorer-outline-timeline-view-common-views-workbench-common/-/monaco-vscode-explorer-outline-timeline-view-common-views-workbench-common-11.1.2.tgz", - "integrity": "sha512-eiGQAxNC+3lGo1XRuKe10P7lUZRBjVbAUZ2+wstra7ENsY5nhoh5q3BnSwTamKZBGVVJHN2dCmz4XS2mYMBmiA==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -542,8 +369,7 @@ }, "node_modules/@codingame/monaco-vscode-extensions-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-extensions-service-override/-/monaco-vscode-extensions-service-override-11.1.2.tgz", - "integrity": "sha512-RJWclpQwywEylLQ9Q+onk22qt83SZeHn3596SDtCUvZn4/uUfyJ8DbRm3gqNdQxSXEO7jhdC4ITnlaY3AbxHTA==", + "license": "MIT", "dependencies": { "@codingame/monaco-vscode-chat-extensions-interactive-notebook-search-terminal-common": "11.1.2", "@codingame/monaco-vscode-chat-extensions-notebook-common": "11.1.2", @@ -554,24 +380,20 @@ }, "node_modules/@codingame/monaco-vscode-files-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-files-service-override/-/monaco-vscode-files-service-override-11.1.2.tgz", - "integrity": "sha512-0On3hBe5mOLPF+9E4KePj0JuLX+0ex/x+YLzH7qnLw89YyZtY8muz6yAXs+nIp5h/wFQi+uxb9m+vWCAB01I8Q==", + "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-host-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-host-service-override/-/monaco-vscode-host-service-override-11.1.2.tgz", - "integrity": "sha512-DLoOM8HcrcoyB8np0CzIN3VJ9pOKuYVOBC1fHzgKBp5i/+akJK5e+5JHj6Au3kUEVSd1cJLjn6dNz58QrbLAhA==", + "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-keybindings-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-keybindings-service-override/-/monaco-vscode-keybindings-service-override-11.1.2.tgz", - "integrity": "sha512-5gtRZODgZ1xNAB3JoGedLFpgteHFZBOuIv6npoZTGdxJLL2mORVOpbQ1P01d8oYK3Rhqh6yI028OaI1ffDHJgQ==", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-files-service-override": "11.1.2", @@ -580,8 +402,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-cs": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-cs/-/monaco-vscode-language-pack-cs-11.1.2.tgz", - "integrity": "sha512-U9s2PNvUCcLLm56SOoaeKdNPf0mfed3BdLV7zv9qMibxRCDFBG9R9yZ1Rl23xH6BQTLdtjVncd1u+KvGyTVh3A==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -589,8 +409,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-de": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-de/-/monaco-vscode-language-pack-de-11.1.2.tgz", - "integrity": "sha512-xaFmXj8GZI6GBtR+HM/LWEAweuq0uNi1nSRS6s/8ZqSyIY0rvZ2yhLpp0m2Gfvh07vU/10GklQNt2hb3t11iIA==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -598,8 +416,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-es": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-es/-/monaco-vscode-language-pack-es-11.1.2.tgz", - "integrity": "sha512-LxY8UH+Q0n8Oz1Hfvz+OAPV5gmJS4iVYim/HrGt0t/TM77aYUo+ulHSci5P+x6cFyrOFF4CZI7piAVhBTZLWvQ==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -607,8 +423,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-fr": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-fr/-/monaco-vscode-language-pack-fr-11.1.2.tgz", - "integrity": "sha512-EoOmqvo/tyxC0auAsMrFfy7w3vIfC53tD3X+Ary3BleCd5IuWd4z/48NtrbaSlnxv/MqmgNLNnsC4yJ22lSInQ==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -616,8 +430,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-it": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-it/-/monaco-vscode-language-pack-it-11.1.2.tgz", - "integrity": "sha512-E9f44X0jtWinSBGNVPF8g16w2QmvxEiclymQeHkkD98erOEJOVrA3pfABkEtTjaC9fLgJNgHyzGybIWurtdG8A==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -625,8 +437,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-ja": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-ja/-/monaco-vscode-language-pack-ja-11.1.2.tgz", - "integrity": "sha512-I3M7TOln+Bs+oTCb02J7pAHOAYSP9nISojVpiChBRqdIymVxE0wdWNN2CgTGuFCCTck9JOlCYzh9an58qSXcxg==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -634,8 +444,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-ko": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-ko/-/monaco-vscode-language-pack-ko-11.1.2.tgz", - "integrity": "sha512-FLY2Zid23kBTIj5YjGsaCtTi21cRZDBlIpQE2/V+go1skCmKpqlJ4L1+mTJenmkAfw6m9ABPHFETswDEU6G1YA==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -643,8 +451,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-pl": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-pl/-/monaco-vscode-language-pack-pl-11.1.2.tgz", - "integrity": "sha512-YPZW53yWenknAlpvAe50qJD+p30EFSUzBkWD1ODSUC/umC1yfYnMsP2sr66oRKjJmp5/LhTWifE0vXMk+EMt/w==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -652,8 +458,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-pt-br": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-pt-br/-/monaco-vscode-language-pack-pt-br-11.1.2.tgz", - "integrity": "sha512-KjILMoi+uuO/l/xsL8yCEhMeSu8es25A/xwHMq2wU9dDjk5mMQ8yoVo6BfBzkmyLghz+EDi6kU2ZP8m+ffPQyA==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -661,8 +465,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-qps-ploc": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-qps-ploc/-/monaco-vscode-language-pack-qps-ploc-11.1.2.tgz", - "integrity": "sha512-muxlncwxCigDqfUnSPIW+OxjmdJ0DW4Nra5bBN0d4ZtFteIFV683IqBlqWyRqoUZETuhdvpTvcxGEPGGE9Kw5g==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -670,8 +472,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-ru": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-ru/-/monaco-vscode-language-pack-ru-11.1.2.tgz", - "integrity": "sha512-0UV+fnUV9A60D0IJrBami2vMSn8XT6RZZtD12g/wil+iSeJ5KQTC4bZTozAEs7dTcjkxUxOkxinWg/zUxT6k3w==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -679,8 +479,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-tr": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-tr/-/monaco-vscode-language-pack-tr-11.1.2.tgz", - "integrity": "sha512-xaA5hBOJL2iuvcfgVidziGm8holR+nSptipjLr/iWdxnUeEM99rEvwX5+bqbHcT/sm9MIDcBw/iP0kNX87MlnQ==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -688,8 +486,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-zh-hans": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-zh-hans/-/monaco-vscode-language-pack-zh-hans-11.1.2.tgz", - "integrity": "sha512-H18x5ZBnL/QijPsqRhgezNJyaKi1kPc+hoAQYF+3DrLNMQEC7cqQ4ThfPVKa7HXfK9FyNpUYKTxqzGrmD8IZAg==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -697,8 +493,6 @@ }, "node_modules/@codingame/monaco-vscode-language-pack-zh-hant": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-zh-hant/-/monaco-vscode-language-pack-zh-hant-11.1.2.tgz", - "integrity": "sha512-o7A+Jpj7roMeNHpQhli5+lYjjz/cbN/WljwZPTOeU6Usa+NvSawth23Q4SbvCtUBcvLEpsOmNF1Kmq7a/3XIIw==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -706,8 +500,6 @@ }, "node_modules/@codingame/monaco-vscode-languages-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-languages-service-override/-/monaco-vscode-languages-service-override-11.1.2.tgz", - "integrity": "sha512-ETYg5/5tP0Pwuxg31kInUMWQmQIK67PH4craJ+gPS82Hh6/EDMNRV63z/REW4QDqw0QEpkLrow/fWXZpgeHCDQ==", "license": "MIT", "peer": true, "dependencies": { @@ -717,16 +509,13 @@ }, "node_modules/@codingame/monaco-vscode-layout-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-layout-service-override/-/monaco-vscode-layout-service-override-11.1.2.tgz", - "integrity": "sha512-WB/wYSV8/Y1C2qgprkkq0+gRi/KTmxpDQc0RZN9tlBHS1C4vLSnuDcXsNsqsXb8VuZ0KAWcES0qJfWGh5Cm1OA==", + "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-localization-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-localization-service-override/-/monaco-vscode-localization-service-override-11.1.2.tgz", - "integrity": "sha512-fOwp+LqXvrtCAbl0vEdYFJS5CfVv8/4raiAr74NzSx/1w0xtvVW8FoFkH+/GAzk+S+9AdDwtbyEnKJYx5HdRwA==", "license": "MIT", "peer": true, "dependencies": { @@ -735,8 +524,6 @@ }, "node_modules/@codingame/monaco-vscode-log-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-log-service-override/-/monaco-vscode-log-service-override-11.1.2.tgz", - "integrity": "sha512-ZCKEjZSq5b9ynl/X52cX+2NI2C+76aJWWkksduAtBS+QQg7uzymjtk98mTGmlSDlHzTSDrU3R4TdShZzBr/m7g==", "license": "MIT", "peer": true, "dependencies": { @@ -746,8 +533,6 @@ }, "node_modules/@codingame/monaco-vscode-model-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-model-service-override/-/monaco-vscode-model-service-override-11.1.2.tgz", - "integrity": "sha512-jFH2VvAiAK7Ytyzl4RMhOdARxrm/LOQFurXBtNhpTcimz3nINgixxh2+e0bviIe0BBs7ATsc9M//g6dA7S/FvQ==", "license": "MIT", "peer": true, "dependencies": { @@ -756,8 +541,6 @@ }, "node_modules/@codingame/monaco-vscode-monarch-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-monarch-service-override/-/monaco-vscode-monarch-service-override-11.1.2.tgz", - "integrity": "sha512-ccvAOLFQna6wsxfirf+rRvuAmjW+AjsOtxfMijJjJ+YVb74bxQH/yttHILagTidTbH0G5eb9IvWF3C0pEBgznQ==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -765,8 +548,6 @@ }, "node_modules/@codingame/monaco-vscode-notifications-workbench-common": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-notifications-workbench-common/-/monaco-vscode-notifications-workbench-common-11.1.2.tgz", - "integrity": "sha512-MChzLX6RpLo8mNTT1R1wwEjo98FljVskBd2ZIGprycne5oydhpfFLQ9JRVc0N9UU5c0trvtvA2rFnEBagURT5g==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -774,48 +555,50 @@ }, "node_modules/@codingame/monaco-vscode-quickaccess-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-quickaccess-service-override/-/monaco-vscode-quickaccess-service-override-11.1.2.tgz", - "integrity": "sha512-VT6F25bEtCvVE2kjBOfgiFOQ1V7YynlrhsHXFZEUzVTK0vFM13Za5otS/CTwgI/ml5FRDFjQKYJjKBAWmlPCaw==", + "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-standalone-css-language-features": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-css-language-features/-/monaco-vscode-standalone-css-language-features-11.1.2.tgz", - "integrity": "sha512-03OmmG/+5ibnSZnVsGcSVJ3TDjHedDqUeuVqzhplFS44eOP0vbrXnbi7+J18vQF+ekNu/SjaMJ8Q48KE3l26pQ==", + "license": "MIT", + "dependencies": { + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@11.1.2" + } + }, + "node_modules/@codingame/monaco-vscode-standalone-html-language-features": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-html-language-features/-/monaco-vscode-standalone-html-language-features-11.1.2.tgz", + "integrity": "sha512-PHRiZRH9ENI7hBJ7b+VSk78TCfQNqGVaS/fbr3jHcS98ohHdlfTRry/Kl1CT7aRIZj7yV9iNWX57hN+lzPp2vg==", + "license": "MIT", "dependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-standalone-json-language-features": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-json-language-features/-/monaco-vscode-standalone-json-language-features-11.1.2.tgz", - "integrity": "sha512-3UjcJpSjYmMoPshZjZDLCIB2hU+NVnYo9EsvZik3zpEgaXQzO+bZLPV7QrH8pufR1WAu/PZqHbqad/0lqPkT+A==", + "license": "MIT", "dependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-standalone-languages": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-languages/-/monaco-vscode-standalone-languages-11.1.2.tgz", - "integrity": "sha512-x2yTosl9JMoiImPPju1+2edKhWQilkREZovSNBkjLeIGpLTqVBeSijSa1KfxZwifAmtwBfRx/LTych0tbWy8kQ==", + "license": "MIT", "dependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-standalone-typescript-language-features": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-typescript-language-features/-/monaco-vscode-standalone-typescript-language-features-11.1.2.tgz", - "integrity": "sha512-6XbJgMGH1C5VJxBfVgWzqBoV5jr22q4ecncsdhP1G6C5sIgEiQFRHcyXb0HWkBJVgfJ/TOH7R8fB+WVeaAznmg==", + "license": "MIT", "dependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@11.1.2" } }, "node_modules/@codingame/monaco-vscode-textmate-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-textmate-service-override/-/monaco-vscode-textmate-service-override-11.1.2.tgz", - "integrity": "sha512-XYifKsm7QCW0GQQrZbstBPK5z8HSi5hT52ViIvMf/w910kvswW2KDiasEAGEGyyG3WaqTGjtwyNkuo6tlBftlQ==", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-files-service-override": "11.1.2", @@ -826,8 +609,6 @@ }, "node_modules/@codingame/monaco-vscode-theme-defaults-default-extension": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-theme-defaults-default-extension/-/monaco-vscode-theme-defaults-default-extension-11.1.2.tgz", - "integrity": "sha512-YeGfdtS9gsTYAJALbYz6DCK8fjZFtm7HdDwC3J1f0zsu7ANHlRwDpKxslLUb+OghV/1uLfaA0C6IxStcu3Jg/w==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -835,8 +616,6 @@ }, "node_modules/@codingame/monaco-vscode-theme-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-theme-service-override/-/monaco-vscode-theme-service-override-11.1.2.tgz", - "integrity": "sha512-6b1EmAiPiRc4JNxKbyJh13RSdLNxsAaaAwAaRXZb2IacYbHFxW2ThlYiZqJMoJHTisNlx2QDLrLq34hG3FTJ2Q==", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-files-service-override": "11.1.2", @@ -845,8 +624,6 @@ }, "node_modules/@codingame/monaco-vscode-view-banner-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-banner-service-override/-/monaco-vscode-view-banner-service-override-11.1.2.tgz", - "integrity": "sha512-174R3jFg6+hrz04sljYpyRvCkFKWDaqoLGaHHmsEI2+Mfu2AAaNUahAfZkii/QNzdXzRDQR4lG3D9zalqHwFkw==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -854,8 +631,6 @@ }, "node_modules/@codingame/monaco-vscode-view-common-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-common-service-override/-/monaco-vscode-view-common-service-override-11.1.2.tgz", - "integrity": "sha512-sbFrlG2GkPZ91JDEDP80IM1b8O5xClDW3P2omRpRH+gscspGU++kItzc8oEJu7LxqL71+i+rmvfo2iJKqw+sgg==", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-bulk-edit-service-override": "11.1.2", @@ -866,8 +641,6 @@ }, "node_modules/@codingame/monaco-vscode-view-common-views-workbench-common": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-common-views-workbench-common/-/monaco-vscode-view-common-views-workbench-common-11.1.2.tgz", - "integrity": "sha512-mjfCjDM9vqzML1I0jGaQICDKLMCKenhPK93lKqpJQeEV7JRE0vpnbbLUBGBYYMi5aWZ0CkGC8BCO0/BqUX7MvQ==", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-explorer-outline-timeline-view-common-views-workbench-common": "11.1.2", @@ -876,8 +649,6 @@ }, "node_modules/@codingame/monaco-vscode-view-status-bar-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-status-bar-service-override/-/monaco-vscode-view-status-bar-service-override-11.1.2.tgz", - "integrity": "sha512-CJQFiqbPrrGpgrmfLDt3vzWNlU0BRyuMILksFctEoLLiypIzfN7VQ+O81qeX2r5rlocVRurPXJnJIL9jNR1HfQ==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -885,8 +656,6 @@ }, "node_modules/@codingame/monaco-vscode-view-title-bar-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-title-bar-service-override/-/monaco-vscode-view-title-bar-service-override-11.1.2.tgz", - "integrity": "sha512-3Q+JoF2H8JYAe8gxfa8zYA9Q8qJ/7jXdeh8F0wjtofHUVl+sLl3bDAyAibFSeZohwnGywBXVxPaOWIqkLhzvUw==", "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" @@ -894,8 +663,6 @@ }, "node_modules/@codingame/monaco-vscode-views-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-views-service-override/-/monaco-vscode-views-service-override-11.1.2.tgz", - "integrity": "sha512-1n8Umz+BIjyX68ardEhjL19BRGOEQzDVGuhBA1kL27ceJAER/GRzRMYMmqs90ZeIThba8OZwuGceItsMti8gkQ==", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-keybindings-service-override": "11.1.2", @@ -907,8 +674,6 @@ }, "node_modules/@codingame/monaco-vscode-workbench-service-override": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-workbench-service-override/-/monaco-vscode-workbench-service-override-11.1.2.tgz", - "integrity": "sha512-E+SWwMiVN/cTmqHWw/1rmkI+zPUxkujGJoC0fqQ3LjUfsLsifoHCt3vKIL9yNFqmSP/jO3OJQ1ZB81pCgDjg7Q==", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-keybindings-service-override": "11.1.2", @@ -924,8 +689,6 @@ }, "node_modules/@csstools/css-parser-algorithms": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz", - "integrity": "sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==", "dev": true, "funding": [ { @@ -948,8 +711,6 @@ }, "node_modules/@csstools/css-tokenizer": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.4.1.tgz", - "integrity": "sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==", "dev": true, "funding": [ { @@ -969,8 +730,6 @@ }, "node_modules/@csstools/media-query-list-parser": { "version": "2.1.13", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.13.tgz", - "integrity": "sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==", "dev": true, "funding": [ { @@ -992,426 +751,35 @@ "@csstools/css-tokenizer": "^2.4.1" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", + "version": "2.1.4", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1432,9 +800,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1442,9 +809,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1453,44 +819,39 @@ } }, "node_modules/@eslint/js": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", - "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", + "version": "8.57.1", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@floating-ui/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz", - "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==", + "version": "1.6.9", "dev": true, + "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.1.3" + "@floating-ui/utils": "^0.2.9" } }, "node_modules/@floating-ui/dom": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", - "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", + "version": "1.6.13", "dev": true, + "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.4.2", - "@floating-ui/utils": "^0.1.3" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" } }, "node_modules/@floating-ui/utils": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", - "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==", - "dev": true + "version": "0.2.9", + "dev": true, + "license": "MIT" }, "node_modules/@hey-api/openapi-ts": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/@hey-api/openapi-ts/-/openapi-ts-0.43.0.tgz", - "integrity": "sha512-Qq3bcy579T+8hhhaSW7MuFgvD07tl8njiFh8/mTYGXerBjoWxAn2ygkV+yE+RKY0eMvSmeH2+9yEAsrVrh5Hjw==", + "version": "0.43.2", "dev": true, + "license": "MIT", "dependencies": { "@apidevtools/json-schema-ref-parser": "11.6.1", "c12": "1.10.0", @@ -1508,35 +869,13 @@ "typescript": "^5.x" } }, - "node_modules/@hey-api/openapi-ts/node_modules/camelcase": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", - "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@hey-api/openapi-ts/node_modules/commander": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", - "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", - "dev": true, - "engines": { - "node": ">=18" - } - }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.13.0", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -1545,9 +884,8 @@ }, "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1555,9 +893,8 @@ }, "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1567,9 +904,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -1579,59 +915,113 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true + "version": "2.0.3", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@internationalized/date": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.6.0.tgz", - "integrity": "sha512-+z6ti+CcJnRlLHok/emGEsWQhe7kfSmEW+/6qCzvKY67YPh7YOBfvc7+/+NXq+zJlbArg30tYpqLjNgcAYv2YQ==", + "version": "3.7.0", "dev": true, "license": "Apache-2.0", "dependencies": { "@swc/helpers": "^0.5.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "license": "ISC", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.25", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1639,46 +1029,38 @@ }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@json2csv/formatters": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@json2csv/formatters/-/formatters-7.0.6.tgz", - "integrity": "sha512-hjIk1H1TR4ydU5ntIENEPgoMGW+Q7mJ+537sDFDbsk+Y3EPl2i4NfFVjw0NJRgT+ihm8X30M67mA8AS6jPidSA==" + "license": "MIT" }, "node_modules/@json2csv/plainjs": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@json2csv/plainjs/-/plainjs-7.0.6.tgz", - "integrity": "sha512-4Md7RPDCSYpmW1HWIpWBOqCd4vWfIqm53S3e/uzQ62iGi7L3r34fK/8nhOMEe+/eVfCx8+gdSCt1d74SlacQHw==", + "license": "MIT", "dependencies": { "@json2csv/formatters": "^7.0.6", "@streamparser/json": "^0.0.20" } }, "node_modules/@kurkle/color": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", - "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + "version": "0.3.4", + "license": "MIT" }, "node_modules/@leeoniya/ufuzzy": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@leeoniya/ufuzzy/-/ufuzzy-1.0.11.tgz", - "integrity": "sha512-QWyEseqEK9t50h9baDmoPkTPSczWZH5TaZAXSBBWbSI6+AxHFd6ldZRmyvCKfyNvjceJ6MwqKCeizsVT+gyJPw==" + "version": "1.0.18", + "license": "MIT" }, "node_modules/@mapbox/jsonlint-lines-primitives": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", "engines": { "node": ">= 0.6" } }, "node_modules/@mapbox/mapbox-gl-style-spec": { "version": "13.28.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.28.0.tgz", - "integrity": "sha512-B8xM7Fp1nh5kejfIl4SWeY0gtIeewbuRencqO3cJDrCHZpaPg7uY+V8abuR+esMeuOjRl5cLhVTP40v+1ywxbg==", + "license": "ISC", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/point-geometry": "^0.1.0", @@ -1698,18 +1080,14 @@ }, "node_modules/@mapbox/point-geometry": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" + "license": "ISC" }, "node_modules/@mapbox/unitbezier": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", - "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==" + "license": "BSD-2-Clause" }, "node_modules/@melt-ui/pp": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@melt-ui/pp/-/pp-0.3.2.tgz", - "integrity": "sha512-xKkPvaIAFinklLXcQOpwZ8YSpqAFxykjWf8Y/fSJQwsixV/0rcFs07hJ49hJjPy5vItvw5Qa0uOjzFUbXzBypQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1722,9 +1100,7 @@ } }, "node_modules/@melt-ui/svelte": { - "version": "0.86.2", - "resolved": "https://registry.npmjs.org/@melt-ui/svelte/-/svelte-0.86.2.tgz", - "integrity": "sha512-wRVN603oIt1aXvx2QRmKqVDJgTScSvr/WJLLokkD8c4QzHgn6pfpPtUKmhV6Dvkk+OY89OG/1Irkd6ouA50Ztw==", + "version": "0.86.4", "dev": true, "license": "MIT", "dependencies": { @@ -1741,8 +1117,6 @@ }, "node_modules/@melt-ui/svelte/node_modules/nanoid": { "version": "5.0.9", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz", - "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==", "dev": true, "funding": [ { @@ -1758,19 +1132,10 @@ "node": "^18 || >=20" } }, - "node_modules/@mistralai/mistralai": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.3.0.tgz", - "integrity": "sha512-G5DPCSC8sEhG3LUEZDYLD7qEZWDuZXgaX3IcoC3a/ydm9jFuh2pRZtknsgMx2sU8d7kxRuxblY3fPH5C38wnhQ==", - "peerDependencies": { - "zod": ">= 3" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1781,18 +1146,16 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1801,204 +1164,41 @@ "node": ">= 8" } }, - "node_modules/@octokit/auth-token": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", - "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/core": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", - "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/auth-token": "^4.0.0", - "@octokit/graphql": "^7.1.0", - "@octokit/request": "^8.3.1", - "@octokit/request-error": "^5.1.0", - "@octokit/types": "^13.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/endpoint": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.5.tgz", - "integrity": "sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/graphql": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz", - "integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/request": "^8.3.0", - "@octokit/types": "^13.0.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "22.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", - "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==", - "dev": true, + "node_modules/@petamoriken/float16": { + "version": "3.9.2", "license": "MIT" }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.1.tgz", - "integrity": "sha512-ryqobs26cLtM1kQxqeZui4v8FeznirUsksiA+RYemMPJ7Micju0WSkv50dBksTuZks9O5cg4wp+t8fZ/cLY56g==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", "dev": true, "license": "MIT", - "dependencies": { - "@octokit/types": "^13.5.0" - }, + "optional": true, "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" + "node": ">=14" } }, - "node_modules/@octokit/plugin-request-log": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz", - "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.2.2.tgz", - "integrity": "sha512-EI7kXWidkt3Xlok5uN43suK99VWqc8OaIMktY9d9+RNKl69juoTyxmLoWPIZgJYzi41qj/9zU7G/ljnNOJ5AFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.5.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "^5" - } - }, - "node_modules/@octokit/request": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.0.tgz", - "integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/endpoint": "^9.0.1", - "@octokit/request-error": "^5.1.0", - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/request-error": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.0.tgz", - "integrity": "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.1.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/rest": { - "version": "20.1.1", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.1.1.tgz", - "integrity": "sha512-MB4AYDsM5jhIHro/dq4ix1iWTLGToIGk6cWF5L6vanFaMble5jTX/UBQyiv05HsWnwUtY8JrfHy2LWfKwihqMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/core": "^5.0.2", - "@octokit/plugin-paginate-rest": "11.3.1", - "@octokit/plugin-request-log": "^4.0.0", - "@octokit/plugin-rest-endpoint-methods": "13.2.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/types": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.5.0.tgz", - "integrity": "sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^22.2.0" - } - }, - "node_modules/@petamoriken/float16": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.8.4.tgz", - "integrity": "sha512-kB+NJ5Br56ZhElKsf0pM7/PQfrDdDVMRz8f0JM6eVOGE+L89z9hwcst9QvWBBnazzuqGTGtPsJNZoQ1JdNiGSQ==" - }, "node_modules/@playwright/test": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.0.tgz", - "integrity": "sha512-PdW+kn4eV99iP5gxWNSDQCbhMaDVej+RXL5xr6t04nbKLCBwYtA046t7ofoczHOm8u6c+45hpDKQVZqtqwkeQg==", + "version": "1.51.0", "dev": true, + "license": "Apache-2.0", "dependencies": { - "playwright": "1.40.0" + "playwright": "1.51.0" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@polka/url": { "version": "1.0.0-next.28", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", - "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", "dev": true, "license": "MIT" }, "node_modules/@popperjs/core": { "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -2006,27 +1206,16 @@ }, "node_modules/@redocly/json-to-json-schema": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@redocly/json-to-json-schema/-/json-to-json-schema-0.0.1.tgz", - "integrity": "sha512-dSMyuNPN2k+tFeNZ0+QJ7S1zDJ0UeNL+lpnPFR9K5avj2V4uG4m6FdjrApQ9Zi35AIocaDp/KGfBD9gR5MLUbQ==" - }, - "node_modules/@rgossiaux/svelte-headlessui": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@rgossiaux/svelte-headlessui/-/svelte-headlessui-2.0.0.tgz", - "integrity": "sha512-ksh245HqMM8yqkzd/OyAK2FCHZYOSA3ldLIHab7C9S60FmifqT24JFVgi8tZpsDEMk3plbfQvfah93n5IEi8sg==", - "dev": true, - "peerDependencies": { - "svelte": "^3.47.0" - } + "license": "SEE LICENSE IN LICENSE" }, "node_modules/@rollup/pluginutils": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz", - "integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==", + "version": "5.1.4", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" + "picomatch": "^4.0.2" }, "engines": { "node": ">=14.0.0" @@ -2042,26 +1231,24 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/@rollup/pluginutils/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.2", "dev": true, + "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", - "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", + "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==", "cpu": [ "arm" ], @@ -2073,9 +1260,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", - "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz", + "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==", "cpu": [ "arm64" ], @@ -2087,9 +1274,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", - "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz", + "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==", "cpu": [ "arm64" ], @@ -2101,9 +1288,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", - "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz", + "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==", "cpu": [ "x64" ], @@ -2114,10 +1301,38 @@ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz", + "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz", + "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", - "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz", + "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==", "cpu": [ "arm" ], @@ -2129,9 +1344,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", - "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz", + "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==", "cpu": [ "arm" ], @@ -2143,9 +1358,7 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", - "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "version": "4.35.0", "cpu": [ "arm64" ], @@ -2157,9 +1370,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", - "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz", + "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==", "cpu": [ "arm64" ], @@ -2170,10 +1383,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz", + "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", - "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz", + "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==", "cpu": [ "ppc64" ], @@ -2185,9 +1412,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", - "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz", + "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==", "cpu": [ "riscv64" ], @@ -2199,9 +1426,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", - "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz", + "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==", "cpu": [ "s390x" ], @@ -2213,13 +1440,12 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", - "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.39.0.tgz", + "integrity": "sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2227,9 +1453,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", - "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz", + "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==", "cpu": [ "x64" ], @@ -2241,9 +1467,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", - "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz", + "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==", "cpu": [ "arm64" ], @@ -2255,9 +1481,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", - "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz", + "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==", "cpu": [ "ia32" ], @@ -2269,9 +1495,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", - "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz", + "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==", "cpu": [ "x64" ], @@ -2283,58 +1509,57 @@ ] }, "node_modules/@smithy/types": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.5.0.tgz", - "integrity": "sha512-/a31lYofrMBkJb3BuPlYJTMKDj0hUmKUP6JFZQu6YVuQVoAjubiY0A52U9S0Uysd33n/djexCUSNJ+G9bf3/aA==", + "version": "4.1.0", + "license": "Apache-2.0", "dependencies": { - "tslib": "^2.5.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, "node_modules/@streamparser/json": { "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.20.tgz", - "integrity": "sha512-VqAAkydywPpkw63WQhPVKCD3SdwXuihCUVZbbiY3SfSTGQyHmwRoq27y4dmJdZuJwd5JIlQoMPyGvMbUPY0RKQ==" + "license": "MIT" }, "node_modules/@svelte-put/shortcut": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@svelte-put/shortcut/-/shortcut-3.1.1.tgz", - "integrity": "sha512-2L5EYTZXiaKvbEelVkg5znxqvfZGZai3m97+cAiUBhLZwXnGtviTDpHxOoZBsqz41szlfRMcamW/8o0+fbW3ZQ==", + "license": "MIT", "peerDependencies": { "svelte": "^3.55.0 || ^4.0.0 || ^5.0.0" } }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.5", + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, "node_modules/@sveltejs/adapter-static": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.6.tgz", - "integrity": "sha512-MGJcesnJWj7FxDcB/GbrdYD3q24Uk0PIL4QIX149ku+hlJuj//nxUbb0HxUTpjkecWfHjVveSUnUaQWnPRXlpg==", + "version": "3.0.8", "dev": true, + "license": "MIT", "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "node_modules/@sveltejs/kit": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.9.0.tgz", - "integrity": "sha512-W3E7ed3ChB6kPqRs2H7tcHp+Z7oiTFC6m+lLyAQQuyXeqw6LdNuuwEUla+5VM0OGgqQD+cYD6+7Xq80vVm17Vg==", + "version": "2.19.0", "dev": true, - "hasInstallScript": true, "license": "MIT", "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", "devalue": "^5.1.0", - "esm-env": "^1.2.1", + "esm-env": "^1.2.2", "import-meta-resolve": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", - "sirv": "^3.0.0", - "tiny-glob": "^0.2.9" + "sirv": "^3.0.0" }, "bin": { "svelte-kit": "svelte-kit.js" @@ -2349,16 +1574,15 @@ } }, "node_modules/@sveltejs/package": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-2.2.2.tgz", - "integrity": "sha512-rP3sVv6cAntcdcG4r4KspLU6nZYYUrHJBAX3Arrw0KJFdgxtlsi2iDwN0Jwr/vIkgjcU0ZPWM8kkT5kpZDlWAw==", + "version": "2.3.10", "dev": true, + "license": "MIT", "dependencies": { - "chokidar": "^3.5.3", + "chokidar": "^4.0.3", "kleur": "^4.1.5", "sade": "^1.8.1", - "semver": "^7.5.3", - "svelte2tsx": "~0.6.19" + "semver": "^7.5.4", + "svelte2tsx": "~0.7.33" }, "bin": { "svelte-package": "svelte-package.js" @@ -2367,52 +1591,60 @@ "node": "^16.14 || >=18" }, "peerDependencies": { - "svelte": "^3.44.0 || ^4.0.0" + "svelte": "^3.44.0 || ^4.0.0 || ^5.0.0-next.1" + } + }, + "node_modules/@sveltejs/package/node_modules/svelte2tsx": { + "version": "0.7.35", + "dev": true, + "license": "MIT", + "dependencies": { + "dedent-js": "^1.0.1", + "pascal-case": "^3.1.1" + }, + "peerDependencies": { + "svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0", + "typescript": "^4.9.4 || ^5.0.0" } }, "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", - "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", + "version": "5.0.3", "dev": true, + "license": "MIT", "dependencies": { - "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", - "debug": "^4.3.4", + "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", + "debug": "^4.4.0", "deepmerge": "^4.3.1", "kleur": "^4.1.5", - "magic-string": "^0.30.10", - "svelte-hmr": "^0.16.0", - "vitefu": "^0.2.5" + "magic-string": "^0.30.15", + "vitefu": "^1.0.4" }, "engines": { - "node": "^18.0.0 || >=20" + "node": "^18.0.0 || ^20.0.0 || >=22" }, "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.0" + "svelte": "^5.0.0", + "vite": "^6.0.0" } }, "node_modules/@sveltejs/vite-plugin-svelte-inspector": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", - "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "version": "4.0.1", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.3.4" + "debug": "^4.3.7" }, "engines": { - "node": "^18.0.0 || >=20" + "node": "^18.0.0 || ^20.0.0 || >=22" }, "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.0" + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "vite": "^6.0.0" } }, "node_modules/@swc/helpers": { "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2420,22 +1652,20 @@ } }, "node_modules/@tailwindcss/forms": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", - "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", + "version": "0.5.10", "dev": true, + "license": "MIT", "dependencies": { "mini-svg-data-uri": "^1.2.3" }, "peerDependencies": { - "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1" } }, "node_modules/@tailwindcss/typography": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", - "integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==", + "version": "0.5.16", "dev": true, + "license": "MIT", "dependencies": { "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", @@ -2443,31 +1673,23 @@ "postcss-selector-parser": "6.0.10" }, "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "node_modules/@tanstack/svelte-table": { - "version": "8.10.7", - "resolved": "https://registry.npmjs.org/@tanstack/svelte-table/-/svelte-table-8.10.7.tgz", - "integrity": "sha512-nHHBYAzXZKs5GseAEJJFyK8EP5arHplHJc3a1X50oUv/xnE10EY/DhLV0YSNigIbNEbDcj+AsTg/6OtamIARQg==", + "name": "tanstack-table-8-svelte-5", + "version": "0.1.2", + "license": "MIT", "dependencies": { - "@tanstack/table-core": "8.10.7" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" + "@tanstack/table-core": "^8.20.5" }, "peerDependencies": { - "svelte": "^4.0.0 || ^3.49.0" + "svelte": "^5.0.0" } }, "node_modules/@tanstack/table-core": { - "version": "8.10.7", - "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.10.7.tgz", - "integrity": "sha512-KQk5OMg5OH6rmbHZxuNROvdI+hKDIUxANaHlV+dPlNN7ED3qYQ/WkpY2qlXww1SIdeMlkIhpN/2L00rof0fXFw==", + "version": "8.21.2", + "license": "MIT", "engines": { "node": ">=12" }, @@ -2478,24 +1700,21 @@ }, "node_modules/@trysound/sax": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10.13.0" } }, "node_modules/@types/cookie": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3": { "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", - "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", @@ -2531,44 +1750,38 @@ }, "node_modules/@types/d3-array": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", - "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-axis": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", - "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-brush": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", - "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-chord": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", - "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-color": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + "license": "MIT" }, "node_modules/@types/d3-contour": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", - "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-array": "*", "@types/geojson": "*" @@ -2576,163 +1789,139 @@ }, "node_modules/@types/d3-delaunay": { "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-dispatch": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", - "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-drag": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", - "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-dsv": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", - "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-ease": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-fetch": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", - "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-dsv": "*" } }, "node_modules/@types/d3-force": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.9.tgz", - "integrity": "sha512-IKtvyFdb4Q0LWna6ymywQsEYjK/94SGhPrMfEr1TIc5OBeziTi+1jcCvttts8e0UWZIxpasjnQk9MNk/3iS+kA==", - "dev": true + "version": "3.0.10", + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-format": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", - "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-geo": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/geojson": "*" } }, "node_modules/@types/d3-hierarchy": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.6.tgz", - "integrity": "sha512-qlmD/8aMk5xGorUvTUWHCiumvgaUXYldYjNVOWtYoTYY/L+WwIEAmJxUmTgr9LoGNG0PPAOmqMDJVDPc7DOpPw==", - "dev": true + "version": "3.1.7", + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", "dependencies": { "@types/d3-color": "*" } }, "node_modules/@types/d3-path": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.2.tgz", - "integrity": "sha512-WAIEVlOCdd/NKRYTsqCpOMHQHemKBEINf8YXMYOtXH0GA7SY0dqMB78P3Uhgfy+4X+/Mlw2wDtlETkN6kQUCMA==", - "dev": true + "version": "3.1.1", + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-polygon": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", - "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-quadtree": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.5.tgz", - "integrity": "sha512-Cb1f3jyNBnvMMkf4KBZ7IgAQVWd9yzBwYcrxGqg3aPCUgWELAS+nyeB7r76aqu1e3+CGDjhk4BrWaFBekMwigg==", - "dev": true + "version": "3.0.6", + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-random": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-scale": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", - "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "version": "4.0.9", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-time": "*" } }, "node_modules/@types/d3-scale-chromatic": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.2.tgz", - "integrity": "sha512-kpKNZMDT3OAX6b5ct5nS/mv6LULagnUy4DmS6yyNjclje1qVe7vbjPwY3q1TGz6+Wr2IUkgFatCzqYUl54fHag==", - "dev": true + "version": "3.1.0", + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-selection": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", - "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" + "version": "3.0.11", + "license": "MIT" }, "node_modules/@types/d3-shape": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.5.tgz", - "integrity": "sha512-dfEWpZJ1Pdg8meLlICX1M3WBIpxnaH2eQV2eY43Y5ysRJOTAV9f3/R++lgJKFstfrEOE2zdJ0sv5qwr2Bkic6Q==", + "version": "3.1.7", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-path": "*" } }, "node_modules/@types/d3-time": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", - "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==", - "dev": true + "version": "3.0.4", + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-time-format": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", - "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-timer": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-transition": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.8.tgz", - "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", + "version": "3.0.9", + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-zoom": { "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", - "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" @@ -2740,76 +1929,73 @@ }, "node_modules/@types/debug": { "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", "dependencies": { "@types/ms": "*" } }, + "node_modules/@types/diff": { + "version": "7.0.1", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "version": "1.0.6", + "license": "MIT" }, "node_modules/@types/geojson": { - "version": "7946.0.13", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz", - "integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==", - "dev": true + "version": "7946.0.16", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hammerjs": { + "version": "2.0.46", + "license": "MIT" }, "node_modules/@types/hast": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", "dependencies": { "@types/unist": "*" } }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.14.201", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.201.tgz", - "integrity": "sha512-y9euML0cim1JrykNxADLfaG0FgD1g/yTHwUs/Jg9ZIU7WKj2/4IW9Lbb1WZbvck78W/lfGXFfe+u2EGfIJXdLQ==", - "dev": true + "version": "4.17.16", + "dev": true, + "license": "MIT" }, "node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "version": "4.0.4", + "license": "MIT", "dependencies": { "@types/unist": "*" } }, "node_modules/@types/minimist": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true, "license": "MIT", "peer": true }, "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + "version": "2.1.0", + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.1.tgz", - "integrity": "sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==", + "version": "20.17.24", + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==", + "version": "2.6.12", + "license": "MIT", "dependencies": { "@types/node": "*", "form-data": "^4.0.0" @@ -2817,45 +2003,28 @@ }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true, "license": "MIT", "peer": true }, - "node_modules/@types/pug": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.9.tgz", - "integrity": "sha512-Yg4LkgFYvn1faISbDNWmcAC1XoDT8IoMUFspp5mnagKk+UvD2N0IWt5A7GRdMubsNWqgCLmrkf8rXkzNqb4szA==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" - }, "node_modules/@types/semver": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz", - "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==", - "dev": true + "version": "7.5.8", + "dev": true, + "license": "MIT" }, "node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "license": "MIT" }, "node_modules/@types/vscode": { - "version": "1.84.1", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.84.1.tgz", - "integrity": "sha512-DB10vBRLEPA/us7p3gQilU2Tq5HDu6JWTyCpD9qtb7MKWIvJS5In9HU3YgVGCXf/miwHJiY62aXwjtUSMpT8HA==", - "dev": true + "version": "1.98.0", + "dev": true, + "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -2887,9 +2056,8 @@ }, "node_modules/@typescript-eslint/parser": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -2914,9 +2082,8 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0" @@ -2931,9 +2098,8 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "5.62.0", "@typescript-eslint/utils": "5.62.0", @@ -2958,9 +2124,8 @@ }, "node_modules/@typescript-eslint/types": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2971,9 +2136,8 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0", @@ -2998,9 +2162,8 @@ }, "node_modules/@typescript-eslint/utils": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", @@ -3024,9 +2187,8 @@ }, "node_modules/@typescript-eslint/visitor-keys": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" @@ -3040,20 +2202,15 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + "version": "1.3.0", + "license": "ISC" }, "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/@windmill-labs/esbuild-import-meta-url-plugin": { "version": "0.0.0-semantic-release", - "resolved": "https://registry.npmjs.org/@windmill-labs/esbuild-import-meta-url-plugin/-/esbuild-import-meta-url-plugin-0.0.0-semantic-release.tgz", - "integrity": "sha512-WaexVcQOpYhX+bRmLq0ZyST1NWu1ujPVLxfcfScP7AX7DUdHfXiLTL1mhdwBcFYiucylOZbkUp2z5lkeSC4abg==", "dev": true, "license": "ISC", "dependencies": { @@ -3063,30 +2220,25 @@ }, "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", - "integrity": "sha512-A6pWayH3nOi79DZohTscGj5t2PuNtHlKM5WIAj9WlVDx5pS1A+MsyfuNZi8oCpj2590wFmQl+58G4y4xZqDa1Q==", + "license": "MIT", "peerDependencies": { "svelte": ">=3.23.0 || ^5.0.0-next.0" } }, "node_modules/@xyflow/svelte": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/@xyflow/svelte/-/svelte-0.1.15.tgz", - "integrity": "sha512-QGM7rlBkoLG6jhHA9U8ZyMtqL62Cpn/T4OElTAUuKTgwuLTdzWqwSCdXpFTs8T6eiJD/Y4jYbVYsmQKDaB9rOw==", + "version": "0.1.31", "license": "MIT", "dependencies": { - "@svelte-put/shortcut": "^3.1.0", - "@xyflow/system": "0.0.38", + "@svelte-put/shortcut": "3.1.1", + "@xyflow/system": "0.0.52", "classcat": "^5.0.4" }, "peerDependencies": { - "svelte": "^3.0.0 || ^4.0.0" + "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0" } }, "node_modules/@xyflow/system": { - "version": "0.0.38", - "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.38.tgz", - "integrity": "sha512-auJU8djbT59S5Afb9lFds1lQJvKIb0zUoHhO+il/ogDDG5BbFds6D8g5a8Q3oHdyR6dy0TaD1oZq9s7Ydhn41g==", + "version": "0.0.52", "license": "MIT", "dependencies": { "@types/d3-drag": "^3.0.7", @@ -3099,18 +2251,16 @@ } }, "node_modules/@zerodevx/svelte-toast": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@zerodevx/svelte-toast/-/svelte-toast-0.9.5.tgz", - "integrity": "sha512-JLeB/oRdJfT+dz9A5bgd3Z7TuQnBQbeUtXrGIrNWMGqWbabpepBF2KxtWVhL2qtxpRqhae2f6NAOzH7xs4jUSw==", + "version": "0.9.6", "dev": true, + "license": "ISC", "peerDependencies": { - "svelte": "^3.57.0 || ^4.0.0" + "svelte": "^3.57.0 || ^4.0.0 || ^5.0.0" } }, "node_modules/abort-controller": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" }, @@ -3120,8 +2270,7 @@ }, "node_modules/abstract-leveldown": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", - "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", + "license": "MIT", "optional": true, "dependencies": { "buffer": "^5.5.0", @@ -3135,9 +2284,8 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.1", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3147,43 +2295,42 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/ag-charts-community": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ag-charts-community/-/ag-charts-community-9.0.1.tgz", - "integrity": "sha512-FZy1tAWO10TzRheoM622/vJWRqldAYH3VGreQ8qirt7FB/ctIR4kjY9GPZywDJnVcb/wET3nrgwq2vIiFKhKBw==" + "version": "9.3.2", + "license": "MIT" }, "node_modules/ag-charts-enterprise": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ag-charts-enterprise/-/ag-charts-enterprise-9.0.1.tgz", - "integrity": "sha512-b8Lz6wgs/CSL1lz0PUnNod016Z5n7vus1mTM9GXhxJ3uyEYP0klwFyvgtK0Cjgc0YeFyhoVDmb38dMKIvHnUyg==", + "version": "9.3.2", + "license": "Commercial", "dependencies": { - "ag-charts-community": "9.0.1" + "ag-charts-community": "9.3.2" } }, "node_modules/ag-grid-community": { - "version": "31.0.0", - "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-31.0.0.tgz", - "integrity": "sha512-OUrXSAbLs0s5DTL9G/J626IKF2mzENHtLzLo5SV0RMO34ZzQANZd1mWlahT0uhZyUFnhyyEEecJBE5nSI88VEw==" + "version": "31.3.4", + "license": "MIT" }, "node_modules/ag-grid-enterprise": { - "version": "31.0.0", - "resolved": "https://registry.npmjs.org/ag-grid-enterprise/-/ag-grid-enterprise-31.0.0.tgz", - "integrity": "sha512-upYw/eeMMqM6TQsOgbAGItSS+x74Spsub8jqqyrozPry8l1UgLmq8TetBrfQ9neS5q8MQpRTHJbXWS3+Gdbo5g==", + "version": "31.3.4", + "license": "Commercial", "dependencies": { - "ag-grid-community": "~31.0.0" + "ag-charts-community": "9.3.2", + "ag-grid-community": "31.3.4" } }, + "node_modules/ag-grid-enterprise/node_modules/ag-charts-community": { + "version": "9.3.2", + "license": "MIT" + }, "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "version": "4.6.0", + "license": "MIT", "dependencies": { "humanize-ms": "^1.2.1" }, @@ -3193,9 +2340,8 @@ }, "node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3209,8 +2355,6 @@ }, "node_modules/amator": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/amator/-/amator-1.1.0.tgz", - "integrity": "sha512-V5+aH8pe+Z3u/UG3L3pG3BaFQGXAyXHVQDroRwjPHdh08bcUEchAVsU1MCuJSCaU5o60wTK6KaE6te5memzgYw==", "license": "MIT", "dependencies": { "bezier-easing": "^2.0.3" @@ -3218,26 +2362,23 @@ }, "node_modules/ansi_up": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ansi_up/-/ansi_up-5.2.1.tgz", - "integrity": "sha512-5bz5T/7FRmlxA37zDXhG6cAwlcZtfnmNLDJra66EEIT3kYlw5aPJdbkJEhm59D6kA4Wi5ict6u6IDYHJaQlH+g==", + "license": "MIT", "engines": { "node": "*" } }, "node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3250,15 +2391,13 @@ }, "node_modules/any-promise": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -3267,51 +2406,33 @@ "node": ">= 8" } }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/arg": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dependencies": { - "dequal": "^2.0.3" + "version": "5.3.2", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" } }, "node_modules/array-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/arrify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, "license": "MIT", "peer": true, @@ -3321,8 +2442,6 @@ }, "node_modules/astral-regex": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, "license": "MIT", "peer": true, @@ -3332,19 +2451,15 @@ }, "node_modules/async-limiter": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "license": "MIT", "optional": true }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "license": "MIT" }, "node_modules/autoprefixer": { - "version": "10.4.16", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", - "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", + "version": "10.4.21", "dev": true, "funding": [ { @@ -3360,12 +2475,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "browserslist": "^4.21.10", - "caniuse-lite": "^1.0.30001538", - "fraction.js": "^4.3.6", + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -3379,9 +2495,7 @@ } }, "node_modules/axios": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz", - "integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==", + "version": "1.8.2", "dev": true, "license": "MIT", "dependencies": { @@ -3392,8 +2506,6 @@ }, "node_modules/axobject-query": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "license": "Apache-2.0", "engines": { "node": ">= 0.4" @@ -3401,8 +2513,7 @@ }, "node_modules/bail": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3410,13 +2521,10 @@ }, "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==" + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -3431,72 +2539,49 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "optional": true }, - "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/bezier-easing": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz", - "integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==", "license": "MIT" }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", "dev": true, + "license": "MIT", "engines": { "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "optional": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/boolbase": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.24.4", "dev": true, "funding": [ { @@ -3512,11 +2597,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -3527,8 +2613,6 @@ }, "node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { "type": "github", @@ -3543,26 +2627,17 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "optional": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/c12": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/c12/-/c12-1.10.0.tgz", - "integrity": "sha512-0SsG7UDhoRWcuSvKWHaXmu5uNjDCDN3nkQLRL4Q42IlFy+ze58FcCoI3uPwINXinkz7ZinbhEgyzYFw9u9ZV8g==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^3.6.0", "confbox": "^0.1.3", @@ -3578,223 +2653,10 @@ "rc9": "^2.1.1" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/camelcase-keys": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", - "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "camelcase": "^6.3.0", - "map-obj": "^4.1.0", - "quick-lru": "^5.1.1", - "type-fest": "^1.2.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-keys/node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-keys/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001655", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz", - "integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/canvas": { - "version": "3.0.0-rc2", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.0.0-rc2.tgz", - "integrity": "sha512-esx4bYDznnqgRX4G8kaEaf0W3q8xIc51WpmrIitDzmcoEgwnv9wSKdzT6UxWZ4wkVu5+ileofppX0TpyviJRdQ==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "node-addon-api": "^7.0.0", - "prebuild-install": "^7.1.1", - "simple-get": "^3.0.3" - }, - "engines": { - "node": "^18.12.0 || >= 20.9.0" - } - }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chart.js": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.6.tgz", - "integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==", - "dependencies": { - "@kurkle/color": "^0.3.0" - }, - "engines": { - "pnpm": ">=8" - } - }, - "node_modules/chartjs-adapter-date-fns": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", - "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", - "peerDependencies": { - "chart.js": ">=2.8.0", - "date-fns": ">=2.0.0" - } - }, - "node_modules/chartjs-plugin-zoom": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-2.0.1.tgz", - "integrity": "sha512-ogOmLu6e+Q7E1XWOCOz9YwybMslz9qNfGV2a+qjfmqJYpsw5ZMoRHZBUyW+NGhkpQ5PwwPA/+rikHpBZb7PZuA==", - "dependencies": { - "hammerjs": "^2.0.8" - }, - "peerDependencies": { - "chart.js": ">=3.2.0" - } - }, - "node_modules/chokidar": { + "node_modules/c12/node_modules/chokidar": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -3814,41 +2676,292 @@ "fsevents": "~2.3.2" } }, + "node_modules/c12/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/c12/node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/camelcase-keys": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/quick-lru": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/type-fest": { + "version": "1.4.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001703", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chart.js": { + "version": "4.4.8", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/chartjs-adapter-date-fns": { + "version": "3.0.0", + "license": "MIT", + "peerDependencies": { + "chart.js": ">=2.8.0", + "date-fns": ">=2.0.0" + } + }, + "node_modules/chartjs-plugin-zoom": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "@types/hammerjs": "^2.0.45", + "hammerjs": "^2.0.8" + }, + "peerDependencies": { + "chart.js": ">=3.2.0" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/chownr": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/citty": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", - "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", "dev": true, + "license": "MIT", "dependencies": { "consola": "^3.2.3" } }, "node_modules/classcat": { "version": "5.0.5", - "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", - "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==" + "license": "MIT" }, "node_modules/clone": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", "engines": { "node": ">=0.8" } }, + "node_modules/clsx": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/code-red": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", - "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@types/estree": "^1.0.1", @@ -3859,9 +2972,8 @@ }, "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3871,20 +2983,17 @@ }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colord": { "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3894,48 +3003,48 @@ }, "node_modules/comma-separated-tokens": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/commander": { + "version": "12.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/confbox": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.6.tgz", - "integrity": "sha512-ONc4FUXne/1UBN1EuxvQ5rAjjAbo+N4IxrxWI8bzGHbd1PyrFlI/E3G23/yoJZDFBaFFxPGfI0EOq0fa4dgX7A==", - "dev": true + "version": "0.1.8", + "dev": true, + "license": "MIT" }, "node_modules/consola": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", - "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "version": "3.4.0", "dev": true, + "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" } }, "node_modules/cookie": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cosmiconfig": { "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, "license": "MIT", "peer": true, @@ -3961,10 +3070,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3975,21 +3083,18 @@ } }, "node_modules/css-declaration-sorter": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", - "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "version": "7.2.0", "dev": true, + "license": "ISC", "engines": { - "node": "^10 || ^12 || >=14" + "node": "^14 || ^16 || >=18" }, "peerDependencies": { "postcss": "^8.0.9" } }, "node_modules/css-functions-list": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz", - "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==", + "version": "3.2.3", "dev": true, "license": "MIT", "peer": true, @@ -3999,9 +3104,8 @@ }, "node_modules/css-select": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -4015,8 +3119,8 @@ }, "node_modules/css-tree": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "license": "MIT", "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -4027,9 +3131,8 @@ }, "node_modules/css-what": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -4039,14 +3142,12 @@ }, "node_modules/csscolorparser": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", - "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==" + "license": "MIT" }, "node_modules/cssesc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -4055,13 +3156,12 @@ } }, "node_modules/cssnano": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", - "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", + "version": "6.1.2", "dev": true, + "license": "MIT", "dependencies": { - "cssnano-preset-default": "^6.0.1", - "lilconfig": "^2.1.0" + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" }, "engines": { "node": "^14 || ^16 || >=18.0" @@ -4071,69 +3171,67 @@ "url": "https://opencollective.com/cssnano" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/cssnano-preset-default": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", - "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", + "version": "6.1.2", "dev": true, + "license": "MIT", "dependencies": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^9.0.0", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.1", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", + "version": "4.0.2", "dev": true, + "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/csso": { "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "license": "MIT", "dependencies": { "css-tree": "~2.2.0" }, @@ -4144,9 +3242,8 @@ }, "node_modules/csso/node_modules/css-tree": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "license": "MIT", "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -4158,15 +3255,13 @@ }, "node_modules/csso/node_modules/mdn-data": { "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, "node_modules/d3-array": { "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", "dev": true, + "license": "ISC", "dependencies": { "internmap": "1 - 2" }, @@ -4176,17 +3271,15 @@ }, "node_modules/d3-color": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-dag": { "version": "0.11.5", - "resolved": "https://registry.npmjs.org/d3-dag/-/d3-dag-0.11.5.tgz", - "integrity": "sha512-sNHvYqjzDlvV2fyEkoOCSuLs2GeWliIg7pJcAiKXgtUSxl0kIX0C2q1J8JzzA9CQWptKxYtzxFCXiKptTW8qsQ==", "dev": true, + "license": "MIT", "dependencies": { "d3-array": "^3.1.6", "fastpriorityqueue": "0.7.2", @@ -4196,16 +3289,14 @@ }, "node_modules/d3-dispatch": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-drag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" @@ -4216,16 +3307,14 @@ }, "node_modules/d3-ease": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "engines": { "node": ">=12" } }, "node_modules/d3-interpolate": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3" }, @@ -4235,24 +3324,21 @@ }, "node_modules/d3-selection": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-timer": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-transition": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", @@ -4269,8 +3355,7 @@ }, "node_modules/d3-zoom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -4284,8 +3369,7 @@ }, "node_modules/date-fns": { "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -4299,16 +3383,13 @@ }, "node_modules/debounce-promise": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/debounce-promise/-/debounce-promise-3.1.2.tgz", - "integrity": "sha512-rZHcgBkbYavBeD9ej6sP56XfG53d51CD4dnaw989YX/nZ/ZJfgRx/9ePKmTNiUiyQvh4mtrMoS3OAWW+yoYtpg==", "license": "MIT" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -4321,8 +3402,6 @@ }, "node_modules/decamelize": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", - "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", "dev": true, "license": "MIT", "peer": true, @@ -4335,8 +3414,6 @@ }, "node_modules/decamelize-keys": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", "dev": true, "license": "MIT", "peer": true, @@ -4353,8 +3430,6 @@ }, "node_modules/decamelize-keys/node_modules/decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, "license": "MIT", "peer": true, @@ -4364,8 +3439,6 @@ }, "node_modules/decamelize-keys/node_modules/map-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", "dev": true, "license": "MIT", "peer": true, @@ -4374,9 +3447,8 @@ } }, "node_modules/decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "version": "1.1.0", + "license": "MIT", "dependencies": { "character-entities": "^2.0.0" }, @@ -4385,29 +3457,14 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "license": "MIT", - "optional": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dedent-js": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz", - "integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deep-equal": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", - "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", + "license": "MIT", "dependencies": { "is-arguments": "^1.1.1", "is-date-object": "^1.0.5", @@ -4423,35 +3480,22 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/deferred-leveldown": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz", - "integrity": "sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw==", + "license": "MIT", "optional": true, "dependencies": { "abstract-leveldown": "~6.2.1", @@ -4463,8 +3507,7 @@ }, "node_modules/define-data-property": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -4479,8 +3522,7 @@ }, "node_modules/define-properties": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -4495,69 +3537,36 @@ }, "node_modules/defu": { "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true, - "license": "ISC" - }, "node_modules/dequal": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/destr": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.3.tgz", - "integrity": "sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==", - "dev": true - }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, "node_modules/devalue": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", - "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", "dev": true, "license": "MIT" }, "node_modules/devlop": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", "dependencies": { "dequal": "^2.0.0" }, @@ -4568,23 +3577,20 @@ }, "node_modules/didyoumean": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "version": "7.0.0", + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, "node_modules/dir-glob": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -4594,15 +3600,13 @@ }, "node_modules/dlv": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -4612,9 +3616,8 @@ }, "node_modules/dom-serializer": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -4626,21 +3629,19 @@ }, "node_modules/domelementtype": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -4652,10 +3653,9 @@ } }, "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "version": "3.2.2", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -4666,10 +3666,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -4678,19 +3677,33 @@ } }, "node_modules/driver.js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/driver.js/-/driver.js-1.3.1.tgz", - "integrity": "sha512-MvUdXbqSgEsgS/H9KyWb5Rxy0aE6BhOVT4cssi2x2XjmXea6qQfgdx32XKVLLSqTaIw7q/uxU5Xl3NV7+cN6FQ==" + "version": "1.3.5", + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/earcut": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + "license": "ISC" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "license": "MIT" }, "node_modules/easy-reactive": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/easy-reactive/-/easy-reactive-1.0.4.tgz", - "integrity": "sha512-dFVouegPctMf6XT5si+sRByBWUQE30n99TW0Y45Y7mccmNsbSl4uXA2sBGI8zCDZqXjhb8ouA3wVVhSSGpXk5Q==", + "license": "Apache-2.0", "dependencies": { "lodash.clonedeep": "^4.5.0", "lodash.get": "^4.4.2", @@ -4698,22 +3711,18 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.588", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.588.tgz", - "integrity": "sha512-soytjxwbgcCu7nh5Pf4S2/4wa6UIu+A3p03U2yVr53qGxi1/VTR3ENI+p50v+UxqqZAfl48j3z55ud7VHIOr9w==", - "dev": true + "version": "1.5.113", + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "peer": true + "license": "MIT" }, "node_modules/encoding-down": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz", - "integrity": "sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==", + "license": "MIT", "optional": true, "dependencies": { "abstract-leveldown": "^6.2.1", @@ -4725,20 +3734,9 @@ "node": ">=6" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "license": "MIT", - "optional": true, - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/entities": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -4748,8 +3746,7 @@ }, "node_modules/errno": { "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "license": "MIT", "optional": true, "dependencies": { "prr": "~1.0.1" @@ -4760,8 +3757,6 @@ }, "node_modules/error-ex": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "license": "MIT", "peer": true, @@ -4770,34 +3765,44 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, - "node_modules/es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", - "dev": true + "node_modules/es-object-atoms": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.0", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4805,48 +3810,48 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -4855,16 +3860,15 @@ } }, "node_modules/eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", - "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", + "version": "8.57.1", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.54.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -4910,10 +3914,12 @@ } }, "node_modules/eslint-compat-utils": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz", - "integrity": "sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==", + "version": "0.5.1", "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, "engines": { "node": ">=12" }, @@ -4923,9 +3929,8 @@ }, "node_modules/eslint-config-prettier": { "version": "8.10.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", - "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", "dev": true, + "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -4934,23 +3939,21 @@ } }, "node_modules/eslint-plugin-svelte": { - "version": "2.35.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.35.0.tgz", - "integrity": "sha512-3WDFxNrkXaMlpqoNo3M1ZOQuoFLMO9+bdnN6oVVXaydXC7nzCJuGy9a0zqoNDHMSRPYt0Rqo6hIdHMEaI5sQnw==", + "version": "2.46.1", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@jridgewell/sourcemap-codec": "^1.4.14", - "debug": "^4.3.1", - "eslint-compat-utils": "^0.1.2", + "@eslint-community/eslint-utils": "^4.4.0", + "@jridgewell/sourcemap-codec": "^1.4.15", + "eslint-compat-utils": "^0.5.1", "esutils": "^2.0.3", - "known-css-properties": "^0.29.0", - "postcss": "^8.4.5", + "known-css-properties": "^0.35.0", + "postcss": "^8.4.38", "postcss-load-config": "^3.1.4", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.11", - "semver": "^7.5.3", - "svelte-eslint-parser": ">=0.33.0 <1.0.0" + "postcss-selector-parser": "^6.1.0", + "semver": "^7.6.2", + "svelte-eslint-parser": "^0.43.0" }, "engines": { "node": "^14.17.0 || >=16.0.0" @@ -4959,8 +3962,8 @@ "url": "https://github.com/sponsors/ota-meshi" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0-0", - "svelte": "^3.37.0 || ^4.0.0" + "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0", + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "peerDependenciesMeta": { "svelte": { @@ -4968,11 +3971,18 @@ } } }, + "node_modules/eslint-plugin-svelte/node_modules/lilconfig": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-plugin-svelte/node_modules/postcss-load-config": { "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", "dev": true, + "license": "MIT", "dependencies": { "lilconfig": "^2.0.5", "yaml": "^1.10.2" @@ -4998,10 +4008,9 @@ } }, "node_modules/eslint-plugin-svelte/node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.1.2", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -5012,18 +4021,16 @@ }, "node_modules/eslint-plugin-svelte/node_modules/yaml": { "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 6" } }, "node_modules/eslint-scope": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -5034,9 +4041,8 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5046,9 +4052,8 @@ }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5056,9 +4061,8 @@ }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -5072,30 +4076,16 @@ }, "node_modules/eslint/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5104,25 +4094,21 @@ } }, "node_modules/esm-env": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.1.tgz", - "integrity": "sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==", + "version": "1.2.2", "license": "MIT" }, "node_modules/esm-env-robust": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/esm-env-robust/-/esm-env-robust-0.0.3.tgz", - "integrity": "sha512-90Gnuw2DALOqlL1581VxP3GHPUNHX9U+fQ+8FNcTTFClhY5gEggAAnJ3q1b2Oq23knRsjv8YpNeMRPaMLUymOA==", "dev": true, + "license": "MIT", "dependencies": { "esm-env": "^1.0.0" } }, "node_modules/espree": { "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -5136,10 +4122,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -5149,18 +4134,23 @@ }, "node_modules/esquery/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, + "node_modules/esrap": { + "version": "1.4.5", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, "node_modules/esrecurse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -5170,161 +4160,121 @@ }, "node_modules/esrecurse/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/estree-walker": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" } }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/event-target-shim": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/eventemitter3": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", - "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==" - }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/execa/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", - "optional": true, - "engines": { - "node": ">=6" - } + "license": "MIT" }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-diff": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", - "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==" + "license": "Apache-2.0" }, "node_modules/fast-equals": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", - "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "version": "5.2.2", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "version": "3.0.6", "dev": true, - "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", "peer": true }, "node_modules/fastest-levenshtein": { "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "dev": true, "license": "MIT", "peer": true, @@ -5334,24 +4284,21 @@ }, "node_modules/fastpriorityqueue": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.2.tgz", - "integrity": "sha512-5DtIKh6vtOmEGkYdEPNNb+mxeYCnBiKbK3s4gq52l6cX8I5QaTDWWw0Wx/iYo80fVOblSycHu1/iJeqeNxG8Jw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.19.1", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/file-entry-cache": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -5360,10 +4307,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5373,9 +4319,8 @@ }, "node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -5389,9 +4334,8 @@ }, "node_modules/flat-cache": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -5402,15 +4346,12 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "version": "3.3.3", + "dev": true, + "license": "ISC" }, "node_modules/focus-trap": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.2.tgz", - "integrity": "sha512-9FhUxK1hVju2+AiQIDJ5Dd//9R2n2RAfJ0qfhF4IHGHgcoEUTMpbTeG/zbEuwaiYXfuAH6XE0/aCyxDdRM+W5w==", + "version": "7.6.4", "dev": true, "license": "MIT", "dependencies": { @@ -5418,9 +4359,7 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", "dev": true, "funding": [ { @@ -5438,13 +4377,28 @@ } } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.2", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" }, "engines": { @@ -5453,13 +4407,11 @@ }, "node_modules/form-data-encoder": { "version": "1.7.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + "license": "MIT" }, "node_modules/formdata-node": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" @@ -5468,19 +4420,10 @@ "node": ">= 12.20" } }, - "node_modules/formdata-node/node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "engines": { - "node": ">= 14" - } - }, "node_modules/fraction.js": { "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, @@ -5489,18 +4432,10 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT", - "optional": true - }, "node_modules/fs-minipass": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -5510,9 +4445,8 @@ }, "node_modules/fs-minipass/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -5522,15 +4456,15 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5541,24 +4475,21 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/functions-have-names": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/geotiff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.1.0.tgz", - "integrity": "sha512-B/iFJuFfRpmPHXf8aIRPRgUWwfaNb6dlsynkM8SWeHAPu7CpyvfqEa43KlBt7xxq5OTVysQacFHxhCn3SZhRKQ==", + "version": "2.1.3", + "license": "MIT", "dependencies": { "@petamoriken/float16": "^3.4.7", "lerc": "^3.0.0", @@ -5574,15 +4505,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5591,49 +4526,43 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "engines": { - "node": ">=16" + "node_modules/get-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.4" } }, "node_modules/giget": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.3.tgz", - "integrity": "sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==", + "version": "1.2.5", "dev": true, + "license": "MIT", "dependencies": { "citty": "^0.1.6", - "consola": "^3.2.3", + "consola": "^3.4.0", "defu": "^6.1.4", - "node-fetch-native": "^1.6.3", - "nypm": "^0.3.8", - "ohash": "^1.1.3", - "pathe": "^1.1.2", - "tar": "^6.2.0" + "node-fetch-native": "^1.6.6", + "nypm": "^0.5.4", + "pathe": "^2.0.3", + "tar": "^6.2.1" }, "bin": { "giget": "dist/cli.mjs" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT", - "optional": true + "node_modules/giget/node_modules/pathe": { + "version": "2.0.3", + "dev": true, + "license": "MIT" }, "node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5650,22 +4579,20 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", "dev": true, + "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/glob/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5673,9 +4600,8 @@ }, "node_modules/glob/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5685,8 +4611,6 @@ }, "node_modules/global-modules": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", "dev": true, "license": "MIT", "peer": true, @@ -5699,8 +4623,6 @@ }, "node_modules/global-prefix": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", "dev": true, "license": "MIT", "peer": true, @@ -5715,8 +4637,6 @@ }, "node_modules/global-prefix/node_modules/which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "license": "ISC", "peer": true, @@ -5728,10 +4648,9 @@ } }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -5742,17 +4661,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, "node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5770,53 +4682,34 @@ }, "node_modules/globjoin": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", - "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", "dev": true, "license": "MIT", "peer": true }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "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 - }, "node_modules/graphemer": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "version": "16.10.0", + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } }, "node_modules/graphql-language-service": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-5.3.0.tgz", - "integrity": "sha512-gCQIIy7lM9CB1KPLEb+DNZLczA9zuTLEOJE2hEQZTFYInogdmMDRa6RAkvM4LL0LcgcS+3uPs6KtHlcjCqRbUg==", "license": "MIT", "dependencies": { "debounce-promise": "^3.1.2", @@ -5832,17 +4725,15 @@ }, "node_modules/hammerjs": { "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==", + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/handlebars": { "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", @@ -5861,8 +4752,6 @@ }, "node_modules/hard-rejection": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true, "license": "MIT", "peer": true, @@ -5872,17 +4761,15 @@ }, "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/has-property-descriptors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -5890,21 +4777,9 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5913,11 +4788,10 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -5928,13 +4802,11 @@ }, "node_modules/hash-sum": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", - "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" + "license": "MIT" }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -5944,8 +4816,6 @@ }, "node_modules/hast-util-from-html": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", - "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -5961,16 +4831,14 @@ } }, "node_modules/hast-util-from-parse5": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.2.tgz", - "integrity": "sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==", + "version": "8.0.3", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" @@ -5982,8 +4850,6 @@ }, "node_modules/hast-util-is-element": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -5995,8 +4861,6 @@ }, "node_modules/hast-util-parse-selector": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -6008,8 +4872,6 @@ }, "node_modules/hast-util-raw": { "version": "9.1.0", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", - "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -6033,8 +4895,6 @@ }, "node_modules/hast-util-to-parse5": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", - "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -6050,16 +4910,22 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-parse5/node_modules/property-information": { + "version": "6.5.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/hastscript": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz", - "integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==", + "version": "9.0.1", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" }, "funding": { @@ -6068,17 +4934,14 @@ } }, "node_modules/highlight.js": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", - "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", + "version": "11.11.1", + "license": "BSD-3-Clause", "engines": { "node": ">=12.0.0" } }, "node_modules/hosted-git-info": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, "license": "ISC", "peer": true, @@ -6091,8 +4954,6 @@ }, "node_modules/html-tags": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", "dev": true, "license": "MIT", "peer": true, @@ -6105,35 +4966,25 @@ }, "node_modules/html-void-elements": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", - "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "engines": { - "node": ">=16.17.0" - } - }, "node_modules/humanize-ms": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", "dependencies": { "ms": "^2.0.0" } }, + "node_modules/idb": { + "version": "8.0.2", + "license": "ISC" + }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -6147,28 +4998,26 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.2", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/immediate": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", - "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", + "license": "MIT", "optional": true }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -6182,8 +5031,6 @@ }, "node_modules/import-lazy": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", "dev": true, "license": "MIT", "peer": true, @@ -6193,8 +5040,6 @@ }, "node_modules/import-meta-resolve": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", - "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", "dev": true, "license": "MIT", "funding": { @@ -6204,17 +5049,14 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } }, "node_modules/indent-string": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, "license": "MIT", "peer": true, @@ -6227,9 +5069,8 @@ }, "node_modules/inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -6237,39 +5078,34 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "devOptional": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "devOptional": true, "license": "ISC" }, + "node_modules/ini": { + "version": "1.3.8", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/inline-style-parser": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/internmap": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "version": "1.2.0", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6280,17 +5116,14 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, "license": "MIT", "peer": true }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -6299,23 +5132,25 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.16.1", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6326,28 +5161,24 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "peer": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -6357,26 +5188,22 @@ }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-path-inside": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-plain-obj": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "dev": true, "license": "MIT", "peer": true, @@ -6386,8 +5213,6 @@ }, "node_modules/is-plain-object": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, "license": "MIT", "peer": true, @@ -6396,20 +5221,20 @@ } }, "node_modules/is-reference": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", - "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "version": "3.0.3", + "license": "MIT", "dependencies": { - "@types/estree": "*" + "@types/estree": "^1.0.6" } }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -6418,61 +5243,56 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isomorphic.js": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", - "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", + "license": "MIT", "funding": { "type": "GitHub Sponsors ❤", "url": "https://github.com/sponsors/dmonad" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/javascript-lp-solver": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/javascript-lp-solver/-/javascript-lp-solver-0.4.24.tgz", - "integrity": "sha512-5edoDKnMrt/u3M6GnZKDDIPxOyFOg+WrwDv8mjNiMC2DePhy2H9/FFQgf4ggywaXT1utvkxusJcjQUER72cZmA==", - "dev": true + "dev": true, + "license": "Unlicense" }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.7", "dev": true, + "license": "MIT", "bin": { "jiti": "bin/jiti.js" } }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, "license": "MIT", "peer": true }, "node_modules/js-yaml": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -6482,63 +5302,46 @@ }, "node_modules/jschardet": { "version": "3.1.4", - "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.1.4.tgz", - "integrity": "sha512-/kmVISmrwVwtyYU40iQUOp3SUPk2dhNCMsZBQX0R1/jZ8maaXJ/oZIzUOiyOqcgtLnETFKYChbJ5iDC/eWmFHg==", + "license": "LGPL-2.1+", "engines": { "node": ">=0.1.90" } }, "node_modules/json-buffer": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, "license": "MIT", "peer": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-pretty-compact": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz", - "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==" - }, - "node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true, "license": "MIT" }, "node_modules/keyv": { "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } }, "node_modules/kind-of": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, "license": "MIT", "peer": true, @@ -6548,28 +5351,24 @@ }, "node_modules/kleur": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/known-css-properties": { - "version": "0.29.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz", - "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==", - "dev": true + "version": "0.35.0", + "dev": true, + "license": "MIT" }, "node_modules/lerc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", - "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==" + "license": "Apache-2.0" }, "node_modules/level": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/level/-/level-6.0.1.tgz", - "integrity": "sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw==", + "license": "MIT", "optional": true, "dependencies": { "level-js": "^5.0.0", @@ -6586,8 +5385,7 @@ }, "node_modules/level-codec": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.2.tgz", - "integrity": "sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==", + "license": "MIT", "optional": true, "dependencies": { "buffer": "^5.6.0" @@ -6598,8 +5396,7 @@ }, "node_modules/level-concat-iterator": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", - "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==", + "license": "MIT", "optional": true, "engines": { "node": ">=6" @@ -6607,8 +5404,7 @@ }, "node_modules/level-errors": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz", - "integrity": "sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==", + "license": "MIT", "optional": true, "dependencies": { "errno": "~0.1.1" @@ -6619,8 +5415,7 @@ }, "node_modules/level-iterator-stream": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz", - "integrity": "sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q==", + "license": "MIT", "optional": true, "dependencies": { "inherits": "^2.0.4", @@ -6633,8 +5428,7 @@ }, "node_modules/level-js": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/level-js/-/level-js-5.0.2.tgz", - "integrity": "sha512-SnBIDo2pdO5VXh02ZmtAyPP6/+6YTJg2ibLtl9C34pWvmtMEmRTWpra+qO/hifkUtBTOtfx6S9vLDjBsBK4gRg==", + "license": "MIT", "optional": true, "dependencies": { "abstract-leveldown": "~6.2.3", @@ -6645,8 +5439,7 @@ }, "node_modules/level-packager": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-5.1.1.tgz", - "integrity": "sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ==", + "license": "MIT", "optional": true, "dependencies": { "encoding-down": "^6.3.0", @@ -6658,8 +5451,7 @@ }, "node_modules/level-supports": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", - "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", + "license": "MIT", "optional": true, "dependencies": { "xtend": "^4.0.2" @@ -6670,9 +5462,8 @@ }, "node_modules/leveldown": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-5.6.0.tgz", - "integrity": "sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ==", "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "abstract-leveldown": "~6.2.1", @@ -6685,8 +5476,7 @@ }, "node_modules/levelup": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.4.0.tgz", - "integrity": "sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ==", + "license": "MIT", "optional": true, "dependencies": { "deferred-leveldown": "~5.3.0", @@ -6701,9 +5491,8 @@ }, "node_modules/levn": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -6713,13 +5502,13 @@ } }, "node_modules/lib0": { - "version": "0.2.87", - "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.87.tgz", - "integrity": "sha512-TbB63XJixvNToW2IHWAFsCJj9tVnajmwjE14p69i51Rx8byOQd2IP4ourE8v4d7vhyO++nVm1sQk3ePslfbucg==", + "version": "0.2.99", + "license": "MIT", "dependencies": { "isomorphic.js": "^0.2.4" }, "bin": { + "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js", "0gentesthtml": "bin/gentesthtml.js", "0serve": "bin/0serve.js" }, @@ -6732,30 +5521,29 @@ } }, "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "version": "3.1.3", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/locate-character": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -6768,66 +5556,54 @@ }, "node_modules/lodash.castarray": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", - "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.clonedeep": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "license": "MIT" }, "node_modules/lodash.get": { "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + "license": "MIT" }, "node_modules/lodash.isequal": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.memoize": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.truncate": { "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true, "license": "MIT", "peer": true }, "node_modules/lodash.uniq": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/longest-streak": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -6835,17 +5611,17 @@ }, "node_modules/lower-case": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } }, "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", + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -6855,30 +5631,25 @@ }, "node_modules/ltgt": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", - "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==", + "license": "MIT", "optional": true }, "node_modules/lucide-svelte": { "version": "0.399.0", - "resolved": "https://registry.npmjs.org/lucide-svelte/-/lucide-svelte-0.399.0.tgz", - "integrity": "sha512-NQ8AxNMKbIJsx7HV//gnAsIY1wJfb3rbXSK2S/ZDjIldvAEdzGngpUT8T8Q8zHYUuii0bavAmVARN8giR4vvpA==", + "license": "ISC", "peerDependencies": { "svelte": "^3 || ^4 || ^5.0.0-next.42" } }, "node_modules/magic-string": { - "version": "0.30.14", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", - "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", + "version": "0.30.17", + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/map-obj": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true, "license": "MIT", "peer": true, @@ -6890,14 +5661,12 @@ } }, "node_modules/mapbox-to-css-font": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/mapbox-to-css-font/-/mapbox-to-css-font-2.4.2.tgz", - "integrity": "sha512-f+NBjJJY4T3dHtlEz1wCG7YFlkODEjFIYlxDdLIDMNpkSksqTt+l/d4rjuwItxuzkuMFvPyrjzV2lxRM4ePcIA==" + "version": "2.4.5", + "license": "BSD-2-Clause" }, "node_modules/markdown-table": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", - "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "version": "3.0.4", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -6905,8 +5674,7 @@ }, "node_modules/marked": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", - "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "license": "MIT", "bin": { "marked": "bin/marked.js" }, @@ -6914,10 +5682,15 @@ "node": ">= 18" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mathml-tag-names": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", - "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", "dev": true, "license": "MIT", "peer": true, @@ -6927,9 +5700,8 @@ } }, "node_modules/mdast-util-find-and-replace": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", - "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "version": "3.0.2", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", @@ -6943,8 +5715,7 @@ }, "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -6953,9 +5724,8 @@ } }, "node_modules/mdast-util-from-markdown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", - "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", + "version": "2.0.2", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -6976,9 +5746,8 @@ } }, "node_modules/mdast-util-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", - "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "version": "3.1.0", + "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", @@ -6994,9 +5763,8 @@ } }, "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", - "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", + "version": "2.0.1", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", @@ -7010,9 +5778,8 @@ } }, "node_modules/mdast-util-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "version": "2.1.0", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", @@ -7027,8 +5794,7 @@ }, "node_modules/mdast-util-gfm-strikethrough": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -7041,8 +5807,7 @@ }, "node_modules/mdast-util-gfm-table": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", @@ -7057,8 +5822,7 @@ }, "node_modules/mdast-util-gfm-task-list-item": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", @@ -7072,8 +5836,7 @@ }, "node_modules/mdast-util-phrasing": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" @@ -7084,9 +5847,8 @@ } }, "node_modules/mdast-util-to-hast": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz", - "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==", + "version": "13.2.0", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -7104,15 +5866,15 @@ } }, "node_modules/mdast-util-to-markdown": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", - "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "version": "2.1.2", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" @@ -7124,8 +5886,7 @@ }, "node_modules/mdast-util-to-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" }, @@ -7136,13 +5897,11 @@ }, "node_modules/mdn-data": { "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + "dev": true, + "license": "CC0-1.0" }, "node_modules/meow": { "version": "10.1.5", - "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", - "integrity": "sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==", "dev": true, "license": "MIT", "peer": true, @@ -7169,8 +5928,6 @@ }, "node_modules/meow/node_modules/type-fest": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "dev": true, "license": "(MIT OR CC0-1.0)", "peer": true, @@ -7181,25 +5938,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "version": "4.0.2", "funding": [ { "type": "GitHub Sponsors", @@ -7210,6 +5958,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -7231,9 +5980,7 @@ } }, "node_modules/micromark-core-commonmark": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", - "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", + "version": "2.0.3", "funding": [ { "type": "GitHub Sponsors", @@ -7244,6 +5991,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", @@ -7265,8 +6013,7 @@ }, "node_modules/micromark-extension-gfm": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", @@ -7283,9 +6030,8 @@ } }, "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz", - "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==", + "version": "2.1.0", + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", @@ -7298,9 +6044,8 @@ } }, "node_modules/micromark-extension-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==", + "version": "2.1.0", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", @@ -7317,9 +6062,8 @@ } }, "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", + "version": "2.1.0", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -7334,9 +6078,8 @@ } }, "node_modules/micromark-extension-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", - "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", + "version": "2.1.1", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", @@ -7351,8 +6094,7 @@ }, "node_modules/micromark-extension-gfm-tagfilter": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" }, @@ -7362,9 +6104,8 @@ } }, "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz", - "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==", + "version": "2.1.0", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", @@ -7378,9 +6119,7 @@ } }, "node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7391,6 +6130,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -7398,9 +6138,7 @@ } }, "node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7411,6 +6149,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -7419,9 +6158,7 @@ } }, "node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7432,15 +6169,14 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7451,6 +6187,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -7459,9 +6196,7 @@ } }, "node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7472,6 +6207,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -7480,9 +6216,7 @@ } }, "node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", "funding": [ { "type": "GitHub Sponsors", @@ -7493,15 +6227,14 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7512,14 +6245,13 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7530,6 +6262,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -7537,9 +6270,7 @@ } }, "node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7550,15 +6281,14 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "version": "2.0.2", "funding": [ { "type": "GitHub Sponsors", @@ -7569,14 +6299,13 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7587,6 +6316,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -7595,39 +6325,7 @@ } }, "node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7638,14 +6336,41 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7656,14 +6381,13 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7674,6 +6398,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", @@ -7681,9 +6406,7 @@ } }, "node_modules/micromark-util-subtokenize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", - "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", + "version": "2.1.0", "funding": [ { "type": "GitHub Sponsors", @@ -7694,6 +6417,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -7702,9 +6426,7 @@ } }, "node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", "funding": [ { "type": "GitHub Sponsors", @@ -7714,12 +6436,11 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "version": "2.0.2", "funding": [ { "type": "GitHub Sponsors", @@ -7729,45 +6450,31 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -7775,53 +6482,26 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/min-indent": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, + "license": "MIT", + "peer": true, "engines": { "node": ">=4" } }, "node_modules/mini-svg-data-uri": { "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", "dev": true, + "license": "MIT", "bin": { "mini-svg-data-uri": "cli.js" } }, "node_modules/minimatch": { "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -7834,16 +6514,13 @@ }, "node_modules/minimist": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minimist-options": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "license": "MIT", "peer": true, @@ -7858,18 +6535,16 @@ }, "node_modules/minipass": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=8" } }, "node_modules/minizlib": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -7880,9 +6555,8 @@ }, "node_modules/minizlib/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -7891,49 +6565,42 @@ } }, "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "version": "1.0.4", "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT", - "optional": true - }, "node_modules/mlly": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", - "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", + "version": "1.7.4", "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^8.11.3", - "pathe": "^1.1.2", - "pkg-types": "^1.0.3", - "ufo": "^1.3.2" + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" } }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, "node_modules/monaco-editor": { "name": "@codingame/monaco-vscode-editor-api", "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-editor-api/-/monaco-vscode-editor-api-11.1.2.tgz", - "integrity": "sha512-RYnk0VpL0uSvrFD9k1Oka+K4dP3rhptBzIFVKwjlvCxL0n/mdbECbrcTLKn7wpR11wfMMWvFDHqlNH7ri3rsXg==", + "license": "MIT", "dependencies": { "vscode": "npm:@codingame/monaco-vscode-api@11.1.2" } }, "node_modules/monaco-editor-wrapper": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/monaco-editor-wrapper/-/monaco-editor-wrapper-6.1.1.tgz", - "integrity": "sha512-EvsV/A+Cq3qayz2YoPqoI1qBP8G+nufaBqFG8N4QtpgQAF357ELIUw7Rikmw7Cn2vMc9CAGnhsZdEL2vdvTOTA==", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-chat-extensions-notebook-task-terminal-testing-common": "~11.1.2", @@ -7983,8 +6650,6 @@ }, "node_modules/monaco-graphql": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/monaco-graphql/-/monaco-graphql-1.6.0.tgz", - "integrity": "sha512-KFANLCtgsaHhLAqxiIbwjGwjsO19j1vQhw1iSgaewxr1/RfUEs5FBoUVfq3JITrpgLjBahfcgIWlB0mdgb9RgA==", "license": "MIT", "dependencies": { "graphql-language-service": "^5.3.0", @@ -7998,8 +6663,6 @@ }, "node_modules/monaco-languageclient": { "version": "9.1.1", - "resolved": "https://registry.npmjs.org/monaco-languageclient/-/monaco-languageclient-9.1.1.tgz", - "integrity": "sha512-0S2Ehn5i1nsmgxaX0qWm4c+3pwMN3K3rgXb6vFtCIMzl/bPbqazoKBXFNr6GbUI6l8SpvrDXavLi73Sg3dNNJQ==", "license": "MIT", "dependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~11.1.2", @@ -8608,9 +7271,7 @@ } }, "node_modules/monaco-vim": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/monaco-vim/-/monaco-vim-0.4.1.tgz", - "integrity": "sha512-+cy0TE9xarjLIgUexqxIEbat3K1l7WbiFSLZKAO2kYl1qFRvkeWn4ro/C4c6dK0i9+WQKUC4Dhu/nyCbZfA37w==", + "version": "0.4.2", "license": "MIT", "peerDependencies": { "monaco-editor": "*" @@ -8618,17 +7279,14 @@ }, "node_modules/mri": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/mrmime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", - "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "version": "2.0.1", "dev": true, "license": "MIT", "engines": { @@ -8636,110 +7294,54 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "license": "MIT" }, "node_modules/mz": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "dev": true, + "license": "MIT", "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "license": "MIT", - "optional": true - }, "node_modules/napi-macros": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "license": "MIT", "optional": true }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/natural-compare-lite": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/neo-async": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ngraph.events": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ngraph.events/-/ngraph.events-1.2.2.tgz", - "integrity": "sha512-JsUbEOzANskax+WSYiAPETemLWYXmixuPAlmZmhIbIj6FH/WDgEGCGnRwUQBK0GjOnVm8Ui+e5IJ+5VZ4e32eQ==", "license": "BSD-3-Clause" }, "node_modules/no-case": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, + "license": "MIT", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, - "node_modules/node-abi": { - "version": "3.71.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.71.0.tgz", - "integrity": "sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==", - "license": "MIT", - "optional": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "license": "MIT", - "optional": true - }, "node_modules/node-domexception": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", "funding": [ { "type": "github", @@ -8750,14 +7352,14 @@ "url": "https://paypal.me/jimmywarting" } ], + "license": "MIT", "engines": { "node": ">=10.5.0" } }, "node_modules/node-fetch": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -8774,15 +7376,13 @@ } }, "node_modules/node-fetch-native": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", - "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==", - "dev": true + "version": "1.6.6", + "dev": true, + "license": "MIT" }, "node_modules/node-gyp-build": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz", - "integrity": "sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ==", + "license": "MIT", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -8791,15 +7391,12 @@ } }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true + "version": "2.0.19", + "dev": true, + "license": "MIT" }, "node_modules/normalize-package-data": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "license": "BSD-2-Clause", "peer": true, @@ -8815,54 +7412,24 @@ }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/normalize-range": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/nth-check": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -8872,21 +7439,19 @@ }, "node_modules/nullthrows": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", - "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", "license": "MIT" }, "node_modules/nypm": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.8.tgz", - "integrity": "sha512-IGWlC6So2xv6V4cIDmoV0SwwWx7zLG086gyqkyumteH2fIgCAM4nDVFB2iDRszDvmdSVW9xb1N+2KjQ6C7d4og==", + "version": "0.5.4", "dev": true, + "license": "MIT", "dependencies": { "citty": "^0.1.6", - "consola": "^3.2.3", - "execa": "^8.0.1", - "pathe": "^1.1.2", - "ufo": "^1.4.0" + "consola": "^3.4.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "tinyexec": "^0.3.2", + "ufo": "^1.5.4" }, "bin": { "nypm": "dist/cli.mjs" @@ -8895,42 +7460,33 @@ "node": "^14.16.0 || >=16.10.0" } }, + "node_modules/nypm/node_modules/pathe": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, "node_modules/object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-hash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "version": "1.1.6", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -8941,22 +7497,19 @@ }, "node_modules/object-keys": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/ohash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", - "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", - "dev": true + "version": "1.1.6", + "dev": true, + "license": "MIT" }, "node_modules/ol": { "version": "7.5.2", - "resolved": "https://registry.npmjs.org/ol/-/ol-7.5.2.tgz", - "integrity": "sha512-HJbb3CxXrksM6ct367LsP3N+uh+iBBMdP3DeGGipdV9YAYTP0vTJzqGnoqQ6C2IW4qf8krw9yuyQbc9fjOIaOQ==", + "license": "BSD-2-Clause", "dependencies": { "earcut": "^2.2.3", "geotiff": "^2.0.7", @@ -8971,8 +7524,7 @@ }, "node_modules/ol-mapbox-style": { "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-10.7.0.tgz", - "integrity": "sha512-S/UdYBuOjrotcR95Iq9AejGYbifKeZE85D9VtH11ryJLQPTZXZSW1J5bIXcr4AlAH6tyjPPHTK34AdkwB32Myw==", + "license": "BSD-2-Clause", "dependencies": { "@mapbox/mapbox-gl-style-spec": "^13.23.1", "mapbox-to-css-font": "^2.4.1", @@ -8981,84 +7533,69 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "devOptional": true, + "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/openai": { - "version": "4.57.2", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.57.2.tgz", - "integrity": "sha512-IgIxNjo9tfgnfx6gmwNMg3tdF9giK/2lbwG5DY7zs4TP9Gz+h6h2hBOMoalLPFUVOO5HLOgMI/PFV5VDAUvvMg==", + "version": "4.87.1", + "license": "Apache-2.0", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", - "@types/qs": "^6.9.7", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "qs": "^6.10.3" + "node-fetch": "^2.6.7" }, "bin": { "openai": "bin/cli" }, "peerDependencies": { + "ws": "^8.18.0", "zod": "^3.23.8" }, "peerDependenciesMeta": { + "ws": { + "optional": true + }, "zod": { "optional": true } } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.18.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.9.tgz", - "integrity": "sha512-0f5klcuImLnG4Qreu9hPj/rEfFq6YRc5n2mAjSsH+ec/mJL+3voBH0+8T7o8RpFjH7ovc+TRsL/c7OYIQsPTfQ==", + "version": "18.19.80", + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "license": "MIT" + }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/p-limit": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.1.0.tgz", - "integrity": "sha512-H0jc0q1vOzlEk0TqAKXKZxdl7kX3OFUzCnNVUnq5Pc3DGo0kpeaMuPqxQn235HibwBEb0/pm9dgKTjXy66fBkg==", + "version": "6.2.0", "license": "MIT", "dependencies": { "yocto-queue": "^1.1.1" @@ -9072,9 +7609,8 @@ }, "node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -9087,8 +7623,6 @@ }, "node_modules/p-locate/node_modules/p-limit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9103,8 +7637,6 @@ }, "node_modules/p-locate/node_modules/yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "engines": { @@ -9114,15 +7646,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", - "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + "license": "(MIT AND Zlib)" }, "node_modules/panzoom": { "version": "9.4.3", - "resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.3.tgz", - "integrity": "sha512-xaxCpElcRbQsUtIdwlrZA90P90+BHip4Vda2BC8MEb4tkI05PmR6cKECdqUCZ85ZvBHjpI9htJrZBxV5Gp/q/w==", "license": "MIT", "dependencies": { "amator": "^1.1.0", @@ -9132,14 +7666,12 @@ }, "node_modules/parchment": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz", - "integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==" + "license": "BSD-3-Clause" }, "node_modules/parent-module": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -9149,13 +7681,10 @@ }, "node_modules/parse-headers": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", - "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" + "license": "MIT" }, "node_modules/parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "license": "MIT", "peer": true, @@ -9174,8 +7703,6 @@ }, "node_modules/parse5": { "version": "7.2.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", - "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "license": "MIT", "dependencies": { "entities": "^4.5.0" @@ -9186,9 +7713,8 @@ }, "node_modules/pascal-case": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -9196,56 +7722,68 @@ }, "node_modules/path-browserify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-parse": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "dev": true, + "license": "ISC" }, "node_modules/path-type": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path2d": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.2.tgz", - "integrity": "sha512-+vnG6S4dYcYxZd+CZxzXCNKdELYZSKfohrk98yajCo1PtRoDgCTrrwOvK1GT0UoAdVszagDVllQc0U1vaX4NUQ==", "license": "MIT", "optional": true, "engines": { @@ -9254,14 +7792,12 @@ }, "node_modules/pathe": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pbf": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", - "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", + "license": "BSD-3-Clause", "dependencies": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" @@ -9272,8 +7808,6 @@ }, "node_modules/pdfjs-dist": { "version": "4.8.69", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.8.69.tgz", - "integrity": "sha512-IHZsA4T7YElCKNNXtiLgqScw4zPd3pG9do8UrznC757gMd7UPeHSL2qwNNMJo4r79fl8oj1Xx+1nh2YkzdMpLQ==", "license": "Apache-2.0", "engines": { "node": ">=18" @@ -9285,14 +7819,13 @@ }, "node_modules/perfect-debounce": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", - "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/periscopic": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", - "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^3.0.0", @@ -9301,14 +7834,23 @@ }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/picomatch-browser": { "version": "2.2.6", - "resolved": "https://registry.npmjs.org/picomatch-browser/-/picomatch-browser-2.2.6.tgz", - "integrity": "sha512-0ypsOQt9D4e3hziV8O4elD9uN0z/jtUEfxVRtNaAAtXIyUx9m/SzlO020i8YNL2aL/E6blOvvHQcin6HZlFy/w==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -9318,61 +7860,61 @@ }, "node_modules/pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/pirates": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "version": "1.3.1", "dev": true, + "license": "MIT", "dependencies": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" } }, - "node_modules/playwright": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.0.tgz", - "integrity": "sha512-gyHAgQjiDf1m34Xpwzaqb76KgfzYrhK7iih+2IzcOCoZWr/8ZqmdBw+t0RU85ZmfJMgtgAiNtBQ/KS2325INXw==", + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.3", "dev": true, + "license": "MIT" + }, + "node_modules/playwright": { + "version": "1.51.0", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.40.0" + "playwright-core": "1.51.0" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.0.tgz", - "integrity": "sha512-fvKewVJpGeca8t0ipM56jkVSU6Eo0RmFvQ/MaCQNDYm+sdvKkMBBWTE1FdeMqIdumRaXXjZChWHvIzCGM/tA/Q==", + "version": "1.51.0", "dev": true, + "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/playwright/node_modules/fsevents": { @@ -9381,6 +7923,7 @@ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -9390,9 +7933,7 @@ } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.3", "dev": true, "funding": [ { @@ -9408,8 +7949,9 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -9419,9 +7961,8 @@ }, "node_modules/postcss-calc": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", - "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0" @@ -9434,10 +7975,9 @@ } }, "node_modules/postcss-calc/node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.1.2", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -9447,92 +7987,85 @@ } }, "node_modules/postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", + "version": "6.1.0", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "caniuse-api": "^3.0.0", - "colord": "^2.9.1", + "colord": "^2.9.3", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", + "version": "6.1.0", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", + "version": "6.0.2", "dev": true, + "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", + "version": "6.0.3", "dev": true, + "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", + "version": "6.0.3", "dev": true, + "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", + "version": "6.0.2", "dev": true, + "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-import": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -9547,9 +8080,8 @@ }, "node_modules/postcss-js": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "dev": true, + "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" }, @@ -9565,21 +8097,26 @@ } }, "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "version": "4.0.2", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" }, "engines": { "node": ">= 14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" @@ -9594,44 +8131,53 @@ } }, "node_modules/postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", + "version": "6.0.5", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" + "stylehacks": "^6.1.1" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-merge-rules": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", - "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", + "version": "6.1.1", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" } }, "node_modules/postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", + "version": "6.1.0", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -9639,82 +8185,95 @@ "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", + "version": "6.0.3", "dev": true, + "license": "MIT", "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", + "version": "6.1.0", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", + "version": "6.0.4", "dev": true, + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.5" + "postcss-selector-parser": "^6.0.16" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" } }, "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "version": "6.2.0", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.11" + "postcss-selector-parser": "^6.1.1" }, "engines": { "node": ">=12.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.2.14" } }, "node_modules/postcss-nested/node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.1.2", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -9724,22 +8283,20 @@ } }, "node_modules/postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", + "version": "6.0.2", "dev": true, + "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", + "version": "6.0.2", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -9747,14 +8304,13 @@ "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", + "version": "6.0.2", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -9762,14 +8318,13 @@ "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", + "version": "6.0.2", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -9777,14 +8332,13 @@ "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", + "version": "6.0.2", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -9792,14 +8346,13 @@ "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", + "version": "6.0.2", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -9807,30 +8360,28 @@ "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", + "version": "6.1.0", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", + "version": "6.0.2", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -9838,14 +8389,13 @@ "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", + "version": "6.0.2", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -9853,46 +8403,43 @@ "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", + "version": "6.0.2", "dev": true, + "license": "MIT", "dependencies": { - "cssnano-utils": "^4.0.0", + "cssnano-utils": "^4.0.2", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", + "version": "6.1.0", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "caniuse-api": "^3.0.0" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", + "version": "6.0.2", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -9900,22 +8447,19 @@ "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-resolve-nested-selector": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz", - "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==", "dev": true, "license": "MIT", "peer": true }, "node_modules/postcss-safe-parser": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.0" }, @@ -9929,8 +8473,6 @@ }, "node_modules/postcss-scss": { "version": "4.0.9", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", - "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", "dev": true, "funding": [ { @@ -9946,6 +8488,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "engines": { "node": ">=12.0" }, @@ -9955,9 +8498,8 @@ }, "node_modules/postcss-selector-parser": { "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -9967,102 +8509,139 @@ } }, "node_modules/postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", + "version": "6.0.3", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" + "svgo": "^3.2.0" }, "engines": { "node": "^14 || ^16 || >= 18" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", + "version": "6.0.4", "dev": true, + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.5" + "postcss-selector-parser": "^6.0.16" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" } }, "node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/prebuild-install": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", - "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.9", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, "bin": { - "prebuild-install": "bin.js" + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">=10" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/prebuild-install/node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "mimic-response": "^3.1.0" + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prebuild-install/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "node_modules/prettier-plugin-svelte": { + "version": "3.3.3", + "dev": true, "license": "MIT", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "prettier": "^3.0.0", + "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, - "node_modules/prebuild-install/node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "node_modules/property-information": { + "version": "7.0.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/prr": { + "version": "1.0.1", + "license": "MIT", + "optional": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quadprog": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.x" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, "funding": [ { "type": "github", @@ -10077,142 +8656,11 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "optional": true, - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-plugin-svelte": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-2.10.1.tgz", - "integrity": "sha512-Wlq7Z5v2ueCubWo0TZzKc9XHcm7TDxqcuzRuGd0gcENfzfT4JZ9yDlCbEgxWgiPmLHkBjfOtpAWkcT28MCDpUQ==", - "dev": true, - "peerDependencies": { - "prettier": "^1.16.4 || ^2.0.0", - "svelte": "^3.2.0 || ^4.0.0-next.0" - } - }, - "node_modules/property-information": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", - "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/protocol-buffers-schema": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", - "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, "license": "MIT" }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "optional": true - }, - "node_modules/pump": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "license": "MIT", - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/quadprog": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/quadprog/-/quadprog-1.6.1.tgz", - "integrity": "sha512-fN5Jkcjlln/b3pJkseDKREf89JkKIyu6cKIVXisgL6ocKPQ0yTp9n6NZUAq3otEPPw78WZMG9K0o9WsfKyMWJw==", - "dev": true, - "engines": { - "node": ">=8.x" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/quick-lru": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz", - "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -10222,13 +8670,11 @@ }, "node_modules/quickselect": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + "license": "ISC" }, "node_modules/quill": { "version": "1.3.7", - "resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz", - "integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==", + "license": "BSD-3-Clause", "dependencies": { "clone": "^2.1.1", "deep-equal": "^1.0.1", @@ -10240,8 +8686,7 @@ }, "node_modules/quill-delta": { "version": "3.6.3", - "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz", - "integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==", + "license": "MIT", "dependencies": { "deep-equal": "^1.0.1", "extend": "^3.0.2", @@ -10253,43 +8698,15 @@ }, "node_modules/rbush": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", - "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "license": "MIT", "dependencies": { "quickselect": "^2.0.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "optional": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/rc9": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", - "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", "dev": true, + "license": "MIT", "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" @@ -10297,17 +8714,14 @@ }, "node_modules/read-cache": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^2.3.0" } }, "node_modules/read-pkg": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", - "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", "dev": true, "license": "MIT", "peer": true, @@ -10326,8 +8740,6 @@ }, "node_modules/read-pkg-up": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", - "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", "dev": true, "license": "MIT", "peer": true, @@ -10345,8 +8757,6 @@ }, "node_modules/read-pkg-up/node_modules/type-fest": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "dev": true, "license": "(MIT OR CC0-1.0)", "peer": true, @@ -10359,8 +8769,6 @@ }, "node_modules/read-pkg/node_modules/type-fest": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "dev": true, "license": "(MIT OR CC0-1.0)", "peer": true, @@ -10373,8 +8781,7 @@ }, "node_modules/readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "optional": true, "dependencies": { "inherits": "^2.0.3", @@ -10386,33 +8793,19 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "version": "4.1.2", "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, + "license": "MIT", "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" + "node": ">= 14.18.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/redent": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", - "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", "dev": true, "license": "MIT", "peer": true, @@ -10428,18 +8821,19 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + "version": "0.14.1", + "license": "MIT" }, "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "version": "1.5.4", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -10450,8 +8844,6 @@ }, "node_modules/rehype-github-alerts": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rehype-github-alerts/-/rehype-github-alerts-3.0.0.tgz", - "integrity": "sha512-m8Lm+V0Ee0T9JqaLN0eBqtyUSfMUDFhAOIjbvoAQfI6EKtxKsIGWP6PaQE01UBHat0K7dBtnaeyCmJuUO7ylHg==", "license": "MIT", "dependencies": { "hast-util-from-html": "^2.0.1", @@ -10461,8 +8853,6 @@ }, "node_modules/rehype-raw": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", - "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -10475,9 +8865,8 @@ } }, "node_modules/remark-gfm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", - "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "version": "4.0.1", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", @@ -10493,8 +8882,7 @@ }, "node_modules/remark-parse": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -10507,9 +8895,8 @@ } }, "node_modules/remark-rehype": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", - "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "version": "11.1.1", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -10524,8 +8911,7 @@ }, "node_modules/remark-stringify": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", @@ -10538,8 +8924,6 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, "license": "MIT", "peer": true, @@ -10548,59 +8932,56 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/resolve-protobuf-schema": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", - "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", "dependencies": { "protocol-buffers-schema": "^3.3.1" } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, "node_modules/rfc4648": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/rfc4648/-/rfc4648-1.5.3.tgz", - "integrity": "sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==" + "version": "1.5.4", + "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -10612,13 +8993,11 @@ } }, "node_modules/rollup": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", - "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", + "version": "4.35.0", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -10628,29 +9007,44 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.20.0", - "@rollup/rollup-android-arm64": "4.20.0", - "@rollup/rollup-darwin-arm64": "4.20.0", - "@rollup/rollup-darwin-x64": "4.20.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", - "@rollup/rollup-linux-arm-musleabihf": "4.20.0", - "@rollup/rollup-linux-arm64-gnu": "4.20.0", - "@rollup/rollup-linux-arm64-musl": "4.20.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", - "@rollup/rollup-linux-riscv64-gnu": "4.20.0", - "@rollup/rollup-linux-s390x-gnu": "4.20.0", - "@rollup/rollup-linux-x64-gnu": "4.20.0", - "@rollup/rollup-linux-x64-musl": "4.20.0", - "@rollup/rollup-win32-arm64-msvc": "4.20.0", - "@rollup/rollup-win32-ia32-msvc": "4.20.0", - "@rollup/rollup-win32-x64-msvc": "4.20.0", + "@rollup/rollup-android-arm-eabi": "4.35.0", + "@rollup/rollup-android-arm64": "4.35.0", + "@rollup/rollup-darwin-arm64": "4.35.0", + "@rollup/rollup-darwin-x64": "4.35.0", + "@rollup/rollup-freebsd-arm64": "4.35.0", + "@rollup/rollup-freebsd-x64": "4.35.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.35.0", + "@rollup/rollup-linux-arm-musleabihf": "4.35.0", + "@rollup/rollup-linux-arm64-gnu": "4.35.0", + "@rollup/rollup-linux-arm64-musl": "4.35.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.35.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0", + "@rollup/rollup-linux-riscv64-gnu": "4.35.0", + "@rollup/rollup-linux-s390x-gnu": "4.35.0", + "@rollup/rollup-linux-x64-gnu": "4.35.0", + "@rollup/rollup-linux-x64-musl": "4.35.0", + "@rollup/rollup-win32-arm64-msvc": "4.35.0", + "@rollup/rollup-win32-ia32-msvc": "4.35.0", + "@rollup/rollup-win32-x64-msvc": "4.35.0", "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz", + "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -10666,20 +9060,19 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/rw": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + "license": "BSD-3-Clause" }, "node_modules/sade": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dev": true, + "license": "MIT", "dependencies": { "mri": "^1.1.0" }, @@ -10689,8 +9082,6 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -10705,39 +9096,12 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "optional": true }, - "node_modules/sander": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", - "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", - "dev": true, - "dependencies": { - "es6-promise": "^3.1.2", - "graceful-fs": "^4.1.3", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.2" - } - }, - "node_modules/sander/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "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==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.7.1", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -10746,15 +9110,13 @@ } }, "node_modules/set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", - "dev": true + "version": "2.7.1", + "dev": true, + "license": "MIT" }, "node_modules/set-function-length": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -10768,13 +9130,13 @@ } }, "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "version": "2.0.2", + "license": "MIT", "dependencies": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10782,9 +9144,8 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -10794,73 +9155,29 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, + "node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true - }, - "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "license": "MIT", - "optional": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/simple-svelte-autocomplete": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/simple-svelte-autocomplete/-/simple-svelte-autocomplete-2.5.2.tgz", - "integrity": "sha512-6+kZP3XQGb7zs0djTWoFv8tQorBZdv64YfCKrlsYIYBCFsEeikSiNsBSSYw1Om+LYmFeMEOAYSSKoEw+qpnBXQ==", "dev": true }, "node_modules/sirv": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz", - "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==", + "version": "3.0.1", "dev": true, "license": "MIT", "dependencies": { @@ -10874,17 +9191,14 @@ }, "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/slice-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "license": "MIT", "peer": true, @@ -10900,41 +9214,20 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/sorcery": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", - "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.14", - "buffer-crc32": "^0.2.5", - "minimist": "^1.2.0", - "sander": "^0.5.0" - }, - "bin": { - "sorcery": "bin/sorcery" - } - }, "node_modules/sort-asc": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.1.0.tgz", - "integrity": "sha512-jBgdDd+rQ+HkZF2/OHCmace5dvpos/aWQpcxuyRs9QUbPRnkEJmYVo81PIGpjIdpOcsnJ4rGjStfDHsbn+UVyw==", "engines": { "node": ">=0.10.0" } }, "node_modules/sort-desc": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.1.1.tgz", - "integrity": "sha512-jfZacW5SKOP97BF5rX5kQfJmRVZP5/adDUTY8fCSPvNcXDVpUEe2pr/iKGlcyZzchRJZrswnp68fgk3qBXgkJw==", "engines": { "node": ">=0.10.0" } }, "node_modules/sort-object": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-0.3.2.tgz", - "integrity": "sha512-aAQiEdqFTTdsvUFxXm3umdo04J7MRljoVGbBlkH7BgNsMvVNAJyGj7C/wV1A8wHWAJj/YikeZbfuCKqhggNWGA==", "dependencies": { "sort-asc": "^0.1.0", "sort-desc": "^0.1.1" @@ -10945,25 +9238,22 @@ }, "node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/space-separated-tokens": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", "license": "MIT", "funding": { "type": "github", @@ -10972,8 +9262,6 @@ }, "node_modules/spdx-correct": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -10984,16 +9272,12 @@ }, "node_modules/spdx-exceptions": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true, "license": "CC-BY-3.0", "peer": true }, "node_modules/spdx-expression-parse": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "license": "MIT", "peer": true, @@ -11003,17 +9287,14 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.20", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", - "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "version": "3.0.21", "dev": true, "license": "CC0-1.0", "peer": true }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "optional": true, "dependencies": { "safe-buffer": "~5.2.0" @@ -11021,10 +9302,22 @@ }, "node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "peer": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -11036,9 +9329,8 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -11046,22 +9338,20 @@ "node": ">=8" } }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", "dev": true, - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8" } }, "node_modules/strip-indent": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", - "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", "dev": true, "license": "MIT", "peer": true, @@ -11077,9 +9367,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -11089,41 +9378,47 @@ }, "node_modules/style-search": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", "dev": true, "license": "ISC", "peer": true }, "node_modules/style-to-object": { "version": "0.4.4", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", - "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", "dev": true, + "license": "MIT", "dependencies": { "inline-style-parser": "0.1.1" } }, "node_modules/stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", + "version": "6.1.1", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" }, "engines": { "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" + } + }, + "node_modules/stylehacks/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" } }, "node_modules/stylelint": { "version": "15.11.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-15.11.0.tgz", - "integrity": "sha512-78O4c6IswZ9TzpcIiQJIN49K3qNoXTM8zEJzhaTE/xRTCZswaovSEVIa/uwbOltZrk16X4jAxjaOhzz/hTm1Kw==", "dev": true, "license": "MIT", "peer": true, @@ -11182,9 +9477,8 @@ }, "node_modules/stylelint-config-recommended": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-13.0.0.tgz", - "integrity": "sha512-EH+yRj6h3GAe/fRiyaoO2F9l9Tgg50AOFhaszyfov9v6ayXJ1IkSHwTxd7lB48FmOeSGDPLjatjO11fJpmarkQ==", "dev": true, + "license": "MIT", "engines": { "node": "^14.13.1 || >=16.0.0" }, @@ -11194,8 +9488,6 @@ }, "node_modules/stylelint/node_modules/@csstools/selector-specificity": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz", - "integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==", "dev": true, "funding": [ { @@ -11218,16 +9510,12 @@ }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", "dev": true, "license": "MIT", "peer": true }, "node_modules/stylelint/node_modules/file-entry-cache": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-7.0.2.tgz", - "integrity": "sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==", "dev": true, "license": "MIT", "peer": true, @@ -11238,10 +9526,14 @@ "node": ">=12.0.0" } }, + "node_modules/stylelint/node_modules/known-css-properties": { + "version": "0.29.0", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/stylelint/node_modules/postcss-selector-parser": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "license": "MIT", "peer": true, @@ -11255,8 +9547,6 @@ }, "node_modules/stylelint/node_modules/resolve-from": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", "peer": true, @@ -11265,14 +9555,13 @@ } }, "node_modules/sucrase": { - "version": "3.34.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", - "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", + "version": "3.35.0", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "7.1.6", + "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", @@ -11283,65 +9572,62 @@ "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">=8" - } - }, - "node_modules/sucrase/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node": ">=16 || 14 >=14.17" } }, "node_modules/sucrase/node_modules/commander": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/sucrase/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "10.4.5", "dev": true, + "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": "*" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/sucrase/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.5", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minipass": { + "version": "7.1.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" } }, "node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11350,9 +9636,7 @@ } }, "node_modules/supports-hyperlinks": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz", - "integrity": "sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==", + "version": "3.2.0", "dev": true, "license": "MIT", "peer": true, @@ -11364,14 +9648,13 @@ "node": ">=14.18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -11380,9 +9663,197 @@ } }, "node_modules/svelte": { - "version": "4.2.19", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", - "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", + "version": "5.22.6", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "acorn": "^8.12.1", + "aria-query": "^5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "esm-env": "^1.2.1", + "esrap": "^1.4.3", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte-awesome-color-picker": { + "version": "3.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "colord": "^2.9.3", + "svelte-awesome-slider": "^1.1.2" + }, + "peerDependencies": { + "svelte": "^3.55.1 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/svelte-awesome-slider": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "svelte": "^3.54.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/svelte-carousel": { + "version": "1.0.25", + "license": "Apache-2.0", + "dependencies": { + "easy-reactive": "1.0.4" + } + }, + "node_modules/svelte-check": { + "version": "4.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, + "node_modules/svelte-check/node_modules/fdir": { + "version": "6.4.3", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/svelte-check/node_modules/picomatch": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/svelte-eslint-parser": { + "version": "0.43.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "postcss": "^8.4.39", + "postcss-scss": "^4.0.9" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/svelte-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/svelte-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/svelte-exmarkdown": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "remark-gfm": "^4.0.1", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.1.1", + "unified": "^11.0.5" + }, + "peerDependencies": { + "svelte": "^5.1.3" + } + }, + "node_modules/svelte-floating-ui": { + "version": "1.5.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.5.0", + "@floating-ui/dom": "^1.5.3" + } + }, + "node_modules/svelte-highlight": { + "version": "7.8.2", + "dev": true, + "license": "MIT", + "dependencies": { + "highlight.js": "11.11.1" + } + }, + "node_modules/svelte-infinite-loading": { + "version": "1.4.0", + "license": "MIT" + }, + "node_modules/svelte-multiselect": { + "version": "11.0.0-rc.1", + "dev": true, + "license": "MIT", + "dependencies": { + "svelte": "4.2.12" + } + }, + "node_modules/svelte-multiselect/node_modules/svelte": { + "version": "4.2.12", + "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -11404,217 +9875,35 @@ "node": ">=16" } }, - "node_modules/svelte-awesome-color-picker": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/svelte-awesome-color-picker/-/svelte-awesome-color-picker-3.0.4.tgz", - "integrity": "sha512-nlujXJV7uG2xfyMwjoJDxFqhV+geC9gD/AKs9+wRE3hu4o85nIDE9jjh6lFIMMugzPF5t0M55fCSlENw4kzKOQ==", - "dev": true, - "dependencies": { - "colord": "^2.9.3", - "svelte-awesome-slider": "^1.1.0" - }, - "peerDependencies": { - "svelte": "^3.55.1 || ^4.0.0" - } - }, - "node_modules/svelte-awesome-slider": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/svelte-awesome-slider/-/svelte-awesome-slider-1.1.0.tgz", - "integrity": "sha512-MgY6ZdBON42HVZqNWNjq2HOgyDlC35q0TNbV/YO1l1/bcb5yhM8EE97h1AJ/7F6t6sLzXhQ3qPf5nGyCdDSnCg==", - "dev": true, - "peerDependencies": { - "svelte": "^3.54.0 || ^4.0.0" - } - }, - "node_modules/svelte-carousel": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/svelte-carousel/-/svelte-carousel-1.0.25.tgz", - "integrity": "sha512-vR/AbGYwlh3fgWaB5PJg+iqZFvoVCJq4JWdmlXvPtdG9TLlKJWBcoiKlMZt3MnFF7AqNW46tOH/O+uVMWQzyWQ==", - "dependencies": { - "easy-reactive": "1.0.4" - } - }, - "node_modules/svelte-chartjs": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/svelte-chartjs/-/svelte-chartjs-3.1.5.tgz", - "integrity": "sha512-ka2zh7v5FiwfAX1oMflZ0HkNkgjHjFqANgRyC+vNYXfxtx2ku68Zo+2KgbKeBH2nS1ThDqkIACPzGxy4T0UaoA==", - "peerDependencies": { - "chart.js": "^3.5.0 || ^4.0.0", - "svelte": "^4.0.0" - } - }, - "node_modules/svelte-check": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.0.tgz", - "integrity": "sha512-8VfqhfuRJ1sKW+o8isH2kPi0RhjXH1nNsIbCFGyoUHG+ZxVxHYRKcb+S8eaL/1tyj3VGvWYx3Y5+oCUsJgnzcw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "chokidar": "^3.4.1", - "fast-glob": "^3.2.7", - "import-fresh": "^3.2.1", - "picocolors": "^1.0.0", - "sade": "^1.7.4", - "svelte-preprocess": "^5.1.0", - "typescript": "^5.0.3" - }, - "bin": { - "svelte-check": "bin/svelte-check" - }, - "peerDependencies": { - "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" - } - }, - "node_modules/svelte-eslint-parser": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz", - "integrity": "sha512-vo7xPGTlKBGdLH8T5L64FipvTrqv3OQRx9d2z5X05KKZDlF4rQk8KViZO4flKERY+5BiVdOh7zZ7JGJWo5P0uA==", - "dev": true, - "dependencies": { - "eslint-scope": "^7.0.0", - "eslint-visitor-keys": "^3.0.0", - "espree": "^9.0.0", - "postcss": "^8.4.29", - "postcss-scss": "^4.0.8" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "svelte": "^3.37.0 || ^4.0.0" - }, - "peerDependenciesMeta": { - "svelte": { - "optional": true - } - } - }, - "node_modules/svelte-eslint-parser/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/svelte-eslint-parser/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/svelte-exmarkdown": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/svelte-exmarkdown/-/svelte-exmarkdown-3.0.5.tgz", - "integrity": "sha512-x0ELw7oTziBaJLFsdGZaoursycGK9HPzxRTRZ/rBi2KmseFG29ryyborJxFmeE0X6ORrEW1pRjoi8q41xpIeRQ==", - "dependencies": { - "remark-gfm": "^4.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "unified": "^11.0.0" - }, - "peerDependencies": { - "svelte": "^3.47.0 || ^4.0.0 || >=5.0.0-next.115" - } - }, - "node_modules/svelte-floating-ui": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.5.8.tgz", - "integrity": "sha512-dVvJhZ2bT+kQDHlE4Lep8t+sgEc0XD96fXLzAi2DDI2bsaegBbClxXVNMma0C2WsG+n9GJSYx292dTvA8CYRtw==", - "dev": true, - "dependencies": { - "@floating-ui/core": "^1.5.0", - "@floating-ui/dom": "^1.5.3" - } - }, - "node_modules/svelte-highlight": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/svelte-highlight/-/svelte-highlight-7.6.0.tgz", - "integrity": "sha512-J9X1d07iMIKZMAqNAhlkjLX/FS+7R2lPrqVul7i+EleVZIOYvBhtx7ES62bc661a70nKNOS05yr9JAvyQPPOIA==", - "dev": true, - "dependencies": { - "highlight.js": "11.9.0" - } - }, - "node_modules/svelte-hmr": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", - "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", - "dev": true, - "engines": { - "node": "^12.20 || ^14.13.1 || >= 16" - }, - "peerDependencies": { - "svelte": "^3.19.0 || ^4.0.0" - } - }, - "node_modules/svelte-infinite-loading": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/svelte-infinite-loading/-/svelte-infinite-loading-1.4.0.tgz", - "integrity": "sha512-Jo+f/yr/HmZQuIiiKKzAHVFXdAUWHW2RBbrcQTil8JVk1sCm/riy7KTJVzjBgQvHasrFQYKF84zvtc9/Y4lFYg==", - "license": "MIT" - }, - "node_modules/svelte-multiselect": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/svelte-multiselect/-/svelte-multiselect-10.2.0.tgz", - "integrity": "sha512-nbv0dTgSHGENbwKdiN5seFD4ljtGSAEZGcMkHfcc+Nnk7tVwM2jxvCgkRKp9FdPUKG1M6Zp8ZXLDU+xoZxHyTA==", - "dev": true, - "dependencies": { - "svelte": "^4.2.0" - } - }, "node_modules/svelte-popperjs": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svelte-popperjs/-/svelte-popperjs-1.3.2.tgz", - "integrity": "sha512-fwrErlkvngL876WXRnL3OLlfk/n9YkZwwLxuKRpZOYCJLt1zrwhoKTXS+/sRgDveD/zd6GQ35hV89EOip+NBGA==", "dev": true, + "license": "MIT", "peerDependencies": { "@popperjs/core": ">=2", "svelte": ">=3" } }, "node_modules/svelte-preprocess": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz", - "integrity": "sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==", + "version": "6.0.3", "dev": true, "hasInstallScript": true, - "dependencies": { - "@types/pug": "^2.0.6", - "detect-indent": "^6.1.0", - "magic-string": "^0.30.5", - "sorcery": "^0.11.0", - "strip-indent": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 16.0.0" + "node": ">= 18.0.0" }, "peerDependencies": { "@babel/core": "^7.10.2", "coffeescript": "^2.5.1", "less": "^3.11.3 || ^4.0.0", "postcss": "^7 || ^8", - "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", + "postcss-load-config": ">=3", "pug": "^3.0.0", "sass": "^1.26.8", - "stylus": "^0.55.0", + "stylus": ">=0.55", "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", - "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0", - "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" + "svelte": "^4.0.0 || ^5.0.0-next.100 || ^5.0.0", + "typescript": "^5.0.0" }, "peerDependenciesMeta": { "@babel/core": { @@ -11649,46 +9938,30 @@ } } }, - "node_modules/svelte-preprocess/node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/svelte-range-slider-pips": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/svelte-range-slider-pips/-/svelte-range-slider-pips-2.3.1.tgz", - "integrity": "sha512-P29PNqHld+SiaDuHzf98rLvhSYWXb3TVL9p7U5RG9UX8emUgypZgp9zuIIwpmIXysGQC6JG8duMc5FuaPnSVdg==", - "dev": true + "dev": true, + "license": "MPL-2.0" }, "node_modules/svelte-splitpanes": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/svelte-splitpanes/-/svelte-splitpanes-0.8.0.tgz", - "integrity": "sha512-cdtSUG8GE8eCAY+TiIGJmnEqV0GC1k/7lwWqovN0qTbw7OIAKEA2BWvqnZ/jk7UzSLlzdI2Uxxm4shXgCdN1kQ==", + "version": "8.0.9", "dev": true, + "license": "MIT", "dependencies": { "esm-env-robust": "0.0.3" }, "peerDependencies": { - "svelte": "^4.0.2" + "svelte": "^4.2.19 || ^5.1.0" } }, "node_modules/svelte-tiny-virtual-list": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/svelte-tiny-virtual-list/-/svelte-tiny-virtual-list-2.0.5.tgz", - "integrity": "sha512-xg9ckb8UeeIme4/5qlwCrl2QNmUZ8SCQYZn3Ji83cUsoASqRNy3KWjpmNmzYvPDqCHSZjruBBsoB7t5hwuzw5g==" + "version": "2.1.2", + "license": "MIT" }, "node_modules/svelte2tsx": { - "version": "0.6.25", - "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.6.25.tgz", - "integrity": "sha512-hhBKL5X9gGvKQAZ9xLoHnbE9Yb00HxEZJlxcj2drxWK+Tpqcs/bnodjSfCGbqEhvNaUXYNbVL7s4dEXT+o0f6w==", + "version": "0.6.27", "dev": true, + "license": "MIT", "dependencies": { "dedent-js": "^1.0.1", "pascal-case": "^3.1.1" @@ -11700,22 +9973,20 @@ }, "node_modules/svg-tags": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true, "peer": true }, "node_modules/svgo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.3.tgz", - "integrity": "sha512-X4UZvLhOglD5Xrp834HzGHf8RKUW0Ahigg/08yRO1no9t2NxffOkMiQ0WmaMIbaGlVTlSst2zWANsdhz5ybXgA==", + "version": "3.3.2", "dev": true, + "license": "MIT", "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^5.1.0", - "css-tree": "^2.2.1", - "csso": "5.0.5", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", "picocolors": "^1.0.0" }, "bin": { @@ -11731,24 +10002,19 @@ }, "node_modules/svgo/node_modules/commander": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/tabbable": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", "dev": true, "license": "MIT" }, "node_modules/table": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", - "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "version": "6.9.0", "dev": true, "license": "BSD-3-Clause", "peer": true, @@ -11765,8 +10031,6 @@ }, "node_modules/table/node_modules/ajv": { "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "peer": true, @@ -11783,49 +10047,45 @@ }, "node_modules/table/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT", "peer": true }, "node_modules/tailwind-merge": { "version": "1.14.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz", - "integrity": "sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/dcastil" } }, "node_modules/tailwindcss": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", - "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "version": "3.4.17", "dev": true, + "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.3.0", + "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.19.1", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", @@ -11835,23 +10095,44 @@ "node": ">=14.0.0" } }, - "node_modules/tailwindcss/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/tailwindcss/node_modules/chokidar": { + "version": "3.6.0", "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=10.13.0" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/tailwindcss/node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.1.2", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -11860,11 +10141,21 @@ "node": ">=4" } }, - "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "node_modules/tailwindcss/node_modules/readdirp": { + "version": "3.6.0", "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "dev": true, + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -11877,75 +10168,23 @@ "node": ">=10" } }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "license": "MIT", - "optional": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC", - "optional": true - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/thenify": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dev": true, + "license": "MIT", "dependencies": { "any-promise": "^1.0.0" } }, "node_modules/thenify-all": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "dev": true, + "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -11953,21 +10192,15 @@ "node": ">=0.8" } }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "node_modules/tinyexec": { + "version": "0.3.2", "dev": true, - "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -11977,8 +10210,6 @@ }, "node_modules/totalist": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true, "license": "MIT", "engines": { @@ -11987,13 +10218,11 @@ }, "node_modules/tr46": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "license": "MIT" }, "node_modules/trim-lines": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -12001,8 +10230,6 @@ }, "node_modules/trim-newlines": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.1.1.tgz", - "integrity": "sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==", "dev": true, "license": "MIT", "peer": true, @@ -12015,8 +10242,7 @@ }, "node_modules/trough": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -12024,21 +10250,17 @@ }, "node_modules/ts-interface-checker": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tsutils": { "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -12051,28 +10273,13 @@ }, "node_modules/tsutils/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } + "dev": true, + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -12082,9 +10289,8 @@ }, "node_modules/type-fest": { "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -12093,10 +10299,9 @@ } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.8.2", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12106,16 +10311,14 @@ } }, "node_modules/ufo": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", - "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", - "dev": true + "version": "1.5.4", + "dev": true, + "license": "MIT" }, "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "version": "3.19.3", "dev": true, + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -12125,14 +10328,12 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.19.8", + "license": "MIT" }, "node_modules/unified": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", - "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "version": "11.0.5", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -12149,8 +10350,7 @@ }, "node_modules/unified/node_modules/is-plain-obj": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -12160,8 +10360,7 @@ }, "node_modules/unist-util-is": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -12172,8 +10371,7 @@ }, "node_modules/unist-util-position": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -12184,8 +10382,7 @@ }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -12196,8 +10393,7 @@ }, "node_modules/unist-util-visit": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", @@ -12210,8 +10406,7 @@ }, "node_modules/unist-util-visit-parents": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" @@ -12221,17 +10416,8 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/universal-user-agent": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", - "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", - "dev": true, - "license": "ISC" - }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.3", "dev": true, "funding": [ { @@ -12247,9 +10433,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -12260,23 +10447,19 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -12286,12 +10469,10 @@ } }, "node_modules/vfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", - "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "version": "6.0.3", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" }, "funding": { @@ -12301,8 +10482,6 @@ }, "node_modules/vfile-location": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", - "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -12315,8 +10494,7 @@ }, "node_modules/vfile-message": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" @@ -12327,20 +10505,19 @@ } }, "node_modules/vite": { - "version": "5.4.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", - "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "version": "6.2.1", "dev": true, + "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -12349,19 +10526,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -12382,30 +10565,32 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, "node_modules/vite-plugin-circular-dependency": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vite-plugin-circular-dependency/-/vite-plugin-circular-dependency-0.2.1.tgz", - "integrity": "sha512-NriKEoxJKn5CaAMw5JT1DYMm4KntsCfqcVeGF7ssOXRQVqoxmtUl6hS8AH+sellIKZf51G53v/CyDNt5LXj1NA==", "dev": true, + "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.2", "chalk": "^4.1.2" } }, "node_modules/vite-plugin-mkcert": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/vite-plugin-mkcert/-/vite-plugin-mkcert-1.17.5.tgz", - "integrity": "sha512-KKGY3iHx/9zb7ow8JJ+nLN2HiNIBuPBwj34fJ+jAJT89/8qfk7msO7G7qipR8VDEm9xMCys0xT11QOJbZcg3/Q==", + "version": "1.17.7", "dev": true, "license": "MIT", "dependencies": { - "@octokit/rest": "^20.0.2", - "axios": "^1.6.8", - "debug": "^4.3.4", - "picocolors": "^1.0.0" + "axios": "^1.8.1", + "debug": "^4.4.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=v16.7.0" @@ -12415,12 +10600,15 @@ } }, "node_modules/vitefu": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", - "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "version": "1.0.6", "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*" + ], "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "peerDependenciesMeta": { "vite": { @@ -12431,8 +10619,7 @@ "node_modules/vscode": { "name": "@codingame/monaco-vscode-api", "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-api/-/monaco-vscode-api-11.1.2.tgz", - "integrity": "sha512-8UHz2uH103P+8eXDRAWo1e1PRfMN5F5dR4s/Mb9fX18Qzr8+/GkpWJHhT1t1cd5xY8XwIiH7YyMz6pL0aDOikw==", + "license": "MIT", "dependencies": { "@codingame/monaco-vscode-base-service-override": "11.1.2", "@codingame/monaco-vscode-environment-service-override": "11.1.2", @@ -12448,16 +10635,14 @@ }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/vscode-languageclient": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", - "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", + "license": "MIT", "dependencies": { "minimatch": "^5.1.0", "semver": "^7.3.7", @@ -12469,8 +10654,7 @@ }, "node_modules/vscode-languageclient/node_modules/minimatch": { "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -12480,8 +10664,7 @@ }, "node_modules/vscode-languageserver-protocol": { "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" @@ -12489,30 +10672,23 @@ }, "node_modules/vscode-languageserver-types": { "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" + "license": "MIT" }, "node_modules/vscode-oniguruma": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", "license": "MIT" }, "node_modules/vscode-textmate": { "version": "9.1.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-9.1.0.tgz", - "integrity": "sha512-lxKSVp2DkFOx9RDAvpiYUrB9/KT1fAfi1aE8CBGstP8N7rLF+Seifj8kDA198X0mYj1CjQUC+81+nQf8CO0nVA==", "license": "MIT" }, "node_modules/vscode-uri": { "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", - "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==" + "license": "MIT" }, "node_modules/vscode-ws-jsonrpc": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/vscode-ws-jsonrpc/-/vscode-ws-jsonrpc-3.4.0.tgz", - "integrity": "sha512-jkNZvX0LdHt4skPxMw/jFePr3jRCJU6ZmO28oPoQ7RwNSkwU3uN8mgtxACYEbOY68bYmi/b/uJzhxewKCz1P4w==", + "license": "MIT", "dependencies": { "vscode-jsonrpc": "~8.2.1" }, @@ -12523,36 +10699,37 @@ }, "node_modules/vscode-ws-jsonrpc/node_modules/vscode-jsonrpc": { "version": "8.2.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", - "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/web-namespaces": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/web-worker": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", - "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==" + "version": "1.5.0", + "license": "Apache-2.0" }, "node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "license": "BSD-2-Clause" }, "node_modules/whatwg-url": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -12560,15 +10737,12 @@ }, "node_modules/wheel": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wheel/-/wheel-1.0.0.tgz", - "integrity": "sha512-XiCMHibOiqalCQ+BaNSwRoZ9FDTAvOsXxGHXChBugewDj7HC8VBIER71dEOiRH1fSdLbRCQzngKTSiZ06ZQzeA==", "license": "MIT" }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -12580,71 +10754,150 @@ } }, "node_modules/windmill-parser-wasm-csharp": { - "version": "1.437.1", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-csharp/-/windmill-parser-wasm-csharp-1.437.1.tgz", - "integrity": "sha512-qzB/kUE9JCf1CYFDz+50AI+SUVaZYn3lSgqmJ11Iuibl41AC4EIvfH4zrsOU53lcTOb9b4ZH3D6z9FjCCfqWsw==" + "version": "1.437.1" }, "node_modules/windmill-parser-wasm-go": { - "version": "1.429.0", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-go/-/windmill-parser-wasm-go-1.429.0.tgz", - "integrity": "sha512-M3jeGDqeTyPj9HyyX3msdzMrqIIzlfMfxTMsXS8m7MJp4Cm60qifMxD29Ipxb2B4WdzyGwCSlaBjLsXu0b3c5g==" + "version": "1.429.0" + }, + "node_modules/windmill-parser-wasm-java": { + "version": "1.478.1" }, "node_modules/windmill-parser-wasm-nu": { - "version": "1.474.1", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-nu/-/windmill-parser-wasm-nu-1.474.1.tgz", - "integrity": "sha512-ikRhz9CWpWilt/7K8mmRniF2cdWnH6EgjuL189z76pcEQbuMwDO4eXocAdMDaufehOsTWpXmDtsYeFfmayPIpQ==" + "version": "1.474.1" }, "node_modules/windmill-parser-wasm-php": { - "version": "1.429.0", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-php/-/windmill-parser-wasm-php-1.429.0.tgz", - "integrity": "sha512-SGJAtNpfdRZftkGboxWsm/yQDnJBJodwPQUbX2cWk/aoNook6ULesZwsYtBC9WN1VH6TIskLiVPohMmu6jtXmw==" + "version": "1.429.0" }, "node_modules/windmill-parser-wasm-py": { - "version": "1.477.1", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-py/-/windmill-parser-wasm-py-1.477.1.tgz", - "integrity": "sha512-EY3mSMWpqFPzd7fsLg2/hSfQFU8HpW9nplFwm4JHHCDbcTpBzlvzjPJoHAAGO5kMzowAxjqi5ai/mXjeUWuiSg==" + "version": "1.477.1" }, "node_modules/windmill-parser-wasm-regex": { - "version": "1.478.2", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-regex/-/windmill-parser-wasm-regex-1.478.2.tgz", - "integrity": "sha512-XXYOzCePuHBEdiTREF+UlRGDyUu5VVXD9RBb5JGiq9YkjKhKek0CkjSt8HhJ0yAu0i/gvWLOO0RboT2C04Qt1A==" + "version": "1.481.0", + "resolved": "https://registry.npmjs.org/windmill-parser-wasm-regex/-/windmill-parser-wasm-regex-1.481.0.tgz", + "integrity": "sha512-QY9NOaF0M55SBEbbcAkHoXppjdS2gb2NlwqhlZ1ciYWTtIrbZoL5K8xoG4FbB5vWRHxInG1aRdA2tb+JP180yA==" }, "node_modules/windmill-parser-wasm-rust": { - "version": "1.429.0", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-rust/-/windmill-parser-wasm-rust-1.429.0.tgz", - "integrity": "sha512-c8mjpiw8RxoaBDtecb+sKeWM/IOjNr4Y06nHudGu8sMM48MNO1LhgcISLv8wl6Z9zWd7OzQrECJ6RLorpii5Uw==" + "version": "1.429.0" }, "node_modules/windmill-parser-wasm-ts": { - "version": "1.429.0", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-ts/-/windmill-parser-wasm-ts-1.429.0.tgz", - "integrity": "sha512-mUC2dpHxEqNf0vVdOWR+dLJMDCjfaYvP00ywu8PjVUdLAGr4ic366jC9DiYTymLZFEUV5316snna8DAReWGRUA==" + "version": "1.438.2" }, "node_modules/windmill-parser-wasm-yaml": { - "version": "1.429.0", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-yaml/-/windmill-parser-wasm-yaml-1.429.0.tgz", - "integrity": "sha512-elQYkaWOvzB8LiwVV9NbNqrupSmdtRY3mMEl+qmKTJhGLvYrVOxA8zyBtwGK0MGiFhTOO3ZO96LWSlDfBnpN9g==" + "version": "1.429.0" }, "node_modules/windmill-sql-datatype-parser-wasm": { - "version": "1.318.0", - "resolved": "https://registry.npmjs.org/windmill-sql-datatype-parser-wasm/-/windmill-sql-datatype-parser-wasm-1.318.0.tgz", - "integrity": "sha512-jlRw6abUJi4vDm+7xDSjhb7dvm4tC+lBXv0EEwn52Veadwcl5EB1yGHb9XVqQEfcYr9JU62xfJlN6DoGQmYE/g==" + "version": "1.318.0" + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/wordwrap": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "devOptional": true + "dev": true, + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, "license": "ISC", "peer": true, @@ -12656,38 +10909,34 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/write-file-atomic/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", + "node_modules/ws": { + "version": "8.18.1", + "license": "MIT", + "optional": true, "peer": true, "engines": { - "node": ">=14" + "node": ">=10.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/ws": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", - "optional": true, - "dependencies": { - "async-limiter": "~1.0.0" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/xml-utils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.7.0.tgz", - "integrity": "sha512-bWB489+RQQclC7A9OW8e5BzbT8Tu//jtAOvkYwewFr+Q9T9KDGvfzC1lp0pYPEQPEoPQLDkmxkepSC/2gIAZGw==" + "version": "1.10.1", + "license": "CC0-1.0" }, "node_modules/xtend": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", "optional": true, "engines": { "node": ">=0.4" @@ -12695,8 +10944,7 @@ }, "node_modules/y-leveldb": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/y-leveldb/-/y-leveldb-0.1.2.tgz", - "integrity": "sha512-6ulEn5AXfXJYi89rXPEg2mMHAyyw8+ZfeMMdOtBbV8FJpQ1NOrcgi6DTAcXof0dap84NjHPT2+9d0rb6cFsjEg==", + "license": "MIT", "optional": true, "dependencies": { "level": "^6.0.1", @@ -12711,9 +10959,8 @@ } }, "node_modules/y-monaco": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/y-monaco/-/y-monaco-0.1.5.tgz", - "integrity": "sha512-zyTCMXtewIG+jP9JikJ5NN3/jLCqpkDY3titPIGBrmVeZsJr6qVeFVP3hPfmWOPHGlGZ39KCIzXrC7mFZRNFIw==", + "version": "0.1.6", + "license": "MIT", "dependencies": { "lib0": "^0.2.43" }, @@ -12728,8 +10975,7 @@ }, "node_modules/y-protocols": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.6.tgz", - "integrity": "sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==", + "license": "MIT", "dependencies": { "lib0": "^0.2.85" }, @@ -12747,8 +10993,6 @@ }, "node_modules/y-websocket": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/y-websocket/-/y-websocket-1.5.4.tgz", - "integrity": "sha512-Y3021uy0anOIHqAPyAZbNDoR05JuMEGjRNI8c+K9MHzVS8dWoImdJUjccljAznc8H2L7WkIXhRHZ1igWNRSgPw==", "license": "MIT", "dependencies": { "lib0": "^0.2.52", @@ -12775,23 +11019,31 @@ "yjs": "^13.5.6" } }, + "node_modules/y-websocket/node_modules/ws": { + "version": "6.2.3", + "license": "MIT", + "optional": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, "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/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.7.0", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } }, "node_modules/yargs-parser": { "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "license": "ISC", "peer": true, @@ -12800,11 +11052,10 @@ } }, "node_modules/yjs": { - "version": "13.6.8", - "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.8.tgz", - "integrity": "sha512-ZPq0hpJQb6f59B++Ngg4cKexDJTvfOgeiv0sBc4sUm8CaBWH7OQC4kcCgrqbjJ/B2+6vO49exvTmYfdlPtcjbg==", + "version": "13.6.24", + "license": "MIT", "dependencies": { - "lib0": "^0.2.74" + "lib0": "^0.2.99" }, "engines": { "node": ">=16.0.0", @@ -12816,9 +11067,7 @@ } }, "node_modules/yocto-queue": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "version": "1.2.0", "license": "MIT", "engines": { "node": ">=12.20" @@ -12829,29 +11078,29 @@ }, "node_modules/yootils": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/yootils/-/yootils-0.3.1.tgz", - "integrity": "sha512-A7AMeJfGefk317I/3tBoUYRcDcNavKEkpiPN/nQsBz/viI2GvT7BtrqdPD6rGqBFN8Ax7v4obf+Cl32JF9DDVw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/zimmerframe": { + "version": "1.1.2", + "license": "MIT" }, "node_modules/zod": { - "version": "3.23.8", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zstddec": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.1.0.tgz", - "integrity": "sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg==" + "license": "MIT AND BSD-3-Clause" }, "node_modules/zwitch": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" diff --git a/frontend/package.json b/frontend/package.json index 6356634a93..5d0e13fe3f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.478.1", + "version": "1.481.0", "scripts": { "dev": "vite dev", "build": "vite build", "preview": "vite preview", - "check": "svelte-check --tsconfig ./tsconfig.json --threshold warning", - "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --threshold warning", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. .", "package": "svelte-package -o package", @@ -22,100 +22,94 @@ "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.2", "@playwright/test": "^1.34.3", - "@rgossiaux/svelte-headlessui": "^2.0.0", "@sveltejs/adapter-static": "^3.0.6", - "@sveltejs/kit": "^2.9.0", - "@sveltejs/package": "^2.2.2", - "@sveltejs/vite-plugin-svelte": "^3.1.2", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/package": "^2.3.7", + "@sveltejs/vite-plugin-svelte": "^5.0.0", "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.8", "@types/d3": "^7.4.0", "@types/d3-zoom": "^3.0.3", + "@types/diff": "^7.0.1", "@types/lodash": "^4.14.195", "@types/node": "^20.3.3", "@types/vscode": "^1.83.5", "@typescript-eslint/eslint-plugin": "^5.59.8", "@typescript-eslint/parser": "^5.60.0", "@windmill-labs/esbuild-import-meta-url-plugin": "0.0.0-semantic-release", - "@zerodevx/svelte-toast": "^0.9.5", + "@zerodevx/svelte-toast": "^0.9.6", "autoprefixer": "^10.4.13", "cssnano": "^6.0.1", "d3-dag": "^0.11.5", "eslint": "^8.47.0", "eslint-config-prettier": "^8.6.0", - "eslint-plugin-svelte": "^2.33.1", + "eslint-plugin-svelte": "^2.45.1", "path-browserify": "^1.0.1", "postcss": "^8.4.49", "postcss-load-config": "^4.0.1", - "prettier": "^2.8.8", - "prettier-plugin-svelte": "^2.10.1", + "prettier": "^3.1.0", + "prettier-plugin-svelte": "^3.3.3", "simple-svelte-autocomplete": "^2.5.1", "style-to-object": "^0.4.1", "stylelint-config-recommended": "^13.0.0", - "svelte": "^4.2.19", + "svelte": "^5.0.0", "svelte-awesome-color-picker": "^3.0.4", - "svelte-check": "^3.4.3", + "svelte-check": "^4.0.0", "svelte-floating-ui": "^1.5.8", "svelte-highlight": "^7.6.0", - "svelte-multiselect": "^10.0.0", + "svelte-multiselect": "^11.0.0-rc.1", "svelte-popperjs": "^1.3.2", - "svelte-preprocess": "^5.0.1", + "svelte-preprocess": "^6.0.0", "svelte-range-slider-pips": "^2.3.1", - "svelte-splitpanes": "^0.8.0", + "svelte-splitpanes": "^8.0.9", "svelte2tsx": "^0.6.16", "tailwindcss": "^3.4.1", "tslib": "^2.6.1", - "typescript": "^5.1.3", - "vite": "^5.4.11", + "typescript": "^5.5.0", + "vite": "^6.2.1", "vite-plugin-circular-dependency": "^0.2.1", "vite-plugin-mkcert": "^1.17.5", "yootils": "^0.3.1" }, "overrides": { - "@rgossiaux/svelte-headlessui": { - "svelte": "$svelte" - }, "monaco-graphql": { "monaco-editor": "$monaco-editor" - }, - "svelte-chartjs": { - "svelte": "$svelte" } }, "type": "module", "dependencies": { - "@anthropic-ai/sdk": "^0.37.0", "@aws-crypto/sha256-js": "^4.0.0", "@codingame/monaco-vscode-configuration-service-override": "~11.1.2", "@codingame/monaco-vscode-standalone-css-language-features": "~11.1.2", + "@codingame/monaco-vscode-standalone-html-language-features": "^11.1.2", "@codingame/monaco-vscode-standalone-json-language-features": "~11.1.2", "@codingame/monaco-vscode-standalone-languages": "~11.1.2", "@codingame/monaco-vscode-standalone-typescript-language-features": "~11.1.2", "@json2csv/plainjs": "^7.0.6", "@leeoniya/ufuzzy": "^1.0.8", - "@mistralai/mistralai": "^1.3.0", "@popperjs/core": "^2.11.6", "@redocly/json-to-json-schema": "^0.0.1", - "@tanstack/svelte-table": "^8.9.9", - "@windmill-labs/svelte-dnd-action": "latest", + "@tanstack/svelte-table": "npm:tanstack-table-8-svelte-5@^0.1", + "@windmill-labs/svelte-dnd-action": "^0.9.48", "@xyflow/svelte": "^0.1.15", "ag-charts-community": "^9.0.1", "ag-charts-enterprise": "^9.0.1", - "ag-grid-community": "^31.0.0", - "ag-grid-enterprise": "^31.0.0", + "ag-grid-community": "^31.3.4", + "ag-grid-enterprise": "^31.3.4", "ansi_up": "^5.2.1", "chart.js": "^4.4.6", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.0", "d3-zoom": "^3.0.0", "date-fns": "^2.30.0", - "diff": "^5.1.0", + "diff": "^7.0.0", "driver.js": "^1.3.0", "esm-env": "^1.0.0", "fast-equals": "^5.0.1", "graphql": "^16.7.1", "hash-sum": "^2.0.0", "highlight.js": "^11.8.0", + "idb": "^8.0.2", "lucide-svelte": "^0.399.0", "minimatch": "^10.0.1", "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~11.1.2", @@ -124,7 +118,7 @@ "monaco-languageclient": "9.1.1", "monaco-vim": "^0.4.1", "ol": "^7.4.0", - "openai": "^4.57.2", + "openai": "^4.87.1", "p-limit": "^6.1.0", "panzoom": "^9.4.3", "pdfjs-dist": "4.8.69", @@ -133,8 +127,7 @@ "rehype-raw": "^7.0.0", "rfc4648": "^1.5.3", "svelte-carousel": "^1.0.25", - "svelte-chartjs": "^3.1.5", - "svelte-exmarkdown": "^3.0.5", + "svelte-exmarkdown": "^5.0.0", "svelte-infinite-loading": "^1.4.0", "svelte-tiny-virtual-list": "^2.0.5", "tailwind-merge": "^1.13.2", @@ -144,10 +137,11 @@ "vscode-ws-jsonrpc": "~3.4.0", "windmill-parser-wasm-csharp": "^1.437.1", "windmill-parser-wasm-go": "^1.429.0", + "windmill-parser-wasm-java": "^1.478.1", "windmill-parser-wasm-nu": "^1.474.1", "windmill-parser-wasm-php": "^1.429.0", "windmill-parser-wasm-py": "^1.477.1", - "windmill-parser-wasm-regex": "^1.478.2", + "windmill-parser-wasm-regex": "^1.481.0", "windmill-parser-wasm-rust": "^1.429.0", "windmill-parser-wasm-ts": "^1.429.0", "windmill-parser-wasm-yaml": "^1.429.0", @@ -155,7 +149,8 @@ "y-monaco": "^0.1.4", "y-websocket": "^1.5.4", "yaml": "^2.3.4", - "yjs": "^13.6.7" + "yjs": "^13.6.7", + "zod": "^3.24.2" }, "peerDependencies": { "svelte": "^4.0.0" @@ -513,6 +508,7 @@ } }, "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "^4.35.0", "fsevents": "^2.3.3" } } diff --git a/frontend/src/lib/components/ApiConnectForm.svelte b/frontend/src/lib/components/ApiConnectForm.svelte index b2fc7410e1..877a5aef08 100644 --- a/frontend/src/lib/components/ApiConnectForm.svelte +++ b/frontend/src/lib/components/ApiConnectForm.svelte @@ -1,6 +1,11 @@ {#if !notFound} @@ -185,6 +393,291 @@
Connect Supabase
{/if} + {#if resourceType == 'git_repository' && $workspaceStore && $userStore?.is_admin} + {#if !loadingGithubInstallations} + + + +
+
+ {#if workspaceGithubInstallations.length > 0} +
+

Select Repository

+
+
+

Github Account ID

+ +
+ {#if selectedGHAppAccountId} +
+

Repository

+
+ +
+
+ {/if} +
+ +
+
+
+ {/if} + +
0 + ? 'border-t border-gray-200 dark:border-gray-700' + : '' + } pt-4`} + > +
+
+ +
+ {#if workspaceGithubInstallations.length > 0} +
+

Current installations:

+
+ + + + + + + + + + + {#each workspaceGithubInstallations as installation} + + + + + + + {/each} + +
OrgWorkspaceRepos
{installation.account_id} + {#if $userWorkspaces.find((w) => w.id === installation.workspace_id)?.color} + + {installation.workspace_id} + + {:else} + {installation.workspace_id} + {/if} + + {installation.repositories.length} repos + +
+ + +
+
+
+
+ {/if} + {#if githubInstallationsNotInWorkspace.length > 0} +
+

Installations in other workspaces:

+
+ + + + + + + + + + + {#each githubInstallationsNotInWorkspace as installation} + + + + + + + {/each} + +
OrgWorkspaceRepos
{installation.account_id} + {#if $userWorkspaces.find((w) => w.id === installation.workspace_id)?.color} + + {installation.workspace_id} + + {:else} + {installation.workspace_id} + {/if} + + {installation.repositories.length} repos + + +
+
+
+ {/if} +
+
+ +
+

Import installation from other instance:

+
+ + +
+
+
+
+
+ + {:else} + + {/if} + {/if} {:else}

{error}{:else}

{/if} + >{:else}
{/if}
{#await import('$lib/components/SimpleEditor.svelte')} @@ -213,7 +706,7 @@
File content ({resourceTypeInfo.format_extension})
-
+
{#await import('$lib/components/SimpleEditor.svelte')} diff --git a/frontend/src/lib/components/AppConnectInner.svelte b/frontend/src/lib/components/AppConnectInner.svelte index 02136a91dc..6f73fff916 100644 --- a/frontend/src/lib/components/AppConnectInner.svelte +++ b/frontend/src/lib/components/AppConnectInner.svelte @@ -480,7 +480,7 @@ {/if}
-
+
{#if filteredConnectsManual} {#each filteredConnectsManual as [key, _]} @@ -552,18 +552,19 @@ {#if renderDescription}
GH Markdown
-
{:else if description == undefined || description == ''}
No description provided
{:else} -
+
{/if}
{#key resourceTypeInfo}
{#if step > 2} - + {/if} - {:else} {/if} +
{:else if inputCat == 'object' || inputCat == 'resource-object' || isListJson} {#if oneOf && oneOf.length >= 2} @@ -872,7 +884,7 @@
{/key} {:else if disabled} - {:else} {#await import('$lib/components/JsonEditor.svelte')} @@ -894,7 +906,7 @@ {/if} {/if} {:else if disabled} - {:else} {#await import('$lib/components/JsonEditor.svelte')} @@ -981,7 +993,7 @@ {/if}
{:else if disabled} - {:else} {#await import('$lib/components/JsonEditor.svelte')} @@ -1042,7 +1054,7 @@ {/if} {:else if isRawStringEditor(inputCat)} {#if disabled} - {:else}
{#await import('$lib/components/SimpleEditor.svelte')} @@ -1146,7 +1158,7 @@ )} placeholder={placeholder ?? defaultValue ?? ''} bind:value - /> + > {/key} {#if !disabled && itemPicker && extra?.['disableVariablePicker'] != true} @@ -1188,7 +1200,7 @@ {/if}
{:else if !noMargin} -
+
{/if}
diff --git a/frontend/src/lib/components/ArrayTypeNarrowing.svelte b/frontend/src/lib/components/ArrayTypeNarrowing.svelte index 8e2fe827c3..2d37233086 100644 --- a/frontend/src/lib/components/ArrayTypeNarrowing.svelte +++ b/frontend/src/lib/components/ArrayTypeNarrowing.svelte @@ -25,8 +25,8 @@ itemsType?.type != 'string' ? itemsType?.type : Array.isArray(itemsType?.enum) - ? 'enum' - : 'string' + ? 'enum' + : 'string' let schema = { properties: itemsType?.properties || {}, @@ -105,16 +105,17 @@