diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000..1d953f4bd7 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.github/DockerfileBackendTests b/.github/DockerfileBackendTests index b56e64d085..e20d023bdc 100644 --- a/.github/DockerfileBackendTests +++ b/.github/DockerfileBackendTests @@ -1,22 +1,6 @@ -ARG DEBIAN_IMAGE=debian:bookworm-slim -ARG RUST_IMAGE=rust:1.79-slim-bookworm +ARG RUST_IMAGE=rust:1.80-slim-bookworm ARG PYTHON_IMAGE=python:3.11.4-slim-bookworm -FROM ${DEBIAN_IMAGE} as downloader - -ARG TARGETPLATFORM - -SHELL ["/bin/bash", "-c"] - -RUN apt update -y -RUN apt install -y unzip curl - -RUN [ "$TARGETPLATFORM" == "linux/amd64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.41.0/deno-x86_64-unknown-linux-gnu.zip -o deno.zip || true -RUN [ "$TARGETPLATFORM" == "linux/arm64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.41.0/deno-aarch64-unknown-linux-gnu.zip -o deno.zip || true - - -RUN unzip deno.zip && rm deno.zip - FROM ${RUST_IMAGE} as builder @@ -31,7 +15,7 @@ ENV SQLX_OFFLINE=true RUN mkdir -p /frontend/build RUN apt-get update \ - && apt-get install -y ca-certificates tzdata libpq5 cmake\ + && apt-get install -y ca-certificates tzdata libpq5 cmake unzip\ make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev \ libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libxml2-dev \ libxmlsec1-dev libffi-dev liblzma-dev mecab-ipadic-utf8 libgdbm-dev libc6-dev git libprotobuf-dev libnl-route-3-dev \ @@ -43,6 +27,9 @@ RUN wget https://golang.org/dl/go1.21.5.linux-amd64.tar.gz && tar -C /usr/local ENV PATH="${PATH}:/usr/local/go/bin" ENV GO_PATH=/usr/local/go/bin/go +# Install UV +RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.4.18/uv-installer.sh | sh && mv /usr/local/cargo/bin/uv /usr/local/bin/uv + ENV TZ=Etc/UTC ENV PYTHON_VERSION 3.11.4 @@ -53,13 +40,14 @@ RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VER RUN /usr/local/bin/python3 -m pip install pip-tools -COPY --from=oven/bun:1.1.8 /usr/local/bin/bun /usr/bin/bun +COPY --from=oven/bun:1.1.31 /usr/local/bin/bun /usr/bin/bun +ARG TARGETPLATFORM -RUN [ "$TARGETPLATFORM" == "linux/amd64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.41.0/deno-x86_64-unknown-linux-gnu.zip -o deno.zip || true -RUN [ "$TARGETPLATFORM" == "linux/arm64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.41.0/deno-aarch64-unknown-linux-gnu.zip -o deno.zip || true +RUN curl -Lsf https://github.com/denoland/deno/releases/download/v2.0.2/deno-x86_64-unknown-linux-gnu.zip -o deno.zip +# RUN [ "$TARGETPLATFORM" == "linux/arm64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v2.0.0/deno-aarch64-unknown-linux-gnu.zip -o deno.zip || true -COPY --from=downloader --chmod=755 /deno /usr/bin/deno +RUN unzip deno.zip && rm deno.zip && mv deno /usr/bin/deno RUN apt-get update \ && apt-get install -y postgresql-client --allow-unauthenticated diff --git a/.github/change-versions.sh b/.github/change-versions.sh index 8974c283ab..77ecbc6985 100755 --- a/.github/change-versions.sh +++ b/.github/change-versions.sh @@ -7,7 +7,7 @@ VERSION=$1 echo "Updating versions to: $VERSION" sed -i -e "/^version =/s/= .*/= \"$VERSION\"/" ${root_dirpath}/backend/Cargo.toml -sed -i -e "/^export const VERSION =/s/= .*/= \"v$VERSION\";/" ${root_dirpath}/cli/main.ts +sed -i -e "/^export const VERSION =/s/= .*/= \"$VERSION\";/" ${root_dirpath}/cli/main.ts sed -i -e "/^export const VERSION =/s/= .*/= \"v$VERSION\";/" ${root_dirpath}/benchmarks/lib.ts sed -i -e "/version: /s/: .*/: $VERSION/" ${root_dirpath}/backend/windmill-api/openapi.yaml sed -i -e "/version: /s/: .*/: $VERSION/" ${root_dirpath}/openflow.openapi.yaml diff --git a/.github/workflows/backend-test.yml b/.github/workflows/backend-test.yml index 4a3a9f69e7..cbcf40ebe6 100644 --- a/.github/workflows/backend-test.yml +++ b/.github/workflows/backend-test.yml @@ -29,10 +29,10 @@ jobs: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 with: - toolchain: 1.79.0 + toolchain: 1.80.0 # - uses: Swatinem/rust-cache@v2 # with: # workspaces: | @@ -41,8 +41,12 @@ jobs: - name: cargo test timeout-minutes: 15 run: + /usr/bin/deno --version && + /usr/bin/bun -v && + go version && + /usr/local/bin/python3 --version && mkdir frontend/build && cd backend && touch windmill-api/openapi-deref.yaml && DATABASE_URL=postgres://postgres:changeme@postgres:5432/windmill - DISABLE_EMBEDDING=true RUST_LOG=info cargo test --features enterprise - --all -- --nocapture + DISABLE_EMBEDDING=true RUST_LOG=info cargo test --features + enterprise,deno_core --all -- --nocapture diff --git a/.github/workflows/build-caddy-l4-image.yml b/.github/workflows/build-caddy-l4-image.yml index c6d9c13f8e..cafa9f8e47 100644 --- a/.github/workflows/build-caddy-l4-image.yml +++ b/.github/workflows/build-caddy-l4-image.yml @@ -16,7 +16,7 @@ jobs: - uses: depot/setup-action@v1 - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -26,7 +26,7 @@ jobs: type=raw,value=latest,enable={{is_default_branch}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/.github/workflows/build-publish-rh-image.yml b/.github/workflows/build-publish-rh-image.yml new file mode 100644 index 0000000000..b957ac5148 --- /dev/null +++ b/.github/workflows/build-publish-rh-image.yml @@ -0,0 +1,128 @@ +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +name: Build and publish windmill for RHEL9 +on: + workflow_dispatch + +permissions: write-all + +jobs: + build_ee: + runs-on: ubicloud + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Read EE repo commit hash + run: | + echo "ee_repo_ref=$(cat ./backend/ee-repo-ref.txt)" >> "$GITHUB_ENV" + + - uses: actions/checkout@v4 + with: + repository: windmill-labs/windmill-ee-private + path: ./windmill-ee-private + ref: ${{ env.ee_repo_ref }} + token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }} + fetch-depth: 0 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v2 + - uses: depot/setup-action@v1 + + - name: Docker meta + id: meta-ee-public + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-rhel9 + flavor: | + latest=false + tags: | + type=sha + + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Substitute EE code + run: | + ./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private + + - name: Copy RHEL9 Dockerfile + run: | + cp ./docker/RHEL9/Dockerfile ./Dockerfile + + - name: Build and push publicly ee amd64 + uses: depot/build-push-action@v1 + with: + context: . + platforms: linux/amd64 + push: true + build-args: | + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core + secrets: | + rh_username=${{ secrets.RH_USERNAME }} + rh_password=${{ secrets.RH_PASSWORD }} + tags: | + ${{ steps.meta-ee-public.outputs.tags }}-amd64 + labels: | + ${{ steps.meta-ee-public.outputs.labels }}-amd64 + org.opencontainers.image.licenses=Windmill-Enterprise-License + + - name: Build and push publicly ee arm64 + uses: depot/build-push-action@v1 + with: + context: . + platforms: linux/arm64 + push: true + build-args: | + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core + secrets: | + rh_username=${{ secrets.RH_USERNAME }} + rh_password=${{ secrets.RH_PASSWORD }} + tags: | + ${{ steps.meta-ee-public.outputs.tags }}-arm64 + labels: | + ${{ steps.meta-ee-public.outputs.labels }}-arm64 + org.opencontainers.image.licenses=Windmill-Enterprise-License + + - uses: shrink/actions-docker-extract@v3 + id: extract-ee-amd64 + with: + image: ${{ steps.meta-ee-public.outputs.tags}}-amd64 + path: "/windmill/target/release/windmill" + + - uses: shrink/actions-docker-extract@v3 + id: extract-ee-arm64 + with: + image: ${{ steps.meta-ee-public.outputs.tags}}-arm64 + path: "/windmill/target/release/windmill" + + - name: Rename binary with corresponding architecture + run: | + mv "${{ steps.extract-ee-amd64.outputs.destination }}/windmill" "${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9" + mv "${{ steps.extract-ee-arm64.outputs.destination }}/windmill" "${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel9" + + - uses: actions/upload-artifact@v4 + with: + name: RHEL9-amd64 build + path: ${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9 + + - uses: actions/upload-artifact@v4 + with: + name: RHEL9-arm64 build + path: ${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel9 + + # - name: Attach binary to release + # uses: softprops/action-gh-release@v2 + # if: startsWith(github.ref, 'refs/tags/') + # with: + # files: | + # ${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel9 + # ${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9 diff --git a/.github/workflows/build-staging-image.yml b/.github/workflows/build-staging-image.yml index 2940114f19..724fde4e59 100644 --- a/.github/workflows/build-staging-image.yml +++ b/.github/workflows/build-staging-image.yml @@ -34,7 +34,7 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-staging-ee @@ -45,7 +45,7 @@ jobs: type=ref,event=branch - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -62,7 +62,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core tags: | ${{ steps.meta-ee-public.outputs.tags }} labels: | diff --git a/.github/workflows/build_cli_image.yml b/.github/workflows/build_cli_image.yml index 7f66d68f9e..5b71a786aa 100644 --- a/.github/workflows/build_cli_image.yml +++ b/.github/workflows/build_cli_image.yml @@ -18,13 +18,13 @@ jobs: publish_cli: runs-on: ubicloud steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: depot/setup-action@v1 - name: Docker meta id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -35,7 +35,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/.github/workflows/build_windows_worker.yml b/.github/workflows/build_windows_worker.yml new file mode 100644 index 0000000000..01c38dd2b1 --- /dev/null +++ b/.github/workflows/build_windows_worker.yml @@ -0,0 +1,60 @@ +name: Build and Publish Windows Worker + +on: + push: + tags: + - "v*" + +env: + CARGO_INCREMENTAL: 0 + SQLX_OFFLINE: true + DISABLE_EMBEDDING: true + RUST_LOG: info + +jobs: + cargo_build_windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - name: Read EE repo commit hash + shell: pwsh + run: | + $ee_repo_ref = Get-Content .\backend\ee-repo-ref.txt + echo "ee_repo_ref=$ee_repo_ref" | Out-File -FilePath $env:GITHUB_ENV -Append + + - name: Checkout windmill-ee-private repository + uses: actions/checkout@v4 + with: + repository: windmill-labs/windmill-ee-private + path: ./windmill-ee-private + ref: ${{ env.ee_repo_ref }} + token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }} + fetch-depth: 0 + + - name: Substitute EE code + shell: bash + run: | + ./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private + + - name: Cargo build windows + timeout-minutes: 90 + run: | + vcpkg.exe install openssl-windows:x64-windows + vcpkg.exe install openssl:x64-windows-static + vcpkg.exe integrate install + $env:VCPKGRS_DYNAMIC=1 + $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 + + - name: Rename binary with corresponding architecture + run: | + Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe" + + - name: Attach binary to release + uses: softprops/action-gh-release@v2 + with: + files: | + ./backend/target/release/windmill-ee.exe diff --git a/.github/workflows/build_ws.yml b/.github/workflows/build_ws.yml index a01f8f6cb6..cccab8bea0 100644 --- a/.github/workflows/build_ws.yml +++ b/.github/workflows/build_ws.yml @@ -16,13 +16,13 @@ jobs: publish_multiplayer: runs-on: ubicloud-standard-8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: depot/setup-action@v1 - name: Docker meta id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -33,7 +33,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/.github/workflows/change-versions.yml b/.github/workflows/change-versions.yml index 65a66a6fa4..846eaa9658 100644 --- a/.github/workflows/change-versions.yml +++ b/.github/workflows/change-versions.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubicloud container: node:18 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: git config --system --add safe.directory /__w/windmill/windmill - name: Change versions run: ./.github/change-versions.sh "$(cat version.txt)" diff --git a/.github/workflows/deno_on_release.yml b/.github/workflows/deno_on_release.yml index 68c8b69aa6..61f3c3d7e6 100644 --- a/.github/workflows/deno_on_release.yml +++ b/.github/workflows/deno_on_release.yml @@ -10,7 +10,7 @@ jobs: build_deno_and_push_to_repo: runs-on: ubicloud steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: generate_deno run: | cd deno-client @@ -33,7 +33,7 @@ jobs: needs: [build_deno_and_push_to_repo] runs-on: ubicloud steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: ${{ github.repository_owner }}/${{ env.repo }} token: ${{ secrets.DENO_PAT }} diff --git a/.github/workflows/docker-image-rpi4.yml b/.github/workflows/docker-image-rpi4.yml index dd64cafe71..71a796f679 100644 --- a/.github/workflows/docker-image-rpi4.yml +++ b/.github/workflows/docker-image-rpi4.yml @@ -37,7 +37,7 @@ jobs: - uses: depot/setup-action@v1 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -49,7 +49,7 @@ jobs: - name: Docker meta id: meta-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -67,7 +67,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=embedding,parquet,openidconnect + features=embedding,parquet,openidconnect,deno_core 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 cd1bb62cf7..f1f3cae9f8 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -1,7 +1,11 @@ env: REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.event_name != 'pull_request' && github.repository || 'windmill-labs/windmill-test' }} - DEV_SHA: ${{ github.event_name != 'pull_request' && 'dev' || format('pr-{0}', github.event.number) }} + IMAGE_NAME: + ${{ github.event_name != 'pull_request' && github.repository || + 'windmill-labs/windmill-test' }} + DEV_SHA: + ${{ github.event_name != 'pull_request' && 'dev' || format('pr-{0}', + github.event.number) }} name: Build windmill:main on: @@ -22,6 +26,7 @@ permissions: write-all jobs: build: runs-on: ubicloud + if: (github.event_name != 'issue_comment') || (contains(github.event.comment.body, '/buildimage_all') || contains(github.event.comment.body, '/buildimage_base')) steps: - uses: actions/checkout@v4 with: @@ -44,7 +49,7 @@ jobs: - uses: depot/setup-action@v1 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -56,7 +61,7 @@ jobs: - name: Docker meta id: meta-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -73,7 +78,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=embedding,parquet,openidconnect,jemalloc + features=embedding,parquet,openidconnect,jemalloc,deno_core tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }} ${{ steps.meta-public.outputs.tags }} @@ -83,6 +88,7 @@ jobs: build_ee: runs-on: ubicloud + if: (github.event_name != 'issue_comment') || (contains(github.event.comment.body, '/buildimage_ee') || contains(github.event.comment.body, '/buildimage_nsjail')) || contains(github.event.comment.body, '/buildimage_all') steps: - uses: actions/checkout@v4 with: @@ -106,7 +112,7 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee @@ -117,7 +123,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -134,7 +140,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }} ${{ steps.meta-ee-public.outputs.tags }} @@ -144,7 +150,7 @@ jobs: build_ee_312: runs-on: ubicloud - if: ${{ startsWith(github.ref, 'refs/tags/') }} + if: ${{ startsWith(github.ref, 'refs/tags/v') }} steps: - uses: actions/checkout@v4 with: @@ -168,7 +174,7 @@ jobs: - name: Docker meta id: meta-ee-public-py312 - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-py312 @@ -179,7 +185,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -196,7 +202,7 @@ jobs: platforms: linux/amd64 push: true build-args: | - features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core PYTHON_IMAGE=python:3.12.2-slim-bookworm tags: | ${{ steps.meta-ee-public-py312.outputs.tags }} @@ -240,7 +246,7 @@ jobs: attach_amd64_binary_to_release: needs: [build, build_ee] runs-on: ubicloud - if: ${{ startsWith(github.ref, 'refs/tags/') }} + if: ${{ startsWith(github.ref, 'refs/tags/v') }} env: ARCH: amd64 steps: @@ -275,7 +281,7 @@ jobs: mv "${{ steps.extract-ee.outputs.destination }}/windmill" "${{ steps.extract-ee.outputs.destination }}/windmill-ee-${ARCH}" - name: Attach binary to release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: files: | ${{ steps.extract.outputs.destination }}/* @@ -319,7 +325,7 @@ jobs: # mv "${{ steps.extract-ee.outputs.destination }}/windmill" "${{ steps.extract-ee.outputs.destination }}/windmill-ee-${ARCH}" # - name: Attach binary to release - # uses: softprops/action-gh-release@v1 + # uses: softprops/action-gh-release@v2 # with: # files: | # ${{ steps.extract.outputs.destination }}/* @@ -333,10 +339,10 @@ jobs: with: fetch-depth: 0 - name: Prepare test run - if: ${{ ! startsWith(github.ref, 'refs/tags/') }} + if: ${{ ! startsWith(github.ref, 'refs/tags/v') }} run: cd integration_tests && ./build.sh - name: Test run - if: ${{ ! startsWith(github.ref, 'refs/tags/') }} + if: ${{ ! startsWith(github.ref, 'refs/tags/v') }} timeout-minutes: 15 env: LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }} @@ -352,13 +358,13 @@ jobs: tag_latest: runs-on: ubicloud needs: [run_integration_test, build] - if: github.event_name != 'pull_request' + if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -371,13 +377,13 @@ jobs: tag_latest_ee: runs-on: ubicloud needs: [run_integration_test, build_ee] - if: github.event_name != 'pull_request' + if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -390,7 +396,7 @@ jobs: verify_ee_image_vulnerabilities: runs-on: ubicloud needs: [tag_latest_ee] - # if: ${{ startsWith(github.ref, 'refs/tags/') }} + if: ${{ startsWith(github.ref, 'refs/tags/v') }} steps: - name: Checkout code uses: actions/checkout@v4 @@ -432,7 +438,7 @@ jobs: build_ee_nsjail: needs: [build_ee] runs-on: ubicloud - if: github.event_name != 'pull_request' + if: (github.event_name != 'issue_comment') || (github.event_name != 'pull_request') || (contains(github.event.comment.body, '/buildimage_nsjail') || contains(github.event.comment.body, '/buildimage_all')) steps: - uses: actions/checkout@v4 with: @@ -445,7 +451,7 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-nsjail @@ -455,9 +461,11 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=sha,enable=true,priority=100,prefix=,suffix=,format=short + type=ref,event=branch + type=ref,event=pr - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -490,15 +498,15 @@ jobs: - uses: depot/setup-action@v1 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - + - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-reports @@ -536,12 +544,12 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - + - name: get git hash if: github.event_name != 'pull_request' id: git_hash @@ -557,7 +565,7 @@ jobs: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-nsjail:${{ steps.git_hash.outputs.GIT_HASH }} path: "/static_frontend/." - - uses: reggionick/s3-deploy@v3 + - uses: reggionick/s3-deploy@v4 if: github.event_name != 'pull_request' with: folder: ${{ steps.extract.outputs.destination }} @@ -565,7 +573,7 @@ jobs: bucket-region: us-east-1 build_ee_cuda: - if: ${{ startsWith(github.ref, 'refs/tags/') }} + if: ${{ startsWith(github.ref, 'refs/tags/v') }} needs: [build_ee] runs-on: ubicloud steps: @@ -580,18 +588,16 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-cuda - flavor: | - latest=false tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -610,9 +616,9 @@ jobs: ${{ steps.meta-ee-public.outputs.labels }} org.opencontainers.image.licenses=Windmill-Enterprise-License - build_ee_slim: - if: ${{ startsWith(github.ref, 'refs/tags/') }} - needs: [build_ee] + build_slim: + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + needs: [build] runs-on: ubicloud steps: - uses: actions/checkout@v4 @@ -626,18 +632,16 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-slim - flavor: | - latest=false + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-slim tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -654,4 +658,134 @@ jobs: ${{ steps.meta-ee-public.outputs.tags }} labels: | ${{ steps.meta-ee-public.outputs.labels }} + + build_ee_slim: + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + needs: [build_ee] + runs-on: ubicloud + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v2 + + - uses: depot/setup-action@v1 + + - name: Docker meta + id: meta-ee-public + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-slim + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push publicly ee + uses: depot/build-push-action@v1 + with: + context: . + platforms: linux/amd64 + push: true + file: "./docker/DockerfileSlimEe" + tags: | + ${{ steps.meta-ee-public.outputs.tags }} + labels: | + ${{ steps.meta-ee-public.outputs.labels }} + org.opencontainers.image.licenses=Windmill-Enterprise-License + + build_full: + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + needs: [build] + runs-on: ubicloud + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v2 + + - uses: depot/setup-action@v1 + + - name: Docker meta + id: meta-public + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-full + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push publicly + uses: depot/build-push-action@v1 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + file: "./docker/DockerfileFull" + tags: | + ${{ steps.meta-public.outputs.tags }} + labels: | + ${{ steps.meta-public.outputs.labels }} + + build_ee_full: + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + needs: [build_ee] + runs-on: ubicloud + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v2 + + - uses: depot/setup-action@v1 + + - name: Docker meta + id: meta-ee-public + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-full + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push publicly ee + uses: depot/build-push-action@v1 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + file: "./docker/DockerfileFullEe" + tags: | + ${{ steps.meta-ee-public.outputs.tags }} + labels: | + ${{ steps.meta-ee-public.outputs.labels }} org.opencontainers.image.licenses=Windmill-Enterprise-License diff --git a/.github/workflows/frontend-check.yml b/.github/workflows/frontend-check.yml index ac8ad4272e..845d03146d 100644 --- a/.github/workflows/frontend-check.yml +++ b/.github/workflows/frontend-check.yml @@ -10,7 +10,7 @@ jobs: npm_check: runs-on: ubicloud-standard-8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: node-version: 18 diff --git a/.github/workflows/go_on_release.yml b/.github/workflows/go_on_release.yml index 44b6a030a8..4d39d70178 100644 --- a/.github/workflows/go_on_release.yml +++ b/.github/workflows/go_on_release.yml @@ -12,7 +12,7 @@ jobs: build_go_and_push_to_repo: runs-on: ubicloud-standard-8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 - name: install_jq run: | @@ -42,7 +42,7 @@ jobs: needs: [build_go_and_push_to_repo] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: ${{ github.repository_owner }}/${{ env.repo }} token: ${{ secrets.DENO_PAT }} diff --git a/.github/workflows/npm_on_release.yml b/.github/workflows/npm_on_release.yml index a8e28722cc..bf4af33f80 100644 --- a/.github/workflows/npm_on_release.yml +++ b/.github/workflows/npm_on_release.yml @@ -1,18 +1,33 @@ -name: Publish typescript-client +name: Publish typescript-client & CLI to NPM on release on: push: tags: - "v*" + workflow_dispatch: jobs: - build_npm: + publish_typescript_client: runs-on: ubicloud-standard-8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" registry-url: "https://registry.npmjs.org" - - run: cd typescript-client && ./publish.sh + - run: cd typescript-client && ./publish.sh && cd .. + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + publish_cli: + runs-on: ubicloud-standard-8 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version: "20.x" + registry-url: "https://registry.npmjs.org" + - uses: denoland/setup-deno@v1 + with: + deno-version: v1.x + - run: cd cli && ./build.sh && cd npm && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish_lsp.yml b/.github/workflows/publish_lsp.yml index f4c7ed3351..84f1f836aa 100644 --- a/.github/workflows/publish_lsp.yml +++ b/.github/workflows/publish_lsp.yml @@ -27,13 +27,13 @@ jobs: needs: [sleep] runs-on: ubicloud steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: depot/setup-action@v1 - name: Docker meta id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -44,7 +44,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/.github/workflows/pypi_on_release.yml b/.github/workflows/pypi_on_release.yml index 328033d362..39a3e11b2e 100644 --- a/.github/workflows/pypi_on_release.yml +++ b/.github/workflows/pypi_on_release.yml @@ -12,7 +12,7 @@ jobs: container: image: ghcr.io/windmill-labs/python-client-builder steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Upload python client env: PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} diff --git a/.gitignore b/.gitignore index 282fa5fb48..ffda06e6cb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ frontend/src/routes/test.svelte CaddyfileRemoteMalo *.swp **/.idea/ +.direnv diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b457783be..111225c3a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,846 @@ # Changelog +## [1.416.2](https://github.com/windmill-labs/windmill/compare/v1.416.1...v1.416.2) (2024-11-02) + + +### Bug Fixes + +* apply NO_PROXY and HTTP_PROXY, HTTPS_PROXY more consistently ([567d621](https://github.com/windmill-labs/windmill/commit/567d6216d2631a90fbe59ec6142c38b3b352eea7)) + +## [1.416.1](https://github.com/windmill-labs/windmill/compare/v1.416.0...v1.416.1) (2024-11-01) + + +### Bug Fixes + +* **prometheus:** fix incorrect worker_busy set to 1 ([53f9136](https://github.com/windmill-labs/windmill/commit/53f9136658b9fc1795793d82408c1f1f04adcf06)) + +## [1.416.0](https://github.com/windmill-labs/windmill/compare/v1.415.2...v1.416.0) (2024-11-01) + + +### Features + +* private hub user accessible url setting ([#4617](https://github.com/windmill-labs/windmill/issues/4617)) ([79edf89](https://github.com/windmill-labs/windmill/commit/79edf89bd17827d5f1d946739385327b6c0520bf)) + + +### Bug Fixes + +* **frontend:** improve tag selector for workspace script drawer ([66f6985](https://github.com/windmill-labs/windmill/commit/66f69859ad2de51aef5a133df4ab4397d0f61ccf)) + +## [1.415.2](https://github.com/windmill-labs/windmill/compare/v1.415.1...v1.415.2) (2024-11-01) + + +### Bug Fixes + +* **s3:** align s3 handler additional creds providers ([984c6dd](https://github.com/windmill-labs/windmill/commit/984c6dd10c63097eb195883c4d8a9681ab1b49e0)) + +## [1.415.1](https://github.com/windmill-labs/windmill/compare/v1.415.0...v1.415.1) (2024-10-31) + + +### Bug Fixes + +* **cli:** improve --instance handling wmill instance push ([cb005a1](https://github.com/windmill-labs/windmill/commit/cb005a15baef4272bc58c7e80a43e44723556d31)) + +## [1.415.0](https://github.com/windmill-labs/windmill/compare/v1.414.2...v1.415.0) (2024-10-31) + + +### Features + +* **cli:** opts.instance as instace name and prefix ([#4609](https://github.com/windmill-labs/windmill/issues/4609)) ([a07f57e](https://github.com/windmill-labs/windmill/commit/a07f57e698107056d045d8d5c2458e04c809fcc8)) + + +### Bug Fixes + +* improve express oauth setup ([ba4aed5](https://github.com/windmill-labs/windmill/commit/ba4aed5bf51c65204332cfc158d0ffd9c7095ec7)) +* improve user resource input ([8c7f53b](https://github.com/windmill-labs/windmill/commit/8c7f53b2ebe0990cd93879258d004ac89dc8b24c)) + +## [1.414.2](https://github.com/windmill-labs/windmill/compare/v1.414.1...v1.414.2) (2024-10-29) + + +### Bug Fixes + +* **cli:** improve instance sync for CI/CD + --folder-per-instance ([212579a](https://github.com/windmill-labs/windmill/commit/212579a514d070355fe0d9e0215593bacfa05e1f)) + +## [1.414.1](https://github.com/windmill-labs/windmill/compare/v1.414.0...v1.414.1) (2024-10-29) + + +### Bug Fixes + +* **apps:** enable text selection on aggrid tables by default ([b0b9180](https://github.com/windmill-labs/windmill/commit/b0b9180fb907c92b95a48ff286eb1dae59bb4981)) +* **apps:** public apps can take full height ([703db7d](https://github.com/windmill-labs/windmill/commit/703db7d4412795b4323a2eefcc39ae3cf43bc748)) +* **bun:** handle bun lockfile created with windows ([#4602](https://github.com/windmill-labs/windmill/issues/4602)) ([dcf5e2f](https://github.com/windmill-labs/windmill/commit/dcf5e2f03f977e241f6785530dad61a70c5bdd79)) +* **frontend:** make script and schema scrollable on script detail page ([6e222b3](https://github.com/windmill-labs/windmill/commit/6e222b3b1a419e5543fdf35420a7413699688b41)) +* **frontend:** new approval steps default to timeout 1800 ([b86de62](https://github.com/windmill-labs/windmill/commit/b86de6280e03e014e8ddf85b2b5f8fd030d0467a)) + +## [1.414.0](https://github.com/windmill-labs/windmill/compare/v1.413.2...v1.414.0) (2024-10-29) + +* Issue with previous release, re-releasing + +## [1.413.2](https://github.com/windmill-labs/windmill/compare/v1.413.1...v1.413.2) (2024-10-29) + + +### Bug Fixes + +* **backend:** in flows, workspace scripts should use their set tags instead of the default one ([5b7c6d7](https://github.com/windmill-labs/windmill/commit/5b7c6d7d62dcfd09fec374e781bdf5c5bafe4a9d)) +* **cli:** fix wmill instance pull --instance ([3c62f5e](https://github.com/windmill-labs/windmill/commit/3c62f5ea83d1da8bd3705468969d56e2fe680751)) +* **frontend:** fix script and flow renaming ([d743e00](https://github.com/windmill-labs/windmill/commit/d743e0056353a4fca445a7089e3afc1fd4e8c219)) + +## [1.413.1](https://github.com/windmill-labs/windmill/compare/v1.413.0...v1.413.1) (2024-10-28) + + +### Bug Fixes + +* **cli:** fix wmill instance push --base-url and --instance ([8298710](https://github.com/windmill-labs/windmill/commit/82987105a6fd6ec272c170fb094453a0267143be)) + +## [1.413.0](https://github.com/windmill-labs/windmill/compare/v1.412.0...v1.413.0) (2024-10-28) + + +### Features + +* autoscaling v0 ([#4593](https://github.com/windmill-labs/windmill/issues/4593)) ([fe7d044](https://github.com/windmill-labs/windmill/commit/fe7d044a66e8ec223a337cb704d3e58942dd1502)) + + +### Bug Fixes + +* add run immediately popover to run again ([e54d253](https://github.com/windmill-labs/windmill/commit/e54d25368541dc6109a0f99022a120d28455f9bd)) +* **docs:** smtp setup documentation link ([#4590](https://github.com/windmill-labs/windmill/issues/4590)) ([bac3205](https://github.com/windmill-labs/windmill/commit/bac32057259d893140d649c9dfec2ca75e395ad4)) + +## [1.412.0](https://github.com/windmill-labs/windmill/compare/v1.411.1...v1.412.0) (2024-10-25) + + +### Features + +* add Spotify oauth provider ([#4581](https://github.com/windmill-labs/windmill/issues/4581)) ([a46aa64](https://github.com/windmill-labs/windmill/commit/a46aa644b096e71e75b59507224ed92f7d2f99ba)) + + +### Bug Fixes + +* **app builder:** date input default value improvements ([9f43d5d](https://github.com/windmill-labs/windmill/commit/9f43d5dcd92ddcd0c0baeaa5271779520af652f4)) +* **bash:** correctly propagate sigterm for cancelled bash scripts ([134cfdb](https://github.com/windmill-labs/windmill/commit/134cfdb30eb8d29c2ecb1b78b8fabae2b6e10700)) +* do not update created_at of scripts on lockfile generation ([d1a28eb](https://github.com/windmill-labs/windmill/commit/d1a28eb7cac5f465e2b07f870a507b0cc5cc722a)) +* initialize empty smtp settings correctly ([84e0524](https://github.com/windmill-labs/windmill/commit/84e05249505c3d2f7eb7a4917f6bca503df81017)) + +## [1.411.1](https://github.com/windmill-labs/windmill/compare/v1.411.0...v1.411.1) (2024-10-22) + + +### Bug Fixes + +* update bun to 1.1.32 ([#4568](https://github.com/windmill-labs/windmill/issues/4568)) ([0586446](https://github.com/windmill-labs/windmill/commit/058644667129f0d79ec147aacdda449142ae0ab9)) + +## [1.411.0](https://github.com/windmill-labs/windmill/compare/v1.410.3...v1.411.0) (2024-10-21) + + +### Features + +* **cli:** encrypt sensitive instance settings ([#4561](https://github.com/windmill-labs/windmill/issues/4561)) ([b8a6a11](https://github.com/windmill-labs/windmill/commit/b8a6a116354b10f5977e54edb365d6711e160538)) + + +### Bug Fixes + +* Do not ignore file resources with json file ext ([#4562](https://github.com/windmill-labs/windmill/issues/4562)) ([2079b2e](https://github.com/windmill-labs/windmill/commit/2079b2e7e19aa2fe327f2ae66d1b5eba988b9b0a)) +* update bun to 1.1.31 and deno to 2.0.2 ([0d90396](https://github.com/windmill-labs/windmill/commit/0d9039641b3348e75599937188c35dd89a000584)) + +## [1.410.3](https://github.com/windmill-labs/windmill/compare/v1.410.2...v1.410.3) (2024-10-20) + + +### Bug Fixes + +* **go-client:** reduce runtime dependencies by bumping oai-codeen to v2.4.1 ([87f5c07](https://github.com/windmill-labs/windmill/commit/87f5c078dd63cd3e0ba3e719c2da7b83f1458e2c)) + +## [1.410.1](https://github.com/windmill-labs/windmill/compare/v1.410.0...v1.410.1) (2024-10-19) + + +### Bug Fixes + +* **cli:** improve wmill init behavior ([26a40d1](https://github.com/windmill-labs/windmill/commit/26a40d19441aa816ee711ce30f3435dddd3542a7)) +* **frontend:** improve display of error handlers ([a92a2fd](https://github.com/windmill-labs/windmill/commit/a92a2fd6fd67c11c04554a90b8ae6d7a0dd9067c)) + +## [1.410.1](https://github.com/windmill-labs/windmill/compare/v1.410.0...v1.410.1) (2024-10-19) + + +### Bug Fixes + +* **cli:** improve wmill init behavior ([26a40d1](https://github.com/windmill-labs/windmill/commit/26a40d19441aa816ee711ce30f3435dddd3542a7)) + +## [1.410.0](https://github.com/windmill-labs/windmill/compare/v1.409.4...v1.410.0) (2024-10-18) + + +### Features + +* **typescript-bun:** support relative imports without the .ts extension ([248fdc2](https://github.com/windmill-labs/windmill/commit/248fdc24a61aca946902b20b9d8187101a9b7bfa)) +* websocket triggers ([#4505](https://github.com/windmill-labs/windmill/issues/4505)) ([8807e99](https://github.com/windmill-labs/windmill/commit/8807e99f06caf3e26c526eefdc83dbc2f7aa93ee)) + + +### Bug Fixes + +* cache js static assets by default ([08595c6](https://github.com/windmill-labs/windmill/commit/08595c6f14a89df1559974e8835e63881a1a9601)) +* **frontend:** add back script lockfile to script details pae ([549b11d](https://github.com/windmill-labs/windmill/commit/549b11dcfb39a60acd6d3899fce51b31149f8594)) +* improve cancelling of jobs on public apps for anonymous users ([d7cf5ea](https://github.com/windmill-labs/windmill/commit/d7cf5ea37db313e78865708bc22e87a1feea9e0d)) + +## [1.409.4](https://github.com/windmill-labs/windmill/compare/v1.409.3...v1.409.4) (2024-10-17) + + +### Bug Fixes + +* fix flow viewer renderer outside of flow details and editor context ([59a1e67](https://github.com/windmill-labs/windmill/commit/59a1e67465cd21ded5539cb5b829bc0d4e7169ed)) + +## [1.409.3](https://github.com/windmill-labs/windmill/compare/v1.409.2...v1.409.3) (2024-10-17) + + +### Bug Fixes + +* do not delete primary schedule of script/flow on redeploy even if schedule wasn't loaded ([c3c2fe4](https://github.com/windmill-labs/windmill/commit/c3c2fe462c52f48795a55025414b16f8d3d98fe0)) +* **nsjail:** improve memory reading when using nsjail ([b7ad19b](https://github.com/windmill-labs/windmill/commit/b7ad19bb75bd885a254ebac778349c7d88af8326)) + +## [1.409.2](https://github.com/windmill-labs/windmill/compare/v1.409.1...v1.409.2) (2024-10-16) + + +### Bug Fixes + +* add extra args support for exception to bun scripts ([1466da3](https://github.com/windmill-labs/windmill/commit/1466da3999add0238b9c42ca13df52194f082fc0)) +* fix script persistence in url + add support for extra error args in python ([3174024](https://github.com/windmill-labs/windmill/commit/3174024d8e6ecbe9f8c9e1ea055d611f652c0057)) + +## [1.409.1](https://github.com/windmill-labs/windmill/compare/v1.409.0...v1.409.1) (2024-10-16) + + +### Bug Fixes + +* **apidocs:** fix generated openapi files ([d24e153](https://github.com/windmill-labs/windmill/commit/d24e1530655d27ffda9bb4c19471dc1431124cc2)) +* **git-sync:** propagate update of folders with git sync ([6abb346](https://github.com/windmill-labs/windmill/commit/6abb346013da4a907a860713a8a67642985b8025)) + +## [1.409.0](https://github.com/windmill-labs/windmill/compare/v1.408.1...v1.409.0) (2024-10-16) + + +### Features + +* **frontend:** unify all triggers UX and simplify flow settings ([#4259](https://github.com/windmill-labs/windmill/issues/4259)) ([91a3d06](https://github.com/windmill-labs/windmill/commit/91a3d065298cce7a882464fa0cd31d8f1ae9dda2)) +* Scroll to element in virtual list when clicking on graph point ([#4532](https://github.com/windmill-labs/windmill/issues/4532)) ([7126ba1](https://github.com/windmill-labs/windmill/commit/7126ba12c7eb52d2cfbe8d83311b5592a5707bce)) +* **sso:** adding the ability to define a custom display name for sso ([#4529](https://github.com/windmill-labs/windmill/issues/4529)) ([99c5b3e](https://github.com/windmill-labs/windmill/commit/99c5b3ecdacb1158c2cba5b891c4c3b8b70c3b6a)) + + +### Bug Fixes + +* Add indexer backup lock to fit the deployment model ([#4531](https://github.com/windmill-labs/windmill/issues/4531)) ([411bce7](https://github.com/windmill-labs/windmill/commit/411bce7e13aabfa53db80d55261ea4511f6d1ae9)) +* **app:** accept connecting to non yet existing state output for convenience ([9eb1ecc](https://github.com/windmill-labs/windmill/commit/9eb1ecc9f3017e2f4284a827a2bcd21f36b1b8ac)) +* **app:** improve absolute url handling in download button and downloadFile ([dcdbf1a](https://github.com/windmill-labs/windmill/commit/dcdbf1afb4d5a18e00b9bbb1eb0bef129ea5667f)) +* **app:** make s3 uploads persistent across tabs change ([c3b536b](https://github.com/windmill-labs/windmill/commit/c3b536b1b8069898131768867a187b186b21e537)) +* canceled jobs button reporting 0 jobs cancelled ([#4534](https://github.com/windmill-labs/windmill/issues/4534)) ([e736572](https://github.com/windmill-labs/windmill/commit/e736572db10929ae5e123c4f6cef73b8e90fc29b)) +* **python-client:** improve get_job_status for running jobs ([a8c4ea2](https://github.com/windmill-labs/windmill/commit/a8c4ea2334d2535fa7d5d43f58d65565afe8f3e5)) +* **ui:** dark mode support for queue metrics based critical alert ([#4535](https://github.com/windmill-labs/windmill/issues/4535)) ([f38b3d1](https://github.com/windmill-labs/windmill/commit/f38b3d14e8092ae58817511aea91a4e77725ead6)) + +## [1.408.1](https://github.com/windmill-labs/windmill/compare/v1.408.0...v1.408.1) (2024-10-12) + + +### Bug Fixes + +* fix deno cache --allow-import on deno 2 ([42fe31f](https://github.com/windmill-labs/windmill/commit/42fe31f804c9e6643cd90167494e45270831e013)) + +## [1.408.0](https://github.com/windmill-labs/windmill/compare/v1.407.2...v1.408.0) (2024-10-12) + + +### Features + +* **app builder:** file download helper ([#4511](https://github.com/windmill-labs/windmill/issues/4511)) ([f82f091](https://github.com/windmill-labs/windmill/commit/f82f09129096cfff975370d8bb7b6d832a2b8f9f)) + + +### Bug Fixes + +* **cli:** handle case where 'toString' is a schema field ([568cc66](https://github.com/windmill-labs/windmill/commit/568cc66932fb0470f5e89de7b02d94dba4050638)) +* **frontend:** s3 file uploader works on public apps too ([982dde2](https://github.com/windmill-labs/windmill/commit/982dde2b9dfe6d9eda300c683af729d97a03cb4d)) +* **frontend:** set unused schema property fields to null ([be11240](https://github.com/windmill-labs/windmill/commit/be112408e7c4601314726e9517c37daaeaa1bf09)) +* improve workflow as code row-lock on db to handle more concurrency ([d2c4d3f](https://github.com/windmill-labs/windmill/commit/d2c4d3fa207379cb0b8ac180f6ccc759045580e8)) + +## [1.407.2](https://github.com/windmill-labs/windmill/compare/v1.407.1...v1.407.2) (2024-10-10) + + +### Bug Fixes + +* improve default properties of new nodes of flows (suspend, branchone, branchall) ([d9bdc5a](https://github.com/windmill-labs/windmill/commit/d9bdc5a5b08dd4d0381304656af097315398c9d4)) + +## [1.407.1](https://github.com/windmill-labs/windmill/compare/v1.407.0...v1.407.1) (2024-10-10) + + +### Bug Fixes + +* improve handling of empty lock files on deno 2.0 ([7ca5bf2](https://github.com/windmill-labs/windmill/commit/7ca5bf2faeff44a7543b1afa9369c140fcb71dfc)) + +## [1.407.0](https://github.com/windmill-labs/windmill/compare/v1.406.0...v1.407.0) (2024-10-10) + + +### Features + +* upgrade to deno 2 ([26b11a0](https://github.com/windmill-labs/windmill/commit/26b11a00150acbe101abe4bb542f24379da0cc56)) + + +### Bug Fixes + +* update internal deno runtime to latest (deno 2.0) ([c3a5736](https://github.com/windmill-labs/windmill/commit/c3a57366419882ea2de1938bea592c795b1a1d03)) + +## [1.406.0](https://github.com/windmill-labs/windmill/compare/v1.405.5...v1.406.0) (2024-10-09) + + +### Features + +* **frontend:** components can be moved inside containers by holding ctrl/cmd ([111bfc6](https://github.com/windmill-labs/windmill/commit/111bfc6a659037ae7029e8f557256e2fffcf979b)) +* **monitoring:** Critical Alerts for Jobs Waiting in Queue [enterprise] ([#4491](https://github.com/windmill-labs/windmill/issues/4491)) ([d90d6c2](https://github.com/windmill-labs/windmill/commit/d90d6c2b896c5f99e00681656f376b180901f272)) + + +### Bug Fixes + +* **cli:** instance sync push does not require sync pull ([257f097](https://github.com/windmill-labs/windmill/commit/257f0971f86938da71b879f32d93473976eaa920)) +* remove monaco-editor for app preview code path for faster app loads ([7b05033](https://github.com/windmill-labs/windmill/commit/7b0503332d1bdd7f5999a5ef99150f8c9f6f18be)) + +## [1.405.5](https://github.com/windmill-labs/windmill/compare/v1.405.4...v1.405.5) (2024-10-04) + + +### Bug Fixes + +* windows.exe build with github workflow doesn't have openssl.dll bundled in ([#4489](https://github.com/windmill-labs/windmill/issues/4489)) ([284cb40](https://github.com/windmill-labs/windmill/commit/284cb4069c97efe59b5caf3effb68c8b30e02b73)) + +## [1.405.4](https://github.com/windmill-labs/windmill/compare/v1.405.3...v1.405.4) (2024-10-04) + + +### Bug Fixes + +* **frontend:** correctly initialize step inputs on new inline script ([289ad51](https://github.com/windmill-labs/windmill/commit/289ad51374f0344582372572fc521f3b2bf12b33)) + +## [1.405.3](https://github.com/windmill-labs/windmill/compare/v1.405.2...v1.405.3) (2024-10-04) + + +### Bug Fixes + +* fix id save on apps ([b034b07](https://github.com/windmill-labs/windmill/commit/b034b070c075a0fab74678bec1fd8b829d55b204)) + +## [1.405.2](https://github.com/windmill-labs/windmill/compare/v1.405.1...v1.405.2) (2024-10-03) + + +### Bug Fixes + +* **cli:** fix opts.yes for instance sync ([26659ce](https://github.com/windmill-labs/windmill/commit/26659ce37d2887d5b98dbdbdbba27bab85d4fe3f)) +* fix uv path ([19c62ba](https://github.com/windmill-labs/windmill/commit/19c62ba195b1df85c38c748dab7d9f137696a5c3)) + +## [1.405.1](https://github.com/windmill-labs/windmill/compare/v1.405.0...v1.405.1) (2024-10-03) + + +### Bug Fixes + +* flow picker of flows + precache hub scripts as bundles ([c84e6fd](https://github.com/windmill-labs/windmill/commit/c84e6fd05de2bea426cae61fa25db0323b8770f5)) + +## [1.405.0](https://github.com/windmill-labs/windmill/compare/v1.404.1...v1.405.0) (2024-10-03) + + +### Features + +* Replace `pip-compile` with `uv` ([#4460](https://github.com/windmill-labs/windmill/issues/4460)) ([b54c9ee](https://github.com/windmill-labs/windmill/commit/b54c9ee657cc88fabe694cae39dc0d3c1918fcbb)) +* **worker:** support workers to run natively on windows ([#4446](https://github.com/windmill-labs/windmill/issues/4446)) ([f5c4727](https://github.com/windmill-labs/windmill/commit/f5c472727465dd95f5378bc08ee9bbb983f4d259)) + + +### Bug Fixes + +* **cli:** fix set client of instance when passing token and base url ([794c4cd](https://github.com/windmill-labs/windmill/commit/794c4cde3cd47042472dccdf4b60a012014dd26d)) + +## [1.404.1](https://github.com/windmill-labs/windmill/compare/v1.404.0...v1.404.1) (2024-10-03) + + +### Bug Fixes + +* flow picker of flows ([92f61f0](https://github.com/windmill-labs/windmill/commit/92f61f07ed6d354407d26843e3a270b95bae90bc)) + +## [1.404.0](https://github.com/windmill-labs/windmill/compare/v1.403.1...v1.404.0) (2024-10-03) + + +### Features + +* **frontend:** add quick access menu in flow editor ([#4415](https://github.com/windmill-labs/windmill/issues/4415)) ([45ccd45](https://github.com/windmill-labs/windmill/commit/45ccd45e306c66931880a9b8fd48bfe684c774ac)) + + +### Bug Fixes + +* **cli:** improve schedule path handling on windows ([9ac3b6b](https://github.com/windmill-labs/windmill/commit/9ac3b6b1d5d64d7467dd80506f8a8d772c4630bd)) +* fix id editor for app ([8e58e43](https://github.com/windmill-labs/windmill/commit/8e58e4320a31d71c40a5ed352416a4c2dd3adb26)) +* **frontend:** disable runnable field on route editor from detail panel ([#4469](https://github.com/windmill-labs/windmill/issues/4469)) ([3134f79](https://github.com/windmill-labs/windmill/commit/3134f79ced80aab86912643ab7a60dcf909ab104)) + +## [1.403.1](https://github.com/windmill-labs/windmill/compare/v1.403.0...v1.403.1) (2024-10-01) + + +### Bug Fixes + +* fix new instance db setup ([73ab8e1](https://github.com/windmill-labs/windmill/commit/73ab8e1653d6e0c0c69fa7dcd96583f25d13ef86)) + +## [1.403.0](https://github.com/windmill-labs/windmill/compare/v1.402.3...v1.403.0) (2024-10-01) + + +### Features + +* flow step skipping ([#4461](https://github.com/windmill-labs/windmill/issues/4461)) ([0df169e](https://github.com/windmill-labs/windmill/commit/0df169e3f996ed54b91569b13cce15d7d019a213)) + + +### Bug Fixes + +* skip one migration to avoid using md5 for azure support ([630ae5d](https://github.com/windmill-labs/windmill/commit/630ae5d425cd9957d674befd2df96e2befec52a3)) + +## [1.402.3](https://github.com/windmill-labs/windmill/compare/v1.402.2...v1.402.3) (2024-09-30) + + +### Bug Fixes + +* improve allowed domains setting for sso ([24f4a7c](https://github.com/windmill-labs/windmill/commit/24f4a7caaafa93f51669dcf44a3dca09d5b228bb)) + +## [1.402.2](https://github.com/windmill-labs/windmill/compare/v1.402.1...v1.402.2) (2024-09-28) + + +### Bug Fixes + +* make form properties disablable ([0779d47](https://github.com/windmill-labs/windmill/commit/0779d47c1d39626d11bd3769cd787cb036df0a94)) + +## [1.402.1](https://github.com/windmill-labs/windmill/compare/v1.402.0...v1.402.1) (2024-09-28) + + +### Bug Fixes + +* allow preprocessor to write to args.json on nsjail ([#4455](https://github.com/windmill-labs/windmill/issues/4455)) ([0b9ec83](https://github.com/windmill-labs/windmill/commit/0b9ec83036e2a1d0773b4ec5856f907b383e9323)) +* **frontend:** Fix flow graph bg in dark mode on chrome ([#4454](https://github.com/windmill-labs/windmill/issues/4454)) ([6956a3a](https://github.com/windmill-labs/windmill/commit/6956a3a2ba6d189528cb34ab05f7137fdf4f840b)) +* improve suspend_first behavior and frequency ([b5e226b](https://github.com/windmill-labs/windmill/commit/b5e226b977e6d24ebd28bc1e7c867cb4888f77b2)) + +## [1.402.0](https://github.com/windmill-labs/windmill/compare/v1.401.0...v1.402.0) (2024-09-26) + + +### Features + +* **cli:** add queues, workers and worker-groups commands ([#4439](https://github.com/windmill-labs/windmill/issues/4439)) ([9f91b19](https://github.com/windmill-labs/windmill/commit/9f91b1995a98c9e096c6e599c4d5a8d5ea499ada)) + +## [1.401.0](https://github.com/windmill-labs/windmill/compare/v1.400.0...v1.401.0) (2024-09-25) + + +### Features + +* add return_last_result annotation to sql ([#4443](https://github.com/windmill-labs/windmill/issues/4443)) ([3ce5587](https://github.com/windmill-labs/windmill/commit/3ce5587faae3912ceedae4644732fa9704eb6d76)) + + +### Bug Fixes + +* fix flow rendering ([fd58e7e](https://github.com/windmill-labs/windmill/commit/fd58e7eb48c4fb66d199c33d0f8aaf2535485a2f)) + +## [1.400.0](https://github.com/windmill-labs/windmill/compare/v1.399.0...v1.400.0) (2024-09-25) + + +### Features + +* add static variable and resources support to ansible ([#4435](https://github.com/windmill-labs/windmill/issues/4435)) ([398a09b](https://github.com/windmill-labs/windmill/commit/398a09b7419c7adafa76e5f9f5a981bec6f0611d)) +* **frontend:** Catch flow errors in the UI ([#4429](https://github.com/windmill-labs/windmill/issues/4429)) ([84eefad](https://github.com/windmill-labs/windmill/commit/84eefadfcf06b4f38117b6c4c534f47fb2ef7cc7)) + + +### Bug Fixes + +* remove autocomplete for searchbar ([#4440](https://github.com/windmill-labs/windmill/issues/4440)) ([a1ac583](https://github.com/windmill-labs/windmill/commit/a1ac583f05c34a534c4ae78ca7d2a6850723ce85)) + +## [1.399.0](https://github.com/windmill-labs/windmill/compare/v1.398.1...v1.399.0) (2024-09-25) + + +### Features + +* add tag filtering to external JWT authentication ([#4425](https://github.com/windmill-labs/windmill/issues/4425)) ([590321f](https://github.com/windmill-labs/windmill/commit/590321fd3c88046a657e0a751b62a19424102060)) + + +### Bug Fixes + +* **cli:** version the whole client for deno compatibility ([81c2bb0](https://github.com/windmill-labs/windmill/commit/81c2bb069176a95b8fb9c52b31e5e03c1cc78afc)) +* correct AI generation for CRON and regex ([#4437](https://github.com/windmill-labs/windmill/issues/4437)) ([aeb5b5b](https://github.com/windmill-labs/windmill/commit/aeb5b5bcd163e2e7d1413d7e4aed8bd769996f24)) + +## [1.398.1](https://github.com/windmill-labs/windmill/compare/v1.398.0...v1.398.1) (2024-09-23) + + +### Bug Fixes + +* time handling in bun and deno ([#4423](https://github.com/windmill-labs/windmill/issues/4423)) ([61f27ac](https://github.com/windmill-labs/windmill/commit/61f27acbd5b477f0e2453d4b02d406a7aef76009)) + +## [1.398.0](https://github.com/windmill-labs/windmill/compare/v1.397.4...v1.398.0) (2024-09-23) + + +### Features + +* **frontend:** add http routing templates ([#4421](https://github.com/windmill-labs/windmill/issues/4421)) ([e99e7b2](https://github.com/windmill-labs/windmill/commit/e99e7b2b0bb1bc63d1253d147b80bac06eaff103)) +* http routing ([#4339](https://github.com/windmill-labs/windmill/issues/4339)) ([304dac3](https://github.com/windmill-labs/windmill/commit/304dac34475b8871621c54a768275fae1e9f845e)) + + +### Bug Fixes + +* allow no body in job requests ([#4413](https://github.com/windmill-labs/windmill/issues/4413)) ([70fa78c](https://github.com/windmill-labs/windmill/commit/70fa78c10d8afb3e06be84e3449fdfdeb2673765)) +* **frontend:** Fix delete branch one index ([#4418](https://github.com/windmill-labs/windmill/issues/4418)) ([30017cc](https://github.com/windmill-labs/windmill/commit/30017cc2b1401ea439e3fbec5d7764b206100a38)) +* migrate smtp instance settings to global settings ([#4416](https://github.com/windmill-labs/windmill/issues/4416)) ([50a6f78](https://github.com/windmill-labs/windmill/commit/50a6f789fa8a03d70407b0429da049cc0740b6fa)) +* no failed renewal alert if trial ([#4414](https://github.com/windmill-labs/windmill/issues/4414)) ([5be7be0](https://github.com/windmill-labs/windmill/commit/5be7be03a6df34a9fae96ed7f844d693f7cfce3e)) +* update pip to 24.2 and python 3.11.8->3.11.10 ([a17195d](https://github.com/windmill-labs/windmill/commit/a17195d88ff52b72f0c2cdd95c6218df8ef6d7cf)) +* various improvements for ansible ([#4419](https://github.com/windmill-labs/windmill/issues/4419)) ([a500994](https://github.com/windmill-labs/windmill/commit/a500994cc2cd9cc6cbad722059cebd0bf74a8850)) + +## [1.397.4](https://github.com/windmill-labs/windmill/compare/v1.397.3...v1.397.4) (2024-09-20) + + +### Bug Fixes + +* **cli:** make CLI not require latest version of windmill ([794f87a](https://github.com/windmill-labs/windmill/commit/794f87aa0d33a0b782fcb2726754fdc51bc1d73d)) + +## [1.397.3](https://github.com/windmill-labs/windmill/compare/v1.397.2...v1.397.3) (2024-09-20) + + +### Bug Fixes + +* **cli:** make CLI compatible with Node 18 ([8212532](https://github.com/windmill-labs/windmill/commit/8212532b29fbcf971cb320b8cfc84f3a8d8ad795)) + +## [1.397.2](https://github.com/windmill-labs/windmill/compare/v1.397.1...v1.397.2) (2024-09-20) + + +### Bug Fixes + +* **bun:** never pre-bundle BASE_URL env variable ([69b8754](https://github.com/windmill-labs/windmill/commit/69b8754aef32682bf812be783f79b81cd8526c7a)) + +## [1.397.1](https://github.com/windmill-labs/windmill/compare/v1.397.0...v1.397.1) (2024-09-20) + + +### Bug Fixes + +* **go:** put shared directory in job dir and not go parent ([623ece8](https://github.com/windmill-labs/windmill/commit/623ece8c6791b2c18648a68c562fcd5c8291be9b)) +* improve ability to paste from macos in vscode extension ([07372e7](https://github.com/windmill-labs/windmill/commit/07372e7e65d77df338718929f133e477a1daf993)) +* update git sync script ([30fe28c](https://github.com/windmill-labs/windmill/commit/30fe28ceecb9043eee6811dce8c3e2cd9224927b)) + +## [1.397.0](https://github.com/windmill-labs/windmill/compare/v1.396.1...v1.397.0) (2024-09-18) + + +### Features + +* ansible playbook support ([#4399](https://github.com/windmill-labs/windmill/issues/4399)) ([6855b8d](https://github.com/windmill-labs/windmill/commit/6855b8da9ad92aed514ee1ab214c9550d04e7a22)) + +## [1.396.1](https://github.com/windmill-labs/windmill/compare/v1.396.0...v1.396.1) (2024-09-18) + + +### Bug Fixes + +* postgres scripts that take longer than 20s do not timeout anymore ([37d152f](https://github.com/windmill-labs/windmill/commit/37d152feeb6abeb061daa5c93c24916e520b1fd0)) + +## [1.396.0](https://github.com/windmill-labs/windmill/compare/v1.395.0...v1.396.0) (2024-09-17) + + +### Features + +* Allow setProgress and getProgress from within the script ([#4400](https://github.com/windmill-labs/windmill/issues/4400)) ([d6d4756](https://github.com/windmill-labs/windmill/commit/d6d4756b7a40249dbc622c8a93633e8d8b8333da)) + +## [1.395.0](https://github.com/windmill-labs/windmill/compare/v1.394.6...v1.395.0) (2024-09-17) + + +### Features + +* failed key renewal alert + renew on start if no recent renewal ([#4387](https://github.com/windmill-labs/windmill/issues/4387)) ([de78f6c](https://github.com/windmill-labs/windmill/commit/de78f6c19266c67d43c7f80016a94b7988347e01)) + + +### Bug Fixes + +* cannot create duplicate apps and raw_apps ([d57b139](https://github.com/windmill-labs/windmill/commit/d57b139df2267d1650749b31a3cce5742a3654d9)) +* **cli:** update CLI schema parsers to latest ([6ba77d5](https://github.com/windmill-labs/windmill/commit/6ba77d533fc1c50cf4153730adaf1b14a466f10a)) +* **deno:** replace lock-write with frozen=false ([277d085](https://github.com/windmill-labs/windmill/commit/277d085dbed0b9b1424348cc580ba601d935759b)) +* **frontend:** add support for step id change for forloops and branch… ([#4395](https://github.com/windmill-labs/windmill/issues/4395)) ([97839a3](https://github.com/windmill-labs/windmill/commit/97839a3583ef398c11e2f51058aaceed8e7382fb)) +* **frontend:** new resource type name must be snake case ([#4396](https://github.com/windmill-labs/windmill/issues/4396)) ([9297ffc](https://github.com/windmill-labs/windmill/commit/9297ffcac4d2092022463cd68b4e8ce8f02dcb3c)) +* improve vscode extension handling of relative paths ([8ae6c32](https://github.com/windmill-labs/windmill/commit/8ae6c3262a75af378a261b49f0e3a08d668c74b3)) +* update bun to 1.1.27 ([39374d7](https://github.com/windmill-labs/windmill/commit/39374d7ee13ffa0fe1e4ded146c91869acad144c)) + +## [1.394.6](https://github.com/windmill-labs/windmill/compare/v1.394.5...v1.394.6) (2024-09-15) + + +### Bug Fixes + +* improve first time setup experience ([396258f](https://github.com/windmill-labs/windmill/commit/396258f637e65361a9d9e0285b0a42ca5189fad4)) + +## [1.394.5](https://github.com/windmill-labs/windmill/compare/v1.394.4...v1.394.5) (2024-09-13) + + +### Bug Fixes + +* add filename to s3 upload ([11ca14a](https://github.com/windmill-labs/windmill/commit/11ca14a2d32155e215c0d14d485e2c4048e5c66e)) +* parquet renderer display number of rows" ([#4389](https://github.com/windmill-labs/windmill/issues/4389)) ([51cf420](https://github.com/windmill-labs/windmill/commit/51cf420272cce1948dc4295b587f5037455c4eba)) +* queue metrics graph ([#4388](https://github.com/windmill-labs/windmill/issues/4388)) ([af85d49](https://github.com/windmill-labs/windmill/commit/af85d4936ddd01b390976c9989f3e4e72da3d01e)) +* update internal hub scritps to bun ([#4384](https://github.com/windmill-labs/windmill/issues/4384)) ([f140daf](https://github.com/windmill-labs/windmill/commit/f140daf4dc18db0a11bf478451aa57ae4698fd32)) + +## [1.394.4](https://github.com/windmill-labs/windmill/compare/v1.394.3...v1.394.4) (2024-09-13) + + +### Bug Fixes + +* **frontend:** prompt fix-AI not to rename existing variables ([#4382](https://github.com/windmill-labs/windmill/issues/4382)) ([03a2eae](https://github.com/windmill-labs/windmill/commit/03a2eae49ac5b7c858e642e9f264beebbb2e9b34)) +* **frontend:** table footer display on safari ([#4377](https://github.com/windmill-labs/windmill/issues/4377)) ([93e5ba1](https://github.com/windmill-labs/windmill/commit/93e5ba1d16fcf52dea54ae4b4d7e5b02a899d0bd)) +* **image:** correctly publish windmill-full image ([bde3339](https://github.com/windmill-labs/windmill/commit/bde3339de53ad8430df6d7add6cfb00b4eb895c6)) +* improve app select propagation to list inputs in apps ([fb4c8d2](https://github.com/windmill-labs/windmill/commit/fb4c8d266a359af1ada4541e21b68bac9cb268a8)) +* improve password input for resources editor ([5bef077](https://github.com/windmill-labs/windmill/commit/5bef077480f1d708c507d943abcb4d36de084175)) +* multiple secret picker candidates in resource adder ([f222645](https://github.com/windmill-labs/windmill/commit/f222645dcead8f6608b81be36c683df679a5ae1c)) +* tighten inputs for granular kinds ([#4379](https://github.com/windmill-labs/windmill/issues/4379)) ([ff08b5a](https://github.com/windmill-labs/windmill/commit/ff08b5a9b5606f02228d0b54b45d422704fed3cb)) +* tighten number input validity if min or max is set ([7c16f2c](https://github.com/windmill-labs/windmill/commit/7c16f2cef4943a5d02e2bc6163761d80618aeae4)) +* timeout in pg executor on postgresql connection after 20s ([4dc9ca7](https://github.com/windmill-labs/windmill/commit/4dc9ca7f4e1477c087fe4f9bf6ea03fbcc99099c)) + +## [1.394.3](https://github.com/windmill-labs/windmill/compare/v1.394.2...v1.394.3) (2024-09-11) + + +### Bug Fixes + +* improve runFlowAsync and run_flow_async default behavior + time formatting of scheduled for ([51e6f36](https://github.com/windmill-labs/windmill/commit/51e6f36e13b251f01ddb8514de0d6d1a2bcd2244)) + +## [1.394.2](https://github.com/windmill-labs/windmill/compare/v1.394.1...v1.394.2) (2024-09-11) + + +### Bug Fixes + +* add tag_override for script in flows ([0e64380](https://github.com/windmill-labs/windmill/commit/0e6438047369e0c074e93246d627ecf06c0c78d5)) +* graceful worker exits for same worker jobs ([#4371](https://github.com/windmill-labs/windmill/issues/4371)) ([042a2bf](https://github.com/windmill-labs/windmill/commit/042a2bf917173a540aab7251a559c72c9c687228)) + +## [1.394.1](https://github.com/windmill-labs/windmill/compare/v1.394.0...v1.394.1) (2024-09-11) + + +### Bug Fixes + +* default success handler key can be viewed by anyone in the workspace ([c44e0d3](https://github.com/windmill-labs/windmill/commit/c44e0d37426599186a890f11a079bf2c2030e32d)) +* handle better same_worker flow monitor ([4720237](https://github.com/windmill-labs/windmill/commit/4720237091d4f41d85d9a0f177428d7c3e6d917e)) +* same worker is transitive on nested flows ([decb487](https://github.com/windmill-labs/windmill/commit/decb4873f1d6080f90c1fb2a8dac70423ae2d11a)) + +## [1.394.0](https://github.com/windmill-labs/windmill/compare/v1.393.4...v1.394.0) (2024-09-10) + + +### Features + +* add ability to edit id in flows ([#4364](https://github.com/windmill-labs/windmill/issues/4364)) ([a19db9a](https://github.com/windmill-labs/windmill/commit/a19db9a8d36fd07ff123e09ee079128e353273ad)) + + +### Bug Fixes + +* **cli:** browser login works on npm ([cfb50ce](https://github.com/windmill-labs/windmill/commit/cfb50ce8b8cf5e0e45af4b0fc79e9741d8077c31)) +* **cli:** on node, prompt paste accept more than 8 chars ([e824d2a](https://github.com/windmill-labs/windmill/commit/e824d2a76c0bdcb8aedec190640b26e259ad1131)) +* migrate git sync to using bun based script ([6b43d7e](https://github.com/windmill-labs/windmill/commit/6b43d7e227f2af2d4838d5f816672798d1857e19)) + +## [1.393.4](https://github.com/windmill-labs/windmill/compare/v1.393.3...v1.393.4) (2024-09-09) + + +### Bug Fixes + +* bun scripts cached in docker image have their dependencies pre-loaded ([4a6c3c8](https://github.com/windmill-labs/windmill/commit/4a6c3c8cc51e9e9b15410b4894ae6065e19d6068)) +* **cli:** add --extra-includes to improve git sync capabilities ([9329006](https://github.com/windmill-labs/windmill/commit/9329006ad822e78c196d5ea6469b694d20c9a67f)) +* fix hub sync script ([4e09e7f](https://github.com/windmill-labs/windmill/commit/4e09e7f4517c26fa91820d5fe8202a36ed84ef1c)) + +## [1.393.3](https://github.com/windmill-labs/windmill/compare/v1.393.2...v1.393.3) (2024-09-07) + + +### Bug Fixes + +* **cli:** guide users to migrate to node version of the CLI ([3998ecb](https://github.com/windmill-labs/windmill/commit/3998ecbf7b5c1c1e4ed9f6fb8911e1e18317f815)) + +## [1.393.2](https://github.com/windmill-labs/windmill/compare/v1.393.1...v1.393.2) (2024-09-07) + + +### Bug Fixes + +* **cli:** add --base-url option to add possibility of setting every arg without needing to add a workspace first ([1e813b2](https://github.com/windmill-labs/windmill/commit/1e813b26103098c69ac7880876611954b0ff6996)) + +## [1.393.1](https://github.com/windmill-labs/windmill/compare/v1.393.0...v1.393.1) (2024-09-07) + + +### Bug Fixes + +* fix CLI publishing ([65cddaf](https://github.com/windmill-labs/windmill/commit/65cddaf9752722b1a9489d54e646e270ce742e1d)) + +## [1.393.0](https://github.com/windmill-labs/windmill/compare/v1.392.0...v1.393.0) (2024-09-07) + + +### Features + +* make CLI node compatible ([#4347](https://github.com/windmill-labs/windmill/issues/4347)) ([9b4c598](https://github.com/windmill-labs/windmill/commit/9b4c59809c2b30d419168e624b83379023c5cb5f)) + +## [1.392.0](https://github.com/windmill-labs/windmill/compare/v1.391.0...v1.392.0) (2024-09-06) + + +### Features + +* add load more to runs page if nb of jobs >= 1000 ([e30c344](https://github.com/windmill-labs/windmill/commit/e30c344d329e6dcfa6a560eabae00dd31e774e04)) +* schedule success handler ([#4346](https://github.com/windmill-labs/windmill/issues/4346)) ([dbd4292](https://github.com/windmill-labs/windmill/commit/dbd429226051c74acaf61807ffb13ee1c61e46b1)) + + +### Bug Fixes + +* fix error handler new script if no modules ([32f2d0f](https://github.com/windmill-labs/windmill/commit/32f2d0fc8011943524623917689ff0921ee6d906)) +* improve app reports puppeteer interactions ([df72026](https://github.com/windmill-labs/windmill/commit/df720260b8ebb2b9ccf16dd2ad89d2a13a112c60)) +* increase AI gen timeout + upgrade to 16k gpt4o ([#4340](https://github.com/windmill-labs/windmill/issues/4340)) ([067110e](https://github.com/windmill-labs/windmill/commit/067110e62f1b064268b2c2de07b7832874ace509)) +* make select not reset on user changes in app + app css fix ([8bea2e4](https://github.com/windmill-labs/windmill/commit/8bea2e473df9e59aa0b244f09bee0a84a432cb3d)) +* nativets correct transform resources in args ([50f32c4](https://github.com/windmill-labs/windmill/commit/50f32c4e12b0ece808b810bb7c67255d467a0ab2)) + +## [1.391.0](https://github.com/windmill-labs/windmill/compare/v1.390.1...v1.391.0) (2024-09-04) + + +### Features + +* add slack as a critical alert channel ([#4319](https://github.com/windmill-labs/windmill/issues/4319)) ([a7a08cf](https://github.com/windmill-labs/windmill/commit/a7a08cf9f3b40f6d90d1a1f72ad5ab6e6212b6b9)) + + +### Bug Fixes + +* improve wm_labels indices + UX nits ([ce70693](https://github.com/windmill-labs/windmill/commit/ce7069375481652f88e0417828a0a17a8f429957)) + +## [1.390.1](https://github.com/windmill-labs/windmill/compare/v1.390.0...v1.390.1) (2024-09-03) + + +### Bug Fixes + +* do not require hasNullParent only if scriptPathExact on runs search ([d172e45](https://github.com/windmill-labs/windmill/commit/d172e45766220c525e91f933f22a32738fa2709e)) +* prevent brute force attacks on tokens by slowing unauthorized response ([acfe778](https://github.com/windmill-labs/windmill/commit/acfe7786152f036f2476f93ab5536571514fa9e3)) + +## [1.390.0](https://github.com/windmill-labs/windmill/compare/v1.389.1...v1.390.0) (2024-09-02) + + +### Features + +* add yaml editor in flow builder ([71470d7](https://github.com/windmill-labs/windmill/commit/71470d7da9d3c7a52d7c5a206849f2e63ac4fa02)) + + +### Bug Fixes + +* improve dependency map to handle recusrive loops + handle better flow relative imports ([cdd7349](https://github.com/windmill-labs/windmill/commit/cdd7349f6769a0195f367a1ac27f802287a1f900)) + +## [1.389.1](https://github.com/windmill-labs/windmill/compare/v1.389.0...v1.389.1) (2024-09-02) + + +### Bug Fixes + +* fix erronous branchone status in flow viewer ([e311684](https://github.com/windmill-labs/windmill/commit/e311684a668c461538a3456c02c82a1ea6fecbc9)) +* +## [1.389.0](https://github.com/windmill-labs/windmill/compare/v1.388.0...v1.389.0) (2024-09-01) + + +### Features + +* service logs ([#4244](https://github.com/windmill-labs/windmill/issues/4244)) ([2fe48df](https://github.com/windmill-labs/windmill/commit/2fe48df720b102255832dc6438d5d64f3443207a)) + + +### Bug Fixes + +* prevent duplicate worker alerts ([#4309](https://github.com/windmill-labs/windmill/issues/4309)) ([8e30928](https://github.com/windmill-labs/windmill/commit/8e30928a78c20daef81bc4f98487ab601ecc9b58)) + +## [1.388.0](https://github.com/windmill-labs/windmill/compare/v1.387.1...v1.388.0) (2024-08-30) + + +### Features + +* add rust ([#4253](https://github.com/windmill-labs/windmill/issues/4253)) ([a2beed9](https://github.com/windmill-labs/windmill/commit/a2beed9d7335856bc956ff34343cdaf5a9b8d281)) +* min workers in worker group alert + zombie job critical alert ([#4307](https://github.com/windmill-labs/windmill/issues/4307)) ([aa6fd84](https://github.com/windmill-labs/windmill/commit/aa6fd84079b6015d82d7603218b2c8cb7a156c40)) + +## [1.387.1](https://github.com/windmill-labs/windmill/compare/v1.387.0...v1.387.1) (2024-08-30) + + +### Bug Fixes + +* fix resource list in args being pre-pended with $res ([2397588](https://github.com/windmill-labs/windmill/commit/239758835503ead5bbb1830c04b4fea5d13ad425)) +* improve history navigation on the runs page ([487e7ca](https://github.com/windmill-labs/windmill/commit/487e7ca715d37b4b59a3a03ba8ff2bb644118635)) + +## [1.387.0](https://github.com/windmill-labs/windmill/compare/v1.386.0...v1.387.0) (2024-08-29) + + +### Features + +* **frontend:** add a favorite button on detail pages ([#4297](https://github.com/windmill-labs/windmill/issues/4297)) ([8148518](https://github.com/windmill-labs/windmill/commit/8148518c5c7780d7999b884b0a9e0e540ece09fd)) +* **frontend:** add indicator when a component is locked ([#4296](https://github.com/windmill-labs/windmill/issues/4296)) ([d9b358b](https://github.com/windmill-labs/windmill/commit/d9b358bcc20d2603ef94ada765d395e370d58fc7)) + +## [1.386.0](https://github.com/windmill-labs/windmill/compare/v1.385.0...v1.386.0) (2024-08-28) + + +### Features + +* add vim support for monaco/webeditor ([1ec45e5](https://github.com/windmill-labs/windmill/commit/1ec45e5ad6436d36d3951a75663b4f310025d765)) +* **frontend:** add support to copy a cell value in the clipboard in aggrid tables ([#4286](https://github.com/windmill-labs/windmill/issues/4286)) ([d1ba9b1](https://github.com/windmill-labs/windmill/commit/d1ba9b14040f9c21612a46b36379cce95448fba6)) +* **frontend:** manage ag grid actions programmatically ([#4289](https://github.com/windmill-labs/windmill/issues/4289)) ([a411179](https://github.com/windmill-labs/windmill/commit/a4111798d54f5aa1539dd917eb59ec825c9a4a0b)) +* show last job instead of current job on workers page ([#4293](https://github.com/windmill-labs/windmill/issues/4293)) ([84ce3d8](https://github.com/windmill-labs/windmill/commit/84ce3d819d19254e89c0da9ddf0b9f3819fe6025)) + + +### Bug Fixes + +* cache hub scripts in more cases + pre-cache hub scripts deps in deno ([16465e4](https://github.com/windmill-labs/windmill/commit/16465e47c8acf6320694a821b375aa20ee51067c)) +* items with starred info ([#4298](https://github.com/windmill-labs/windmill/issues/4298)) ([e16bd4a](https://github.com/windmill-labs/windmill/commit/e16bd4a9d25d945b13696f8f7d9e39b10acdb444)) +* show vCPU, mem aggregate on top of worker group ([e083177](https://github.com/windmill-labs/windmill/commit/e0831777a1a8798ba4234f299035c6f471078553)) +* smtp server build without parquet feature ([#4292](https://github.com/windmill-labs/windmill/issues/4292)) ([906cf10](https://github.com/windmill-labs/windmill/commit/906cf1006e5447be075694d7d4903cea04b85737)) + +## [1.385.0](https://github.com/windmill-labs/windmill/compare/v1.384.0...v1.385.0) (2024-08-26) + + +### Features + +* s3 image preview ([#4262](https://github.com/windmill-labs/windmill/issues/4262)) ([35d665f](https://github.com/windmill-labs/windmill/commit/35d665f6179e0a52dd30512e378f270c44703f48)) + + +### Bug Fixes + +* **frontend:** fix inserting Ws scripts from the search menu ([#4290](https://github.com/windmill-labs/windmill/issues/4290)) ([4efc40f](https://github.com/windmill-labs/windmill/commit/4efc40fbb0214fba65f6ff95782e6ead3b20bc71)) + +## [1.384.0](https://github.com/windmill-labs/windmill/compare/v1.383.1...v1.384.0) (2024-08-26) + + +### Features + +* **frontend:** Add a toggle to disable breakpoints in the App editor ([#4274](https://github.com/windmill-labs/windmill/issues/4274)) ([5b2dd75](https://github.com/windmill-labs/windmill/commit/5b2dd7573d7ac2bd1b4ff06094a2dfd480ed24a4)) +* **frontend:** hide/show app editor panels ([#4266](https://github.com/windmill-labs/windmill/issues/4266)) ([fdfd385](https://github.com/windmill-labs/windmill/commit/fdfd385a68c8e05eff147a9471a9f3f44f39e13e)) +* put email triggers attachments on s3 ([#4272](https://github.com/windmill-labs/windmill/issues/4272)) ([5bd38f7](https://github.com/windmill-labs/windmill/commit/5bd38f78089a4beb4a28ba32bc99e649f8119a4c)) + + +### Bug Fixes + +* bun 1.1.21->1.1.25 ([7fa648f](https://github.com/windmill-labs/windmill/commit/7fa648f0876f5b5509fed39b314f40f08528b123)) +* **lsp:** use ruff server instead of ruff-lsp ([88648af](https://github.com/windmill-labs/windmill/commit/88648af1cd6f9e4436e2fd3100f3ece764da75f1)) +* update monaco-editor to latest monaco/language-client ([#4285](https://github.com/windmill-labs/windmill/issues/4285)) ([32c0b89](https://github.com/windmill-labs/windmill/commit/32c0b89729d98a25a5937af1ee41e8ea36334509)) + +## [1.383.1](https://github.com/windmill-labs/windmill/compare/v1.383.0...v1.383.1) (2024-08-22) + + +### Bug Fixes + +* fix app navbar query reactivity + hash in ctx handling is more consistent ([7882d4e](https://github.com/windmill-labs/windmill/commit/7882d4ecdd1007e73a51d2a408cf2e6dc1f83213)) + +## [1.383.0](https://github.com/windmill-labs/windmill/compare/v1.382.2...v1.383.0) (2024-08-22) + + +### Features + +* add native html select support + fix mobile scroll on app text component ([d604b6f](https://github.com/windmill-labs/windmill/commit/d604b6f2a0e5755c949f302c0490de47a8d662ca)) +* add wrap_body header to webhooks ([9226d6c](https://github.com/windmill-labs/windmill/commit/9226d6cbc119f6a1b16936ebb855ff4f50c0e122)) +* improve early stop ([#4257](https://github.com/windmill-labs/windmill/issues/4257)) ([bcde2e6](https://github.com/windmill-labs/windmill/commit/bcde2e62d7846822cfe7f8ef89a9484938829903)) + + +### Bug Fixes + +* **frontend:** fix large JSON viewer ([#4273](https://github.com/windmill-labs/windmill/issues/4273)) ([b3eabff](https://github.com/windmill-labs/windmill/commit/b3eabffb76e266269b2f5ff471a053fa065da4d0)) +* **python-client:** only require httpx to be >= 0.24 instead of ^0.24 ([fc12aeb](https://github.com/windmill-labs/windmill/commit/fc12aeb3961b8a1a42a8493e3774815c940b75af)) + +## [1.382.2](https://github.com/windmill-labs/windmill/compare/v1.382.1...v1.382.2) (2024-08-20) + + +### Bug Fixes + +* **app:** database studio/empty table count reset ([d6d3389](https://github.com/windmill-labs/windmill/commit/d6d33898a765f910f66cd0cfbd70a439ab107528)) +* **frontend:** Fix initial FlowGraph rendering on Chrome ([#4268](https://github.com/windmill-labs/windmill/issues/4268)) ([84d4e2c](https://github.com/windmill-labs/windmill/commit/84d4e2cb956ab4947b364d64c464fd5cf3c1d16f)) +* handle more gracefully worker without tags ([7e1f280](https://github.com/windmill-labs/windmill/commit/7e1f28071a7d6f3f34df417ea746fc9b5dca5157)) + +## [1.382.1](https://github.com/windmill-labs/windmill/compare/v1.382.0...v1.382.1) (2024-08-20) + + +### Bug Fixes + +* **frontend:** Fix flow graph step preview ([#4264](https://github.com/windmill-labs/windmill/issues/4264)) ([0a6832a](https://github.com/windmill-labs/windmill/commit/0a6832aa4561468fb0150f9eb435b7ad857fc841)) + +## [1.382.0](https://github.com/windmill-labs/windmill/compare/v1.381.0...v1.382.0) (2024-08-20) + + +### Features + +* **frontend:** improve versions history by adding a diff viewer with… ([#4261](https://github.com/windmill-labs/windmill/issues/4261)) ([c19df12](https://github.com/windmill-labs/windmill/commit/c19df12292241c20c12e3de5d880c04df9b74324)) + + +### Bug Fixes + +* add FORCE_WORKER_TAGS & fix workers page when default worker group is missing ([09c6af0](https://github.com/windmill-labs/windmill/commit/09c6af05cd6e0b3b30f771a125b1fa330a938101)) +* **bun:** disable large transpiling cache ([1a0e32b](https://github.com/windmill-labs/windmill/commit/1a0e32b40b5f1ac5dcfe3639e697affb6e79a558)) +* **cli:** improve error message of cli ([f3bcadb](https://github.com/windmill-labs/windmill/commit/f3bcadbfb1e42b56996e273800aa0dcb01a6868b)) +* frontend/package.json & frontend/package-lock.json to reduce vulnerabilities ([#4255](https://github.com/windmill-labs/windmill/issues/4255)) ([7fe0442](https://github.com/windmill-labs/windmill/commit/7fe0442a814ed42b1775386be5f4defdcb5c0a0f)) +* **frontend:** nit worker limits ([#4258](https://github.com/windmill-labs/windmill/issues/4258)) ([bb92824](https://github.com/windmill-labs/windmill/commit/bb9282427399f305c3e8874204e6478272c43ff8)) +* improve resource picker handling of objects ([2502377](https://github.com/windmill-labs/windmill/commit/250237793b3c2b1afd5ee122b147301bc487eeeb)) +* **typescript-client:** runFlowAsync by default assume job doesn't outlive flow ([010e0fd](https://github.com/windmill-labs/windmill/commit/010e0fdc2352d740a72de124cc26eea8fc1915af)) + ## [1.381.0](https://github.com/windmill-labs/windmill/compare/v1.380.0...v1.381.0) (2024-08-16) diff --git a/Dockerfile b/Dockerfile index c0f15162de..8683aa9738 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ARG DEBIAN_IMAGE=debian:bookworm-slim -ARG RUST_IMAGE=rust:1.79-slim-bookworm -ARG PYTHON_IMAGE=python:3.11.8-slim-bookworm +ARG RUST_IMAGE=rust:1.80-slim-bookworm +ARG PYTHON_IMAGE=python:3.11.10-slim-bookworm FROM ${RUST_IMAGE} AS rust_base @@ -70,7 +70,9 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \ COPY ./openflow.openapi.yaml /openflow.openapi.yaml COPY ./backend ./ -COPY --from=frontend /frontend /frontend +RUN mkdir -p /frontend + +COPY --from=frontend /frontend/build /frontend/build COPY --from=frontend /backend/windmill-api/openapi-deref.yaml ./windmill-api/openapi-deref.yaml COPY .git/ .git/ @@ -86,17 +88,26 @@ ARG POWERSHELL_VERSION=7.3.5 ARG POWERSHELL_DEB_VERSION=7.3.5-1 ARG KUBECTL_VERSION=1.28.7 ARG HELM_VERSION=3.14.3 +ARG GO_VERSION=1.22.5 ARG APP=/usr/src/app ARG WITH_POWERSHELL=true ARG WITH_KUBECTL=true ARG WITH_HELM=true +ARG WITH_GIT=true +RUN pip install --upgrade pip==24.2 RUN apt-get update \ - && apt-get install -y ca-certificates wget curl git jq unzip build-essential unixodbc xmlsec1 software-properties-common \ + && apt-get install -y ca-certificates wget curl jq unzip build-essential unixodbc xmlsec1 software-properties-common \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +RUN if [ "$WITH_GIT" = "true" ]; then \ + apt-get update -y \ + && apt-get install -y git \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/*; \ + else echo 'Building the image without git'; fi; RUN if [ "$WITH_POWERSHELL" = "true" ]; then \ if [ "$TARGETPLATFORM" = "linux/amd64" ]; then apt-get update -y && apt install libicu-dev -y && wget -O 'pwsh.deb' "https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/powershell_${POWERSHELL_DEB_VERSION}.deb_amd64.deb" && apt-get clean \ @@ -131,14 +142,14 @@ RUN if [ "$WITH_KUBECTL" = "true" ]; then \ RUN set -eux; \ arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \ case "$arch" in \ - 'amd64') \ - targz='go1.22.5.linux-amd64.tar.gz'; \ + "amd64") \ + targz="go${GO_VERSION}.linux-amd64.tar.gz"; \ ;; \ - 'arm64') \ - targz='go1.22.5.linux-arm64.tar.gz'; \ + "arm64") \ + targz="go${GO_VERSION}.linux-arm64.tar.gz"; \ ;; \ - 'armhf') \ - targz='go1.22.5.linux-armv6l.tar.gz'; \ + "armhf") \ + targz="go${GO_VERSION}.linux-armv6l.tar.gz"; \ ;; \ *) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \ esac; \ @@ -147,9 +158,12 @@ RUN set -eux; \ ENV PATH="${PATH}:/usr/local/go/bin" ENV GO_PATH=/usr/local/go/bin/go +# Install UV +RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.4.18/uv-installer.sh | sh && mv /root/.cargo/bin/uv /usr/local/bin/uv + RUN curl -sL https://deb.nodesource.com/setup_20.x | bash - -RUN apt-get -y update && apt-get install -y curl nodejs awscli && apt-get clean \ - && rm -rf /var/lib/apt/lists/* +RUN apt-get -y update && apt-get install -y curl procps nodejs awscli && apt-get clean \ + && rm -rf /var/lib/apt/lists/* # go build is slower the first time it is ran, so we prewarm it in the build RUN mkdir -p /tmp/gobuildwarm && cd /tmp/gobuildwarm && go mod init gobuildwarm && printf "package foo\nimport (\"fmt\")\nfunc main() { fmt.Println(42) }" > warm.go && go mod tidy && go build -x && rm -rf /tmp/gobuildwarm @@ -161,9 +175,9 @@ RUN /usr/local/bin/python3 -m pip install pip-tools COPY --from=builder /frontend/build /static_frontend COPY --from=builder /windmill/target/release/windmill ${APP}/windmill -COPY --from=denoland/deno:1.45.4 --chmod=755 /usr/bin/deno /usr/bin/deno +COPY --from=denoland/deno:2.0.2 --chmod=755 /usr/bin/deno /usr/bin/deno -COPY --from=oven/bun:1.1.21 /usr/local/bin/bun /usr/bin/bun +COPY --from=oven/bun:1.1.32 /usr/local/bin/bun /usr/bin/bun COPY --from=php:8.3.7-cli /usr/local/bin/php /usr/bin/php COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer @@ -171,15 +185,16 @@ COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer # add the docker client to call docker from a worker if enabled COPY --from=docker:dind /usr/local/bin/docker /usr/local/bin/ +ENV RUSTUP_HOME="/usr/local/rustup" +ENV CARGO_HOME="/usr/local/cargo" + WORKDIR ${APP} RUN ln -s ${APP}/windmill /usr/local/bin/windmill COPY ./frontend/src/lib/hubPaths.json ${APP}/hubPaths.json -RUN windmill cache ${APP}/hubPaths.json - -RUN rm ${APP}/hubPaths.json +RUN windmill cache ${APP}/hubPaths.json && rm ${APP}/hubPaths.json && chmod -R 777 /tmp/windmill EXPOSE 8000 diff --git a/README.md b/README.md index b5a14eda55..eb6c64ee2a 100644 --- a/README.md +++ b/README.md @@ -352,14 +352,25 @@ you to have it being synced automatically everyday. | DISABLE_RESPONSE_LOGS | false | Disable response logs | Server | ## Run a local dev setup +See the [./frontend/README_DEV.md](./frontend/README_DEV.md) file for all +running options. + ### only Frontend This will use the backend of but your own frontend -with hot-code reloading. -1. Install [caddy](https://caddyserver.com) -2. Go to `frontend/`: - 1. `npm install`, `npm run generate-backend-client` then `npm run dev` - 2. In another shell `sudo caddy run --config CaddyfileRemote` -3. Et voilà, windmill should be available at `http://localhost/` +with hot-code reloading. Note that you will need to use a username / password login due to CSRF checks using a different auth provider. + +In the `frontend/` directory: + +1. install the dependencies with `npm install` (or `pnpm install` or `yarn`) +2. generate the windmill client: + ``` + npm run generate-backend-client + ## on mac use + npm run generate-backend-client-mac + ``` +3. Run your dev server with `npm run dev` +4. Et voilà, windmill should be available at `http://localhost/` + ### Backend + Frontend See the [./frontend/README_DEV.md](./frontend/README_DEV.md) file for all running options. diff --git a/backend/.sqlx/query-00ce4ed3ca0eac7cb6283b047353a64b9e78c4beb423f04baef9a53fbf87e9f9.json b/backend/.sqlx/query-00ce4ed3ca0eac7cb6283b047353a64b9e78c4beb423f04baef9a53fbf87e9f9.json new file mode 100644 index 0000000000..e4909fc4da --- /dev/null +++ b/backend/.sqlx/query-00ce4ed3ca0eac7cb6283b047353a64b9e78c4beb423f04baef9a53fbf87e9f9.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO alerts (alert_type, message) VALUES ('recovered_critical_error', $1)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [] + }, + "hash": "00ce4ed3ca0eac7cb6283b047353a64b9e78c4beb423f04baef9a53fbf87e9f9" +} diff --git a/backend/.sqlx/query-02424907504848e983bfa89eec343061932dc5b4b17cf13d5cf8d833aedbe6d5.json b/backend/.sqlx/query-02424907504848e983bfa89eec343061932dc5b4b17cf13d5cf8d833aedbe6d5.json new file mode 100644 index 0000000000..c8b5e3086f --- /dev/null +++ b/backend/.sqlx/query-02424907504848e983bfa89eec343061932dc5b4b17cf13d5cf8d833aedbe6d5.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE websocket_trigger SET server_id = $1, last_server_ping = now() WHERE enabled IS TRUE AND workspace_id = $2 AND path = $3 AND (server_id IS NULL OR last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') RETURNING true", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "02424907504848e983bfa89eec343061932dc5b4b17cf13d5cf8d833aedbe6d5" +} diff --git a/backend/.sqlx/query-02b516dac764662194db1bc33e365c01f40bae70af3683f1f09748f6020f0d49.json b/backend/.sqlx/query-02b516dac764662194db1bc33e365c01f40bae70af3683f1f09748f6020f0d49.json deleted file mode 100644 index 99f3606bcd..0000000000 --- a/backend/.sqlx/query-02b516dac764662194db1bc33e365c01f40bae70af3683f1f09748f6020f0d49.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT tag, count(*) as count FROM queue WHERE\n scheduled_for <= now() - ('3 seconds')::interval AND running = false\n GROUP BY tag", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "tag", - "type_info": "Varchar" - }, - { - "ordinal": 1, - "name": "count", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - false, - null - ] - }, - "hash": "02b516dac764662194db1bc33e365c01f40bae70af3683f1f09748f6020f0d49" -} diff --git a/backend/.sqlx/query-02f1a6eeb27067dc438459238e7b016f5ccf9e3fe0ffbe88471f15aad8f74441.json b/backend/.sqlx/query-02f1a6eeb27067dc438459238e7b016f5ccf9e3fe0ffbe88471f15aad8f74441.json new file mode 100644 index 0000000000..a27bc6365a --- /dev/null +++ b/backend/.sqlx/query-02f1a6eeb27067dc438459238e7b016f5ccf9e3fe0ffbe88471f15aad8f74441.json @@ -0,0 +1,89 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, http_method as \"http_method: _\" FROM http_trigger WHERE workspace_id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 3, + "name": "route_path", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "is_async", + "type_info": "Bool" + }, + { + "ordinal": 6, + "name": "requires_auth", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 9, + "name": "http_method: _", + "type_info": { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + } + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "02f1a6eeb27067dc438459238e7b016f5ccf9e3fe0ffbe88471f15aad8f74441" +} diff --git a/backend/.sqlx/query-03d63d2e64b012f624d2731b5bcb8849c74a9474777be61edf0ed43ddda07ef3.json b/backend/.sqlx/query-03d63d2e64b012f624d2731b5bcb8849c74a9474777be61edf0ed43ddda07ef3.json index c501c6f1f8..39374fabd8 100644 --- a/backend/.sqlx/query-03d63d2e64b012f624d2731b5bcb8849c74a9474777be61edf0ed43ddda07ef3.json +++ b/backend/.sqlx/query-03d63d2e64b012f624d2731b5bcb8849c74a9474777be61edf0ed43ddda07ef3.json @@ -32,6 +32,11 @@ "ordinal": 5, "name": "created_by", "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "format_extension", + "type_info": "Varchar" } ], "parameters": { @@ -46,6 +51,7 @@ true, true, true, + true, true ] }, diff --git a/backend/.sqlx/query-050fb876e10ad13654dbbde4532f408ff1ac92ed0f5d31a3ef6c58313e1f8671.json b/backend/.sqlx/query-050fb876e10ad13654dbbde4532f408ff1ac92ed0f5d31a3ef6c58313e1f8671.json new file mode 100644 index 0000000000..9b50ef2c69 --- /dev/null +++ b/backend/.sqlx/query-050fb876e10ad13654dbbde4532f408ff1ac92ed0f5d31a3ef6c58313e1f8671.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT healthy, created_at FROM healthchecks WHERE check_type = 'min_alive_workers_' || $1 ORDER BY created_at DESC LIMIT 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "healthy", + "type_info": "Bool" + }, + { + "ordinal": 1, + "name": "created_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "050fb876e10ad13654dbbde4532f408ff1ac92ed0f5d31a3ef6c58313e1f8671" +} diff --git a/backend/.sqlx/query-051acd49542618e3be5654dce94567a02e87be23a4c0863e3b2d53b5c2cb6749.json b/backend/.sqlx/query-051acd49542618e3be5654dce94567a02e87be23a4c0863e3b2d53b5c2cb6749.json new file mode 100644 index 0000000000..c7c7260ed4 --- /dev/null +++ b/backend/.sqlx/query-051acd49542618e3be5654dce94567a02e87be23a4c0863e3b2d53b5c2cb6749.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE schedule SET on_success = NULL, on_success_extra_args = NULL WHERE workspace_id = $1 RETURNING path", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "051acd49542618e3be5654dce94567a02e87be23a4c0863e3b2d53b5c2cb6749" +} diff --git a/backend/.sqlx/query-0a686ca61444d7ad7484071727aa039a6ea6697e5a49a633b767c052aa3e0a18.json b/backend/.sqlx/query-0a686ca61444d7ad7484071727aa039a6ea6697e5a49a633b767c052aa3e0a18.json index 580e8bfd01..a4c8e3ea0c 100644 --- a/backend/.sqlx/query-0a686ca61444d7ad7484071727aa039a6ea6697e5a49a633b767c052aa3e0a18.json +++ b/backend/.sqlx/query-0a686ca61444d7ad7484071727aa039a6ea6697e5a49a633b767c052aa3e0a18.json @@ -56,7 +56,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-0aa47e68f9e21115d96a8a1117e95f800c8bfb9bd6872a657c7e7131a21563c8.json b/backend/.sqlx/query-0aa47e68f9e21115d96a8a1117e95f800c8bfb9bd6872a657c7e7131a21563c8.json new file mode 100644 index 0000000000..fe02b79503 --- /dev/null +++ b/backend/.sqlx/query-0aa47e68f9e21115d96a8a1117e95f800c8bfb9bd6872a657c7e7131a21563c8.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT 1 FROM password WHERE email = 'admin@windmill.dev' AND password_hash = '$argon2id$v=19$m=4096,t=3,p=1$oLJo/lPn/gezXCuFOEyaNw$i0T2tCkw3xUFsrBIKZwr8jVNHlIfoxQe+HfDnLtd12I'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "0aa47e68f9e21115d96a8a1117e95f800c8bfb9bd6872a657c7e7131a21563c8" +} diff --git a/backend/.sqlx/query-620ddf29c5e867079df4c2aa6e80bccb19beeb9ddfa308ca97f254cd5ba8157e.json b/backend/.sqlx/query-0ad36c1598ff4ece0c325eaeb9a9177a87e1accd192402e21db5ae09c3498ab0.json similarity index 83% rename from backend/.sqlx/query-620ddf29c5e867079df4c2aa6e80bccb19beeb9ddfa308ca97f254cd5ba8157e.json rename to backend/.sqlx/query-0ad36c1598ff4ece0c325eaeb9a9177a87e1accd192402e21db5ae09c3498ab0.json index 790543d970..fc94db0309 100644 --- a/backend/.sqlx/query-620ddf29c5e867079df4c2aa6e80bccb19beeb9ddfa308ca97f254cd5ba8157e.json +++ b/backend/.sqlx/query-0ad36c1598ff4ece0c325eaeb9a9177a87e1accd192402e21db5ae09c3498ab0.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO queue\n (workspace_id, id, running, parent_job, created_by, permissioned_as, scheduled_for, \n script_hash, script_path, raw_code, raw_lock, args, job_kind, schedule_path, raw_flow, flow_status, is_flow_step, language, started_at, same_worker, pre_run_error, email, visible_to_owner, root_job, tag, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id, cache_ttl, priority)\n VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, now()), $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, CASE WHEN $3 THEN now() END, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30) RETURNING id", + "query": "INSERT INTO queue\n (workspace_id, id, running, parent_job, created_by, permissioned_as, scheduled_for, \n script_hash, script_path, raw_code, raw_lock, args, job_kind, schedule_path, raw_flow, flow_status, is_flow_step, language, started_at, same_worker, pre_run_error, email, visible_to_owner, root_job, tag, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id, cache_ttl, priority, last_ping)\n VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, now()), $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, CASE WHEN $3 THEN now() END, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, NULL) RETURNING id", "describe": { "columns": [ { @@ -70,7 +70,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } @@ -93,5 +95,5 @@ false ] }, - "hash": "620ddf29c5e867079df4c2aa6e80bccb19beeb9ddfa308ca97f254cd5ba8157e" + "hash": "0ad36c1598ff4ece0c325eaeb9a9177a87e1accd192402e21db5ae09c3498ab0" } diff --git a/backend/.sqlx/query-0aff8b0f2cddc0dd696759f48368c7315ff39060be5430c59582e1e05a4b3d90.json b/backend/.sqlx/query-0aff8b0f2cddc0dd696759f48368c7315ff39060be5430c59582e1e05a4b3d90.json deleted file mode 100644 index 4f6b896ad4..0000000000 --- a/backend/.sqlx/query-0aff8b0f2cddc0dd696759f48368c7315ff39060be5430c59582e1e05a4b3d90.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE queue\n SET flow_status = JSONB_SET(\n JSONB_SET(flow_status, ARRAY['failure_module'], $1), ARRAY['step'], $2)\n WHERE id = $3", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Jsonb", - "Jsonb", - "Uuid" - ] - }, - "nullable": [] - }, - "hash": "0aff8b0f2cddc0dd696759f48368c7315ff39060be5430c59582e1e05a4b3d90" -} diff --git a/backend/.sqlx/query-0c2e53960dc7786c848079b155e62994d4a861f1dbb9752c0a27428d83040e13.json b/backend/.sqlx/query-0c2e53960dc7786c848079b155e62994d4a861f1dbb9752c0a27428d83040e13.json new file mode 100644 index 0000000000..5c33539878 --- /dev/null +++ b/backend/.sqlx/query-0c2e53960dc7786c848079b155e62994d4a861f1dbb9752c0a27428d83040e13.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT value, is_secret FROM variable WHERE path = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "is_secret", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "0c2e53960dc7786c848079b155e62994d4a861f1dbb9752c0a27428d83040e13" +} diff --git a/backend/.sqlx/query-0e52a588f3edeb8fb58d6d62247b8590e51171e2811c62737bdb81fb0ac8f182.json b/backend/.sqlx/query-0e52a588f3edeb8fb58d6d62247b8590e51171e2811c62737bdb81fb0ac8f182.json new file mode 100644 index 0000000000..f23cf3f710 --- /dev/null +++ b/backend/.sqlx/query-0e52a588f3edeb8fb58d6d62247b8590e51171e2811c62737bdb81fb0ac8f182.json @@ -0,0 +1,15 @@ +{ + "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-0ee63ef2dd5c88edba2a1f56d31f29876724922f148dad7af35b36efbf70207a.json b/backend/.sqlx/query-0ee63ef2dd5c88edba2a1f56d31f29876724922f148dad7af35b36efbf70207a.json new file mode 100644 index 0000000000..5cb52b6ead --- /dev/null +++ b/backend/.sqlx/query-0ee63ef2dd5c88edba2a1f56d31f29876724922f148dad7af35b36efbf70207a.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM healthchecks WHERE check_type = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [] + }, + "hash": "0ee63ef2dd5c88edba2a1f56d31f29876724922f148dad7af35b36efbf70207a" +} diff --git a/backend/.sqlx/query-12a86755706ce030a0a9142da78d035d0c7d361240b60005cc864e4345eb0bc7.json b/backend/.sqlx/query-12a86755706ce030a0a9142da78d035d0c7d361240b60005cc864e4345eb0bc7.json new file mode 100644 index 0000000000..dc357c2169 --- /dev/null +++ b/backend/.sqlx/query-12a86755706ce030a0a9142da78d035d0c7d361240b60005cc864e4345eb0bc7.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE websocket_trigger SET enabled = $1, email = $2, edited_by = $3, edited_at = now(), server_id = NULL, last_server_ping = NULL, error = NULL\n WHERE path = $4 AND workspace_id = $5 RETURNING 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Bool", + "Varchar", + "Varchar", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "12a86755706ce030a0a9142da78d035d0c7d361240b60005cc864e4345eb0bc7" +} diff --git a/backend/.sqlx/query-14abf759dae7ba5c38017ba6001927c6df0653a02b87bcea939066e39ebcf24d.json b/backend/.sqlx/query-14abf759dae7ba5c38017ba6001927c6df0653a02b87bcea939066e39ebcf24d.json new file mode 100644 index 0000000000..29aaf47e88 --- /dev/null +++ b/backend/.sqlx/query-14abf759dae7ba5c38017ba6001927c6df0653a02b87bcea939066e39ebcf24d.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO concurrency_locks (id, last_locked_at, owner)\n VALUES ($1, now(), $2)\n ON CONFLICT (id)\n DO UPDATE SET\n last_locked_at = now(),\n owner = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "14abf759dae7ba5c38017ba6001927c6df0653a02b87bcea939066e39ebcf24d" +} diff --git a/backend/.sqlx/query-16c4fb122ceb30722f54c92db97427b0ddd36f495d549f8cd23d659d2c866a63.json b/backend/.sqlx/query-16c4fb122ceb30722f54c92db97427b0ddd36f495d549f8cd23d659d2c866a63.json new file mode 100644 index 0000000000..00361e6e95 --- /dev/null +++ b/backend/.sqlx/query-16c4fb122ceb30722f54c92db97427b0ddd36f495d549f8cd23d659d2c866a63.json @@ -0,0 +1,36 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE route_path_key = $1 AND http_method = $2)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + } + ] + }, + "nullable": [ + null + ] + }, + "hash": "16c4fb122ceb30722f54c92db97427b0ddd36f495d549f8cd23d659d2c866a63" +} diff --git a/backend/.sqlx/query-17e3e2a3232865c33fa535b5d99455942e30f932c5b97f1e5b508128f39a288f.json b/backend/.sqlx/query-17e3e2a3232865c33fa535b5d99455942e30f932c5b97f1e5b508128f39a288f.json new file mode 100644 index 0000000000..4000bbb962 --- /dev/null +++ b/backend/.sqlx/query-17e3e2a3232865c33fa535b5d99455942e30f932c5b97f1e5b508128f39a288f.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(\n JSONB_SET(flow_status, ARRAY['preprocessor_module'], $1), ARRAY['step'], $2)\n WHERE id = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb", + "Jsonb", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "17e3e2a3232865c33fa535b5d99455942e30f932c5b97f1e5b508128f39a288f" +} diff --git a/backend/.sqlx/query-8ca76fcadc659d7069b97930cdde2d5200f3cef9dedb83b76c8a6a433d2a4de3.json b/backend/.sqlx/query-19bc874a06658b549e13cfa080ac2133190ba448d6f7830c8f1f7c22e4d753b8.json similarity index 53% rename from backend/.sqlx/query-8ca76fcadc659d7069b97930cdde2d5200f3cef9dedb83b76c8a6a433d2a4de3.json rename to backend/.sqlx/query-19bc874a06658b549e13cfa080ac2133190ba448d6f7830c8f1f7c22e4d753b8.json index f05a1b36ac..1fadd917d4 100644 --- a/backend/.sqlx/query-8ca76fcadc659d7069b97930cdde2d5200f3cef9dedb83b76c8a6a433d2a4de3.json +++ b/backend/.sqlx/query-19bc874a06658b549e13cfa080ac2133190ba448d6f7830c8f1f7c22e4d753b8.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT config FROM config WHERE name = 'server'", + "query": "SELECT value FROM global_settings WHERE name = 'slack'", "describe": { "columns": [ { "ordinal": 0, - "name": "config", + "name": "value", "type_info": "Jsonb" } ], @@ -13,8 +13,8 @@ "Left": [] }, "nullable": [ - true + false ] }, - "hash": "8ca76fcadc659d7069b97930cdde2d5200f3cef9dedb83b76c8a6a433d2a4de3" + "hash": "19bc874a06658b549e13cfa080ac2133190ba448d6f7830c8f1f7c22e4d753b8" } diff --git a/backend/.sqlx/query-c2060e8cacef6c3b5ce51ed203a2dbafc18d66f2924d1fe518c6728997647db2.json b/backend/.sqlx/query-1a4d291c2f239f7b50c116594cebb031862e1a18ad9204e02a0194817db26d6a.json similarity index 75% rename from backend/.sqlx/query-c2060e8cacef6c3b5ce51ed203a2dbafc18d66f2924d1fe518c6728997647db2.json rename to backend/.sqlx/query-1a4d291c2f239f7b50c116594cebb031862e1a18ad9204e02a0194817db26d6a.json index 6a08bbeab3..b8c5b89128 100644 --- a/backend/.sqlx/query-c2060e8cacef6c3b5ce51ed203a2dbafc18d66f2924d1fe518c6728997647db2.json +++ b/backend/.sqlx/query-1a4d291c2f239f7b50c116594cebb031862e1a18ad9204e02a0194817db26d6a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT email, login_type::text, verified, super_admin, name, company, username from password ORDER BY super_admin DESC, email LIMIT $1 OFFSET $2", + "query": "SELECT email, login_type::text, verified, super_admin, name, company, username, NULL::bool as operator_only FROM password ORDER BY super_admin DESC, email LIMIT $1 OFFSET $2", "describe": { "columns": [ { @@ -37,6 +37,11 @@ "ordinal": 6, "name": "username", "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "operator_only", + "type_info": "Bool" } ], "parameters": { @@ -52,8 +57,9 @@ false, true, true, - true + true, + null ] }, - "hash": "c2060e8cacef6c3b5ce51ed203a2dbafc18d66f2924d1fe518c6728997647db2" + "hash": "1a4d291c2f239f7b50c116594cebb031862e1a18ad9204e02a0194817db26d6a" } diff --git a/backend/.sqlx/query-1a612eb0b64eddd2c5657ef73598c47886545796424f8612135b711e2b9ddb6c.json b/backend/.sqlx/query-1a612eb0b64eddd2c5657ef73598c47886545796424f8612135b711e2b9ddb6c.json index 9463b1e558..e74be644c7 100644 --- a/backend/.sqlx/query-1a612eb0b64eddd2c5657ef73598c47886545796424f8612135b711e2b9ddb6c.json +++ b/backend/.sqlx/query-1a612eb0b64eddd2c5657ef73598c47886545796424f8612135b711e2b9ddb6c.json @@ -50,7 +50,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-1ca5bc2d35c0498b587fd0618434def64233dc4f8fc3344d8d74be8e96ded659.json b/backend/.sqlx/query-1ca5bc2d35c0498b587fd0618434def64233dc4f8fc3344d8d74be8e96ded659.json new file mode 100644 index 0000000000..3a2e44bdba --- /dev/null +++ b/backend/.sqlx/query-1ca5bc2d35c0498b587fd0618434def64233dc4f8fc3344d8d74be8e96ded659.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM schedule WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "1ca5bc2d35c0498b587fd0618434def64233dc4f8fc3344d8d74be8e96ded659" +} diff --git a/backend/.sqlx/query-1e188d8e427cab25dbe18aa900260e26e644a9d939e74a8317c4a09335f110fe.json b/backend/.sqlx/query-1e188d8e427cab25dbe18aa900260e26e644a9d939e74a8317c4a09335f110fe.json new file mode 100644 index 0000000000..01fb19b1c2 --- /dev/null +++ b/backend/.sqlx/query-1e188d8e427cab25dbe18aa900260e26e644a9d939e74a8317c4a09335f110fe.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(\n JSONB_SET(flow_status, ARRAY['modules', $1::TEXT, 'flow_jobs_success', $3::TEXT], $4),\n ARRAY['modules', $1::TEXT, 'branchall', 'branch'], ((flow_status->'modules'->$1::int->'branchall'->>'branch')::int + 1)::text::jsonb),\n last_ping = NULL\n WHERE id = $2\n RETURNING (flow_status->'modules'->$1::int->'branchall'->>'branch')::int", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "int4", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4", + "Uuid", + "Text", + "Jsonb" + ] + }, + "nullable": [ + null + ] + }, + "hash": "1e188d8e427cab25dbe18aa900260e26e644a9d939e74a8317c4a09335f110fe" +} diff --git a/backend/.sqlx/query-1f5f0858909eb5bac63c4e3b1add95226bd94ca3facb92a620ffa59dacad6705.json b/backend/.sqlx/query-1f5f0858909eb5bac63c4e3b1add95226bd94ca3facb92a620ffa59dacad6705.json new file mode 100644 index 0000000000..0adff2fe2c --- /dev/null +++ b/backend/.sqlx/query-1f5f0858909eb5bac63c4e3b1add95226bd94ca3facb92a620ffa59dacad6705.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO autoscaling_event (worker_group, event_type, desired_workers, reason) VALUES ($1, $2, $3, $4)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + { + "Custom": { + "name": "autoscaling_event_type", + "kind": { + "Enum": [ + "full_scaleout", + "scalein", + "scaleout" + ] + } + } + }, + "Int4", + "Text" + ] + }, + "nullable": [] + }, + "hash": "1f5f0858909eb5bac63c4e3b1add95226bd94ca3facb92a620ffa59dacad6705" +} diff --git a/backend/.sqlx/query-2041526bc58872d71f91f7698144039bd67f8e37895befa94a15b7e4019e114b.json b/backend/.sqlx/query-2041526bc58872d71f91f7698144039bd67f8e37895befa94a15b7e4019e114b.json new file mode 100644 index 0000000000..cbe5ec7607 --- /dev/null +++ b/backend/.sqlx/query-2041526bc58872d71f91f7698144039bd67f8e37895befa94a15b7e4019e114b.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM healthchecks WHERE healthy = true AND created_at < NOW() - INTERVAL '14 days'", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "2041526bc58872d71f91f7698144039bd67f8e37895befa94a15b7e4019e114b" +} diff --git a/backend/.sqlx/query-20fcdcd2674a52ee9bd8d1de518d6bce075f20bcd5d2328f183d8a59331f6bb1.json b/backend/.sqlx/query-20fcdcd2674a52ee9bd8d1de518d6bce075f20bcd5d2328f183d8a59331f6bb1.json new file mode 100644 index 0000000000..824335990f --- /dev/null +++ b/backend/.sqlx/query-20fcdcd2674a52ee9bd8d1de518d6bce075f20bcd5d2328f183d8a59331f6bb1.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO resource\n (workspace_id, path, value, resource_type, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, now()) ON CONFLICT (workspace_id, path) DO UPDATE SET value = $3, edited_at = now()", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Jsonb", + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "20fcdcd2674a52ee9bd8d1de518d6bce075f20bcd5d2328f183d8a59331f6bb1" +} diff --git a/backend/.sqlx/query-2238aaed46031f71b17c1cabcef935a0d3b2ca6d057f446ed9b02d4386e2ddd9.json b/backend/.sqlx/query-2238aaed46031f71b17c1cabcef935a0d3b2ca6d057f446ed9b02d4386e2ddd9.json new file mode 100644 index 0000000000..aa32886ba8 --- /dev/null +++ b/backend/.sqlx/query-2238aaed46031f71b17c1cabcef935a0d3b2ca6d057f446ed9b02d4386e2ddd9.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM websocket_trigger WHERE path = $1 AND workspace_id = $2)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "2238aaed46031f71b17c1cabcef935a0d3b2ca6d057f446ed9b02d4386e2ddd9" +} diff --git a/backend/.sqlx/query-27920aaa55666ffc14a36a247f89ff7994ee40d3953b9f772d0e0ab999bccb7b.json b/backend/.sqlx/query-27920aaa55666ffc14a36a247f89ff7994ee40d3953b9f772d0e0ab999bccb7b.json new file mode 100644 index 0000000000..26a8ba2ee2 --- /dev/null +++ b/backend/.sqlx/query-27920aaa55666ffc14a36a247f89ff7994ee40d3953b9f772d0e0ab999bccb7b.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO healthchecks (check_type, healthy) VALUES ($1, false)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "27920aaa55666ffc14a36a247f89ff7994ee40d3953b9f772d0e0ab999bccb7b" +} diff --git a/backend/.sqlx/query-8813665f8adfcab0daefbac2cc6b50e427dfd1c12d12895451affd307dc59c37.json b/backend/.sqlx/query-2c14d3a88193f16ad3b8cd590749cb5537995f2499f6cb8f0f316fb62902d542.json similarity index 77% rename from backend/.sqlx/query-8813665f8adfcab0daefbac2cc6b50e427dfd1c12d12895451affd307dc59c37.json rename to backend/.sqlx/query-2c14d3a88193f16ad3b8cd590749cb5537995f2499f6cb8f0f316fb62902d542.json index ce8adcd5b7..93017f5aec 100644 --- a/backend/.sqlx/query-8813665f8adfcab0daefbac2cc6b50e427dfd1c12d12895451affd307dc59c37.json +++ b/backend/.sqlx/query-2c14d3a88193f16ad3b8cd590749cb5537995f2499f6cb8f0f316fb62902d542.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT email, login_type::TEXT, super_admin, verified, name, company, username FROM password WHERE email = $1", + "query": "SELECT email, login_type::TEXT, super_admin, verified, name, company, username, NULL::bool as operator_only FROM password WHERE email = $1", "describe": { "columns": [ { @@ -37,6 +37,11 @@ "ordinal": 6, "name": "username", "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "operator_only", + "type_info": "Bool" } ], "parameters": { @@ -51,8 +56,9 @@ false, true, true, - true + true, + null ] }, - "hash": "8813665f8adfcab0daefbac2cc6b50e427dfd1c12d12895451affd307dc59c37" + "hash": "2c14d3a88193f16ad3b8cd590749cb5537995f2499f6cb8f0f316fb62902d542" } diff --git a/backend/.sqlx/query-2e6165543e34216dfaedf6e10729f733cff812e62dea1c1bce8cefd3a3979b14.json b/backend/.sqlx/query-2e6165543e34216dfaedf6e10729f733cff812e62dea1c1bce8cefd3a3979b14.json new file mode 100644 index 0000000000..4a15e2d4fa --- /dev/null +++ b/backend/.sqlx/query-2e6165543e34216dfaedf6e10729f733cff812e62dea1c1bce8cefd3a3979b14.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM websocket_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "2e6165543e34216dfaedf6e10729f733cff812e62dea1c1bce8cefd3a3979b14" +} diff --git a/backend/.sqlx/query-2eec077cc9e27d7ccd160cbaac118c321c422705f79e69550bb60f377083bcef.json b/backend/.sqlx/query-2eec077cc9e27d7ccd160cbaac118c321c422705f79e69550bb60f377083bcef.json new file mode 100644 index 0000000000..f3eecb9006 --- /dev/null +++ b/backend/.sqlx/query-2eec077cc9e27d7ccd160cbaac118c321c422705f79e69550bb60f377083bcef.json @@ -0,0 +1,65 @@ +{ + "db_name": "PostgreSQL", + "query": "WITH active_users AS (SELECT distinct username as email FROM audit WHERE timestamp > NOW() - INTERVAL '1 month' AND (operation = 'users.login' OR operation = 'oauth.login')),\n authors as (SELECT distinct email FROM usr WHERE usr.operator IS false)\n SELECT email, email NOT IN (SELECT email FROM authors) as operator_only, login_type::text, verified, super_admin, name, company, username\n FROM password\n WHERE email IN (SELECT email FROM active_users)\n ORDER BY super_admin DESC\n LIMIT $1 OFFSET $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "operator_only", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "login_type", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "verified", + "type_info": "Bool" + }, + { + "ordinal": 4, + "name": "super_admin", + "type_info": "Bool" + }, + { + "ordinal": 5, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "company", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "username", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + null, + null, + false, + false, + true, + true, + true + ] + }, + "hash": "2eec077cc9e27d7ccd160cbaac118c321c422705f79e69550bb60f377083bcef" +} diff --git a/backend/.sqlx/query-31bc3dcea29be9cc0242771d25a232f173446d29c08fc29ddb8d55294f2c070e.json b/backend/.sqlx/query-31bc3dcea29be9cc0242771d25a232f173446d29c08fc29ddb8d55294f2c070e.json new file mode 100644 index 0000000000..49fc84c349 --- /dev/null +++ b/backend/.sqlx/query-31bc3dcea29be9cc0242771d25a232f173446d29c08fc29ddb8d55294f2c070e.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM http_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "31bc3dcea29be9cc0242771d25a232f173446d29c08fc29ddb8d55294f2c070e" +} diff --git a/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json b/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json new file mode 100644 index 0000000000..85c0412f3b --- /dev/null +++ b/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE schedule SET on_success = $1, on_success_extra_args = $2 WHERE workspace_id = $3 RETURNING path", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Json", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed" +} diff --git a/backend/.sqlx/query-33c1793e55b1127d88d2509aadd0eb04e042463200f237b4c2cb176612fa16fe.json b/backend/.sqlx/query-33c1793e55b1127d88d2509aadd0eb04e042463200f237b4c2cb176612fa16fe.json new file mode 100644 index 0000000000..8728e35a0c --- /dev/null +++ b/backend/.sqlx/query-33c1793e55b1127d88d2509aadd0eb04e042463200f237b4c2cb176612fa16fe.json @@ -0,0 +1,21 @@ +{ + "db_name": "PostgreSQL", + "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)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Varchar", + "Timestamp", + "Varchar", + "Int8", + "Int8", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "33c1793e55b1127d88d2509aadd0eb04e042463200f237b4c2cb176612fa16fe" +} diff --git a/backend/.sqlx/query-9ed77e78e6295c62745ac3ac3b7e5f544f654d7cddc13acb5d3f4fdc12a8875f.json b/backend/.sqlx/query-34a45763bb4d14162f4cd3fa07cd8020f1f6085f4ee85f5eab3458637edf26cd.json similarity index 52% rename from backend/.sqlx/query-9ed77e78e6295c62745ac3ac3b7e5f544f654d7cddc13acb5d3f4fdc12a8875f.json rename to backend/.sqlx/query-34a45763bb4d14162f4cd3fa07cd8020f1f6085f4ee85f5eab3458637edf26cd.json index 9c7af05c42..f9dc00c28c 100644 --- a/backend/.sqlx/query-9ed77e78e6295c62745ac3ac3b7e5f544f654d7cddc13acb5d3f4fdc12a8875f.json +++ b/backend/.sqlx/query-34a45763bb4d14162f4cd3fa07cd8020f1f6085f4ee85f5eab3458637edf26cd.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT created_at FROM metrics WHERE id = 'license_key_renewal' ORDER BY created_at DESC LIMIT 1", + "query": "SELECT created_at FROM healthchecks WHERE check_type = $1 ORDER BY created_at DESC LIMIT 1", "describe": { "columns": [ { @@ -10,11 +10,13 @@ } ], "parameters": { - "Left": [] + "Left": [ + "Text" + ] }, "nullable": [ false ] }, - "hash": "9ed77e78e6295c62745ac3ac3b7e5f544f654d7cddc13acb5d3f4fdc12a8875f" + "hash": "34a45763bb4d14162f4cd3fa07cd8020f1f6085f4ee85f5eab3458637edf26cd" } diff --git a/backend/.sqlx/query-354f88b23d20f92c6b6d5bdd8d6c69b08c6a86116cbfd0ecad8f112f7f49d8d1.json b/backend/.sqlx/query-354f88b23d20f92c6b6d5bdd8d6c69b08c6a86116cbfd0ecad8f112f7f49d8d1.json new file mode 100644 index 0000000000..4b03b16262 --- /dev/null +++ b/backend/.sqlx/query-354f88b23d20f92c6b6d5bdd8d6c69b08c6a86116cbfd0ecad8f112f7f49d8d1.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT SUBSTRING(name, 9) as \"name!\", (config.config->'min_alive_workers_alert_threshold')::INT as \"threshold!\" \n FROM config \n WHERE name LIKE 'worker__%' AND config->'min_alive_workers_alert_threshold' IS NOT NULL", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "name!", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "threshold!", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null, + null + ] + }, + "hash": "354f88b23d20f92c6b6d5bdd8d6c69b08c6a86116cbfd0ecad8f112f7f49d8d1" +} diff --git a/backend/.sqlx/query-eb1f916f9beea3eea83ce359f5305d0cfb0d6cdba9cc56c6139f57e46345f843.json b/backend/.sqlx/query-388b3705f641621b0c2f4496e36cb7aa5a75b7e40fa312eff6590e54b02635a2.json similarity index 54% rename from backend/.sqlx/query-eb1f916f9beea3eea83ce359f5305d0cfb0d6cdba9cc56c6139f57e46345f843.json rename to backend/.sqlx/query-388b3705f641621b0c2f4496e36cb7aa5a75b7e40fa312eff6590e54b02635a2.json index ecd83ae2e3..48f8d1e10c 100644 --- a/backend/.sqlx/query-eb1f916f9beea3eea83ce359f5305d0cfb0d6cdba9cc56c6139f57e46345f843.json +++ b/backend/.sqlx/query-388b3705f641621b0c2f4496e36cb7aa5a75b7e40fa312eff6590e54b02635a2.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = 'bypassrls_1-2')", + "query": "SELECT EXISTS(SELECT 1 FROM metrics WHERE id = 'license_key_renewal' AND created_at > NOW() - INTERVAL '24 hours')", "describe": { "columns": [ { @@ -16,5 +16,5 @@ null ] }, - "hash": "eb1f916f9beea3eea83ce359f5305d0cfb0d6cdba9cc56c6139f57e46345f843" + "hash": "388b3705f641621b0c2f4496e36cb7aa5a75b7e40fa312eff6590e54b02635a2" } diff --git a/backend/.sqlx/query-3d60b4f2cbedb61affeff94fd77b7c86493c30a4d3d648d0660a3281824156b9.json b/backend/.sqlx/query-3d60b4f2cbedb61affeff94fd77b7c86493c30a4d3d648d0660a3281824156b9.json new file mode 100644 index 0000000000..4c17792a7b --- /dev/null +++ b/backend/.sqlx/query-3d60b4f2cbedb61affeff94fd77b7c86493c30a4d3d648d0660a3281824156b9.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM global_settings WHERE name = 'base_url'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "3d60b4f2cbedb61affeff94fd77b7c86493c30a4d3d648d0660a3281824156b9" +} diff --git a/backend/.sqlx/query-3e539fef054ad31bc1736e27276087775a721a6ee7ae35b03fd4ce3563ea3838.json b/backend/.sqlx/query-3e539fef054ad31bc1736e27276087775a721a6ee7ae35b03fd4ce3563ea3838.json new file mode 100644 index 0000000000..f193758557 --- /dev/null +++ b/backend/.sqlx/query-3e539fef054ad31bc1736e27276087775a721a6ee7ae35b03fd4ce3563ea3838.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT raw_flow->'modules'->($1)->'value'->>'type' = 'flow' FROM queue WHERE id = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Uuid" + ] + }, + "nullable": [ + null + ] + }, + "hash": "3e539fef054ad31bc1736e27276087775a721a6ee7ae35b03fd4ce3563ea3838" +} diff --git a/backend/.sqlx/query-3ecb25b05d6c14b499f9b00af42ae74134728899f6b59c68b246979bc5143e30.json b/backend/.sqlx/query-3ecb25b05d6c14b499f9b00af42ae74134728899f6b59c68b246979bc5143e30.json new file mode 100644 index 0000000000..a652b56bad --- /dev/null +++ b/backend/.sqlx/query-3ecb25b05d6c14b499f9b00af42ae74134728899f6b59c68b246979bc5143e30.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT COUNT(*) as count, \n MIN(scheduled_for) as oldest_job\n FROM queue \n WHERE tag = $1 \n AND scheduled_for <= NOW() - $2::interval \n AND running = false\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "oldest_job", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text", + "Interval" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "3ecb25b05d6c14b499f9b00af42ae74134728899f6b59c68b246979bc5143e30" +} diff --git a/backend/.sqlx/query-872dcaec230579e4480adf23075e323557efbe52c813e3a6a0da6b855291951e.json b/backend/.sqlx/query-3fedf12ee5d44e8af9c3864cc70a8f607dccc015ce2d5150c56c68074cd0f84d.json similarity index 57% rename from backend/.sqlx/query-872dcaec230579e4480adf23075e323557efbe52c813e3a6a0da6b855291951e.json rename to backend/.sqlx/query-3fedf12ee5d44e8af9c3864cc70a8f607dccc015ce2d5150c56c68074cd0f84d.json index cdf6a3f4fa..1d91cd4031 100644 --- a/backend/.sqlx/query-872dcaec230579e4480adf23075e323557efbe52c813e3a6a0da6b855291951e.json +++ b/backend/.sqlx/query-3fedf12ee5d44e8af9c3864cc70a8f607dccc015ce2d5150c56c68074cd0f84d.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT tag, dedicated_worker, flow_version.value->>'early_return' as early_return \n FROM flow \n LEFT JOIN flow_version\n ON flow_version.id = flow.versions[array_upper(flow.versions, 1)]\n WHERE flow.path = $1 and flow.workspace_id = $2", + "query": "SELECT tag, dedicated_worker, flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor \n FROM flow \n LEFT JOIN flow_version\n ON flow_version.id = flow.versions[array_upper(flow.versions, 1)]\n WHERE flow.path = $1 and flow.workspace_id = $2", "describe": { "columns": [ { @@ -15,8 +15,8 @@ }, { "ordinal": 2, - "name": "early_return", - "type_info": "Text" + "name": "has_preprocessor", + "type_info": "Bool" } ], "parameters": { @@ -31,5 +31,5 @@ null ] }, - "hash": "872dcaec230579e4480adf23075e323557efbe52c813e3a6a0da6b855291951e" + "hash": "3fedf12ee5d44e8af9c3864cc70a8f607dccc015ce2d5150c56c68074cd0f84d" } diff --git a/backend/.sqlx/query-9bf41c3161a02b7d0731c4e1d79519cef5255f5df1b759af3aa4985bb64313e5.json b/backend/.sqlx/query-41f68f4ce5bed783cf69e42da115e9ad2c9fcbd75f55817b2114c04207f66e4a.json similarity index 78% rename from backend/.sqlx/query-9bf41c3161a02b7d0731c4e1d79519cef5255f5df1b759af3aa4985bb64313e5.json rename to backend/.sqlx/query-41f68f4ce5bed783cf69e42da115e9ad2c9fcbd75f55817b2114c04207f66e4a.json index 2eec9fba30..9397f52b83 100644 --- a/backend/.sqlx/query-9bf41c3161a02b7d0731c4e1d79519cef5255f5df1b759af3aa4985bb64313e5.json +++ b/backend/.sqlx/query-41f68f4ce5bed783cf69e42da115e9ad2c9fcbd75f55817b2114c04207f66e4a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO metrics (id, value)\n VALUES ($1, to_jsonb((SELECT EXTRACT(EPOCH FROM now() - scheduled_for)\n FROM queue WHERE tag = $2 AND running = false AND scheduled_for <= now() - ('3 seconds')::interval\n ORDER BY priority DESC NULLS LAST, scheduled_for, created_at LIMIT 1)))", + "query": "INSERT INTO metrics (id, value)\n VALUES ($1, to_jsonb((SELECT EXTRACT(EPOCH FROM now() - scheduled_for)\n FROM queue WHERE tag = $2 AND running = false AND scheduled_for <= now() - ('3 seconds')::interval\n ORDER BY priority DESC NULLS LAST, scheduled_for LIMIT 1)))", "describe": { "columns": [], "parameters": { @@ -11,5 +11,5 @@ }, "nullable": [] }, - "hash": "9bf41c3161a02b7d0731c4e1d79519cef5255f5df1b759af3aa4985bb64313e5" + "hash": "41f68f4ce5bed783cf69e42da115e9ad2c9fcbd75f55817b2114c04207f66e4a" } diff --git a/backend/.sqlx/query-4422b7183ede17a9cbde4afae41be4da5447020e39398deedbcca9121492834a.json b/backend/.sqlx/query-4422b7183ede17a9cbde4afae41be4da5447020e39398deedbcca9121492834a.json index 1163e930c9..3e8ba47b99 100644 --- a/backend/.sqlx/query-4422b7183ede17a9cbde4afae41be4da5447020e39398deedbcca9121492834a.json +++ b/backend/.sqlx/query-4422b7183ede17a9cbde4afae41be4da5447020e39398deedbcca9121492834a.json @@ -135,6 +135,16 @@ }, { "ordinal": 26, + "name": "on_success", + "type_info": "Varchar" + }, + { + "ordinal": 27, + "name": "on_success_extra_args", + "type_info": "Json" + }, + { + "ordinal": 28, "name": "jobs", "type_info": "JsonArray" } @@ -173,6 +183,8 @@ false, true, true, + true, + true, null ] }, diff --git a/backend/.sqlx/query-7c95f3652de4561b18c1a340db3e0113a4777d38de4468fc41b22ce5b6fd1db7.json b/backend/.sqlx/query-44dd7a66ecc9564ad5727970b5f60a1717eda8924999741be522ffb74cc173fa.json similarity index 63% rename from backend/.sqlx/query-7c95f3652de4561b18c1a340db3e0113a4777d38de4468fc41b22ce5b6fd1db7.json rename to backend/.sqlx/query-44dd7a66ecc9564ad5727970b5f60a1717eda8924999741be522ffb74cc173fa.json index 7222da038c..9f97b97a88 100644 --- a/backend/.sqlx/query-7c95f3652de4561b18c1a340db3e0113a4777d38de4468fc41b22ce5b6fd1db7.json +++ b/backend/.sqlx/query-44dd7a66ecc9564ad5727970b5f60a1717eda8924999741be522ffb74cc173fa.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "WITH queue_metrics as (\n SELECT id, value, created_at\n FROM metrics\n WHERE id LIKE 'queue_%'\n AND created_at > now() - interval '14 day'\n ORDER BY created_at ASC\n )\n SELECT id, array_agg(json_build_object('value', value, 'created_at', created_at)) as \"values!\"\n FROM queue_metrics\n GROUP BY id\n ORDER BY id ASC", + "query": "WITH queue_metrics as (\n SELECT id, value, created_at\n FROM metrics\n WHERE id LIKE 'queue_%'\n AND created_at > now() - interval '14 day'\n )\n SELECT id, array_agg(json_build_object('value', value, 'created_at', created_at) ORDER BY created_at ASC) as \"values!\"\n FROM queue_metrics\n GROUP BY id\n ORDER BY id ASC", "describe": { "columns": [ { @@ -22,5 +22,5 @@ null ] }, - "hash": "7c95f3652de4561b18c1a340db3e0113a4777d38de4468fc41b22ce5b6fd1db7" + "hash": "44dd7a66ecc9564ad5727970b5f60a1717eda8924999741be522ffb74cc173fa" } diff --git a/backend/.sqlx/query-4c0067c2135a259aea5cc2db60f7375a9a33671be8ef406427d90f67a98c9c9f.json b/backend/.sqlx/query-4c0067c2135a259aea5cc2db60f7375a9a33671be8ef406427d90f67a98c9c9f.json new file mode 100644 index 0000000000..32295ea1e1 --- /dev/null +++ b/backend/.sqlx/query-4c0067c2135a259aea5cc2db60f7375a9a33671be8ef406427d90f67a98c9c9f.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO alerts (alert_type, message) VALUES ('critical_error', $1)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [] + }, + "hash": "4c0067c2135a259aea5cc2db60f7375a9a33671be8ef406427d90f67a98c9c9f" +} diff --git a/backend/.sqlx/query-4c97fcc93b31c4b3262419d6ee183773a95de3b6694a398cb80d288bef4f130f.json b/backend/.sqlx/query-4c97fcc93b31c4b3262419d6ee183773a95de3b6694a398cb80d288bef4f130f.json new file mode 100644 index 0000000000..53a59847e7 --- /dev/null +++ b/backend/.sqlx/query-4c97fcc93b31c4b3262419d6ee183773a95de3b6694a398cb80d288bef4f130f.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE completed_job SET args = '{\"reason\":\"PREPROCESSOR_ARGS_ARE_DISCARDED\"}'::jsonb WHERE id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "4c97fcc93b31c4b3262419d6ee183773a95de3b6694a398cb80d288bef4f130f" +} diff --git a/backend/.sqlx/query-4cfa57b2a836242d55071ef237855b21bbc487b80bda7fd6250ac12e93938577.json b/backend/.sqlx/query-4cfa57b2a836242d55071ef237855b21bbc487b80bda7fd6250ac12e93938577.json new file mode 100644 index 0000000000..5ac1cd561e --- /dev/null +++ b/backend/.sqlx/query-4cfa57b2a836242d55071ef237855b21bbc487b80bda7fd6250ac12e93938577.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO healthchecks (check_type, healthy) \n SELECT 'min_alive_workers_' || $1, true \n WHERE NOT EXISTS (\n SELECT 1 FROM healthchecks \n WHERE check_type = 'min_alive_workers_' || $1 AND created_at > NOW() - INTERVAL '2 minutes'\n )\n RETURNING id", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "4cfa57b2a836242d55071ef237855b21bbc487b80bda7fd6250ac12e93938577" +} diff --git a/backend/.sqlx/query-4d8640e84fccf1a0b799d8396a51e69345137e68d5096c70ba0a4332075d97ea.json b/backend/.sqlx/query-4d8640e84fccf1a0b799d8396a51e69345137e68d5096c70ba0a4332075d97ea.json new file mode 100644 index 0000000000..b66edc6d73 --- /dev/null +++ b/backend/.sqlx/query-4d8640e84fccf1a0b799d8396a51e69345137e68d5096c70ba0a4332075d97ea.json @@ -0,0 +1,38 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE http_trigger \n SET route_path = $1, route_path_key = $2, script_path = $3, path = $4, is_flow = $5, http_method = $6, edited_by = $7, email = $8, is_async = $9, requires_auth = $10, edited_at = now() \n WHERE workspace_id = $11 AND path = $12", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Bool", + { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + }, + "Varchar", + "Varchar", + "Bool", + "Bool", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "4d8640e84fccf1a0b799d8396a51e69345137e68d5096c70ba0a4332075d97ea" +} diff --git a/backend/.sqlx/query-4e9668a46bad9e82baa51422946d373b18b6577198df7545c94bd19be3446775.json b/backend/.sqlx/query-4e9668a46bad9e82baa51422946d373b18b6577198df7545c94bd19be3446775.json new file mode 100644 index 0000000000..2f96d31ecb --- /dev/null +++ b/backend/.sqlx/query-4e9668a46bad9e82baa51422946d373b18b6577198df7545c94bd19be3446775.json @@ -0,0 +1,108 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO websocket_trigger (workspace_id, path, url, script_path, is_flow, enabled, filters, edited_by, email, edited_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, now()) RETURNING *", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "url", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 4, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "server_id", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "last_server_ping", + "type_info": "Timestamptz" + }, + { + "ordinal": 11, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 12, + "name": "enabled", + "type_info": "Bool" + }, + { + "ordinal": 13, + "name": "filters", + "type_info": "JsonbArray" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Bool", + "JsonbArray", + "Varchar", + "Varchar" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false + ] + }, + "hash": "4e9668a46bad9e82baa51422946d373b18b6577198df7545c94bd19be3446775" +} diff --git a/backend/.sqlx/query-4eca060026a0cb19c5794cd56ace89fc04765191f251945d14bbe78718714f6e.json b/backend/.sqlx/query-4eca060026a0cb19c5794cd56ace89fc04765191f251945d14bbe78718714f6e.json new file mode 100644 index 0000000000..3b812a53db --- /dev/null +++ b/backend/.sqlx/query-4eca060026a0cb19c5794cd56ace89fc04765191f251945d14bbe78718714f6e.json @@ -0,0 +1,39 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT event_type::AUTOSCALING_EVENT_TYPE AS \"event_type: _\", EXTRACT(EPOCH FROM (NOW() - applied_at))::int as seconds_ago FROM autoscaling_event WHERE worker_group = $1 ORDER BY applied_at DESC LIMIT 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "event_type: _", + "type_info": { + "Custom": { + "name": "autoscaling_event_type", + "kind": { + "Enum": [ + "full_scaleout", + "scalein", + "scaleout" + ] + } + } + } + }, + { + "ordinal": 1, + "name": "seconds_ago", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + null + ] + }, + "hash": "4eca060026a0cb19c5794cd56ace89fc04765191f251945d14bbe78718714f6e" +} diff --git a/backend/.sqlx/query-4fb95eae1c871241efe2ef79615ce03cba0e4a12aad3274e4829d98e38ca1491.json b/backend/.sqlx/query-4fb95eae1c871241efe2ef79615ce03cba0e4a12aad3274e4829d98e38ca1491.json new file mode 100644 index 0000000000..d954f2c26c --- /dev/null +++ b/backend/.sqlx/query-4fb95eae1c871241efe2ef79615ce03cba0e4a12aad3274e4829d98e38ca1491.json @@ -0,0 +1,108 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT workspace_id, path, route_path, route_path_key, script_path, is_flow, http_method as \"http_method: _\", edited_by, email, edited_at, extra_perms, is_async, requires_auth\n FROM http_trigger\n WHERE workspace_id = $1 AND path = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "route_path", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "route_path_key", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 6, + "name": "http_method: _", + "type_info": { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + } + }, + { + "ordinal": 7, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 9, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 10, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 11, + "name": "is_async", + "type_info": "Bool" + }, + { + "ordinal": 12, + "name": "requires_auth", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "4fb95eae1c871241efe2ef79615ce03cba0e4a12aad3274e4829d98e38ca1491" +} diff --git a/backend/.sqlx/query-5303cb9dd5903aa4791ef8e5e5881a50a832e65c8c9632e2e12cd9c2747f2fc7.json b/backend/.sqlx/query-5303cb9dd5903aa4791ef8e5e5881a50a832e65c8c9632e2e12cd9c2747f2fc7.json new file mode 100644 index 0000000000..a95b00b8c8 --- /dev/null +++ b/backend/.sqlx/query-5303cb9dd5903aa4791ef8e5e5881a50a832e65c8c9632e2e12cd9c2747f2fc7.json @@ -0,0 +1,98 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT *\n FROM websocket_trigger\n WHERE enabled IS TRUE AND (server_id IS NULL OR last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds')", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "url", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 4, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "server_id", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "last_server_ping", + "type_info": "Timestamptz" + }, + { + "ordinal": 11, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 12, + "name": "enabled", + "type_info": "Bool" + }, + { + "ordinal": 13, + "name": "filters", + "type_info": "JsonbArray" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false + ] + }, + "hash": "5303cb9dd5903aa4791ef8e5e5881a50a832e65c8c9632e2e12cd9c2747f2fc7" +} diff --git a/backend/.sqlx/query-55d44f569f8ebfccddf975e1a330ef0dc286f4138efe923832371cdbac7157b0.json b/backend/.sqlx/query-55d44f569f8ebfccddf975e1a330ef0dc286f4138efe923832371cdbac7157b0.json new file mode 100644 index 0000000000..ca0a922067 --- /dev/null +++ b/backend/.sqlx/query-55d44f569f8ebfccddf975e1a330ef0dc286f4138efe923832371cdbac7157b0.json @@ -0,0 +1,36 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE http_trigger SET script_path = $1, path = $2, is_flow = $3, http_method = $4, edited_by = $5, email = $6, is_async = $7, requires_auth = $8, edited_at = now() \n WHERE workspace_id = $9 AND path = $10", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Bool", + { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + }, + "Varchar", + "Varchar", + "Bool", + "Bool", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "55d44f569f8ebfccddf975e1a330ef0dc286f4138efe923832371cdbac7157b0" +} diff --git a/backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json b/backend/.sqlx/query-56eafd6d3c72f7114e3d6764184825e2671283fc70abba9a036e88699430af0f.json similarity index 74% rename from backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json rename to backend/.sqlx/query-56eafd6d3c72f7114e3d6764184825e2671283fc70abba9a036e88699430af0f.json index 1f40dbca3b..9f22b4df19 100644 --- a/backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json +++ b/backend/.sqlx/query-56eafd6d3c72f7114e3d6764184825e2671283fc70abba9a036e88699430af0f.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_label';", + "query": "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_labels'", "describe": { "columns": [], "parameters": { @@ -8,5 +8,5 @@ }, "nullable": [] }, - "hash": "89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec" + "hash": "56eafd6d3c72f7114e3d6764184825e2671283fc70abba9a036e88699430af0f" } diff --git a/backend/.sqlx/query-57e270e032e8c04dda7b5c1ca949861756b3ad367a4a500728332a7cb91560a4.json b/backend/.sqlx/query-57e270e032e8c04dda7b5c1ca949861756b3ad367a4a500728332a7cb91560a4.json new file mode 100644 index 0000000000..ccf6b0ad8f --- /dev/null +++ b/backend/.sqlx/query-57e270e032e8c04dda7b5c1ca949861756b3ad367a4a500728332a7cb91560a4.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE concurrency_locks SET\n last_locked_at = now()\n WHERE id = $1 AND owner = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "57e270e032e8c04dda7b5c1ca949861756b3ad367a4a500728332a7cb91560a4" +} diff --git a/backend/.sqlx/query-5f22a7c9170f035779782591b4bfb1d462d5c796f08c7481c42154f9bfacf388.json b/backend/.sqlx/query-5f22a7c9170f035779782591b4bfb1d462d5c796f08c7481c42154f9bfacf388.json new file mode 100644 index 0000000000..1aea7e585c --- /dev/null +++ b/backend/.sqlx/query-5f22a7c9170f035779782591b4bfb1d462d5c796f08c7481c42154f9bfacf388.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO healthchecks (check_type, healthy) \n SELECT 'min_alive_workers_' || $1, false\n WHERE NOT EXISTS (\n SELECT 1 FROM healthchecks \n WHERE check_type = 'min_alive_workers_' || $1 AND created_at > NOW() - INTERVAL '2 minutes'\n )\n RETURNING id", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "5f22a7c9170f035779782591b4bfb1d462d5c796f08c7481c42154f9bfacf388" +} diff --git a/backend/.sqlx/query-5fc6b4a4dbb7875bdec76f876c18543435a95b019b20081f52f6ed6f4457e3c7.json b/backend/.sqlx/query-5fc6b4a4dbb7875bdec76f876c18543435a95b019b20081f52f6ed6f4457e3c7.json new file mode 100644 index 0000000000..d4725c224e --- /dev/null +++ b/backend/.sqlx/query-5fc6b4a4dbb7875bdec76f876c18543435a95b019b20081f52f6ed6f4457e3c7.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM token WHERE label LIKE 'webhook-%' AND workspace_id = $1 AND scopes @> ARRAY['run:' || $2]::text[]", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "5fc6b4a4dbb7875bdec76f876c18543435a95b019b20081f52f6ed6f4457e3c7" +} diff --git a/backend/.sqlx/query-5fd70c70ce52cbc51fa9124cb05f82b5951f17d1b7eade53c6d89253d55f8b9f.json b/backend/.sqlx/query-5fd70c70ce52cbc51fa9124cb05f82b5951f17d1b7eade53c6d89253d55f8b9f.json new file mode 100644 index 0000000000..51f58cb81c --- /dev/null +++ b/backend/.sqlx/query-5fd70c70ce52cbc51fa9124cb05f82b5951f17d1b7eade53c6d89253d55f8b9f.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT owner FROM concurrency_locks WHERE id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "owner", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + true + ] + }, + "hash": "5fd70c70ce52cbc51fa9124cb05f82b5951f17d1b7eade53c6d89253d55f8b9f" +} diff --git a/backend/.sqlx/query-8b10c9ade85c0307e300224e87962ceba8e7ccbe53b56c4670a1634bb9d0e89c.json b/backend/.sqlx/query-64ce3eabed6de7a4f99884640c21218ac19ab2a4bc5f8b42deb2476f85d0deac.json similarity index 86% rename from backend/.sqlx/query-8b10c9ade85c0307e300224e87962ceba8e7ccbe53b56c4670a1634bb9d0e89c.json rename to backend/.sqlx/query-64ce3eabed6de7a4f99884640c21218ac19ab2a4bc5f8b42deb2476f85d0deac.json index 3eddd1237b..6bc0fb8a10 100644 --- a/backend/.sqlx/query-8b10c9ade85c0307e300224e87962ceba8e7ccbe53b56c4670a1634bb9d0e89c.json +++ b/backend/.sqlx/query-64ce3eabed6de7a4f99884640c21218ac19ab2a4bc5f8b42deb2476f85d0deac.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "select path, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, cache_ttl, language as \"language: ScriptLang\", dedicated_worker, priority, delete_after_use, timeout from script where hash = $1 AND workspace_id = $2", + "query": "select path, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, cache_ttl, language as \"language: ScriptLang\", dedicated_worker, priority, delete_after_use, timeout, has_preprocessor from script where hash = $1 AND workspace_id = $2", "describe": { "columns": [ { @@ -55,7 +55,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } @@ -80,6 +82,11 @@ "ordinal": 10, "name": "timeout", "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "has_preprocessor", + "type_info": "Bool" } ], "parameters": { @@ -99,8 +106,9 @@ true, true, true, + true, true ] }, - "hash": "8b10c9ade85c0307e300224e87962ceba8e7ccbe53b56c4670a1634bb9d0e89c" + "hash": "64ce3eabed6de7a4f99884640c21218ac19ab2a4bc5f8b42deb2476f85d0deac" } diff --git a/backend/.sqlx/query-55d6c6f887f1cceb311d9ab034d3485b8ccb2d07d723f184cef2696760d3ccf9.json b/backend/.sqlx/query-6a497334c98bfaf70be44fced572a1cc0dde4141aa4c5002765a95432d0101ab.json similarity index 65% rename from backend/.sqlx/query-55d6c6f887f1cceb311d9ab034d3485b8ccb2d07d723f184cef2696760d3ccf9.json rename to backend/.sqlx/query-6a497334c98bfaf70be44fced572a1cc0dde4141aa4c5002765a95432d0101ab.json index dc06930fb1..9df7dced7b 100644 --- a/backend/.sqlx/query-55d6c6f887f1cceb311d9ab034d3485b8ccb2d07d723f184cef2696760d3ccf9.json +++ b/backend/.sqlx/query-6a497334c98bfaf70be44fced572a1cc0dde4141aa4c5002765a95432d0101ab.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT worker, worker_instance, EXTRACT(EPOCH FROM (now() - ping_at))::integer as last_ping, started_at, ip, jobs_executed, CASE WHEN $4 IS TRUE THEN current_job_id ELSE NULL END as current_job_id, CASE WHEN $4 IS TRUE THEN current_job_workspace_id ELSE NULL END as current_job_workspace_id, custom_tags, worker_group, wm_version, occupancy_rate, memory, vcpus, memory_usage, wm_memory_usage\n FROM worker_ping\n WHERE ($1::integer IS NULL AND ping_at > now() - interval '5 minute') OR (ping_at > now() - ($1 || ' seconds')::interval)\n ORDER BY ping_at desc LIMIT $2 OFFSET $3", + "query": "SELECT worker, worker_instance, EXTRACT(EPOCH FROM (now() - ping_at))::integer as last_ping, started_at, ip, jobs_executed,\n CASE WHEN $4 IS TRUE THEN current_job_id ELSE NULL END as last_job_id, CASE WHEN $4 IS TRUE THEN current_job_workspace_id ELSE NULL END as last_job_workspace_id, \n custom_tags, worker_group, wm_version, occupancy_rate, occupancy_rate_15s, occupancy_rate_5m, occupancy_rate_30m, memory, vcpus, memory_usage, wm_memory_usage\n FROM worker_ping\n WHERE ($1::integer IS NULL AND ping_at > now() - interval '5 minute') OR (ping_at > now() - ($1 || ' seconds')::interval)\n ORDER BY ping_at desc LIMIT $2 OFFSET $3", "describe": { "columns": [ { @@ -35,12 +35,12 @@ }, { "ordinal": 6, - "name": "current_job_id", + "name": "last_job_id", "type_info": "Uuid" }, { "ordinal": 7, - "name": "current_job_workspace_id", + "name": "last_job_workspace_id", "type_info": "Varchar" }, { @@ -65,21 +65,36 @@ }, { "ordinal": 12, + "name": "occupancy_rate_15s", + "type_info": "Float4" + }, + { + "ordinal": 13, + "name": "occupancy_rate_5m", + "type_info": "Float4" + }, + { + "ordinal": 14, + "name": "occupancy_rate_30m", + "type_info": "Float4" + }, + { + "ordinal": 15, "name": "memory", "type_info": "Int8" }, { - "ordinal": 13, + "ordinal": 16, "name": "vcpus", "type_info": "Int8" }, { - "ordinal": 14, + "ordinal": 17, "name": "memory_usage", "type_info": "Int8" }, { - "ordinal": 15, + "ordinal": 18, "name": "wm_memory_usage", "type_info": "Int8" } @@ -108,8 +123,11 @@ true, true, true, + true, + true, + true, true ] }, - "hash": "55d6c6f887f1cceb311d9ab034d3485b8ccb2d07d723f184cef2696760d3ccf9" + "hash": "6a497334c98bfaf70be44fced572a1cc0dde4141aa4c5002765a95432d0101ab" } diff --git a/backend/.sqlx/query-6d134b137ae81534e145fc5b6474cf963ee26a3ad3a0a3d8dc064cb14c8fd9a6.json b/backend/.sqlx/query-6d134b137ae81534e145fc5b6474cf963ee26a3ad3a0a3d8dc064cb14c8fd9a6.json new file mode 100644 index 0000000000..03351cdeab --- /dev/null +++ b/backend/.sqlx/query-6d134b137ae81534e145fc5b6474cf963ee26a3ad3a0a3d8dc064cb14c8fd9a6.json @@ -0,0 +1,52 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT id, worker_group, event_type::text, desired_workers, reason, applied_at FROM autoscaling_event WHERE worker_group = $1 ORDER BY applied_at DESC LIMIT 5", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "worker_group", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "event_type", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "desired_workers", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "reason", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "applied_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + null, + false, + true, + false + ] + }, + "hash": "6d134b137ae81534e145fc5b6474cf963ee26a3ad3a0a3d8dc064cb14c8fd9a6" +} diff --git a/backend/.sqlx/query-6e7f234267fbb4720b29f288fba82c1df21ba601ac0989e175f834c569962d46.json b/backend/.sqlx/query-6e7f234267fbb4720b29f288fba82c1df21ba601ac0989e175f834c569962d46.json new file mode 100644 index 0000000000..e8db78adbd --- /dev/null +++ b/backend/.sqlx/query-6e7f234267fbb4720b29f288fba82c1df21ba601ac0989e175f834c569962d46.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(flow_status, ARRAY['modules', $1::TEXT, 'iterator', 'index'], ((flow_status->'modules'->$1::int->'iterator'->>'index')::int + 1)::text::jsonb),\n last_ping = NULL\n WHERE id = $2\n RETURNING (flow_status->'modules'->$1::int->'iterator'->>'index')::int", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "int4", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4", + "Uuid" + ] + }, + "nullable": [ + null + ] + }, + "hash": "6e7f234267fbb4720b29f288fba82c1df21ba601ac0989e175f834c569962d46" +} diff --git a/backend/.sqlx/query-6f4817fad2739a11d89b6704edf62c3c267ca336a8b6bec5b29d4409030ed561.json b/backend/.sqlx/query-6f4817fad2739a11d89b6704edf62c3c267ca336a8b6bec5b29d4409030ed561.json new file mode 100644 index 0000000000..5605518c9c --- /dev/null +++ b/backend/.sqlx/query-6f4817fad2739a11d89b6704edf62c3c267ca336a8b6bec5b29d4409030ed561.json @@ -0,0 +1,73 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO queue (id, script_hash, script_path, job_kind, language, tag, created_by, permissioned_as, email, scheduled_for, workspace_id, raw_flow, flow_status) (SELECT gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 FROM generate_series(1, 1))", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Varchar", + { + "Custom": { + "name": "job_kind", + "kind": { + "Enum": [ + "script", + "preview", + "flow", + "dependencies", + "flowpreview", + "script_hub", + "identity", + "flowdependencies", + "http", + "graphql", + "postgresql", + "noop", + "appdependencies", + "deploymentcallback", + "singlescriptflow" + ] + } + } + }, + { + "Custom": { + "name": "script_lang", + "kind": { + "Enum": [ + "python3", + "deno", + "go", + "bash", + "postgresql", + "nativets", + "bun", + "mysql", + "bigquery", + "snowflake", + "graphql", + "powershell", + "mssql", + "php", + "bunnative", + "rust", + "ansible" + ] + } + } + }, + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Timestamptz", + "Varchar", + "Jsonb", + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "6f4817fad2739a11d89b6704edf62c3c267ca336a8b6bec5b29d4409030ed561" +} diff --git a/backend/.sqlx/query-722a3096f03d25ef94292d53801d41037de4bc69dd434232029c731cbbcbc22f.json b/backend/.sqlx/query-722a3096f03d25ef94292d53801d41037de4bc69dd434232029c731cbbcbc22f.json deleted file mode 100644 index 2e4dee2a30..0000000000 --- a/backend/.sqlx/query-722a3096f03d25ef94292d53801d41037de4bc69dd434232029c731cbbcbc22f.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO windmill_migrations (name) VALUES ('bypassrls_1-2')", - "describe": { - "columns": [], - "parameters": { - "Left": [] - }, - "nullable": [] - }, - "hash": "722a3096f03d25ef94292d53801d41037de4bc69dd434232029c731cbbcbc22f" -} diff --git a/backend/.sqlx/query-74d5757014fc7a6818ae857bfdda9f6317cf2b9e0a78cbad80ebdc935d3246fd.json b/backend/.sqlx/query-74d5757014fc7a6818ae857bfdda9f6317cf2b9e0a78cbad80ebdc935d3246fd.json new file mode 100644 index 0000000000..0501df6cfe --- /dev/null +++ b/backend/.sqlx/query-74d5757014fc7a6818ae857bfdda9f6317cf2b9e0a78cbad80ebdc935d3246fd.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT 1 FROM password LIMIT 2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "74d5757014fc7a6818ae857bfdda9f6317cf2b9e0a78cbad80ebdc935d3246fd" +} diff --git a/backend/.sqlx/query-76ca60e456022cf3d1931245b7daf22783c81bc757d735a4b247cc693dfed719.json b/backend/.sqlx/query-76ca60e456022cf3d1931245b7daf22783c81bc757d735a4b247cc693dfed719.json new file mode 100644 index 0000000000..530638af1f --- /dev/null +++ b/backend/.sqlx/query-76ca60e456022cf3d1931245b7daf22783c81bc757d735a4b247cc693dfed719.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(flow_status, ARRAY['modules', flow_status->>'step', 'progress'], $1)\n WHERE id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "76ca60e456022cf3d1931245b7daf22783c81bc757d735a4b247cc693dfed719" +} diff --git a/backend/.sqlx/query-a94dbd1f7aab20682548471c5cc06c7a496edac36e3de537b00b76ad93c7556c.json b/backend/.sqlx/query-777190559e27c8c8fb6718b0a0c1d7db9b956abd88b94db3948f2c579c3826d0.json similarity index 60% rename from backend/.sqlx/query-a94dbd1f7aab20682548471c5cc06c7a496edac36e3de537b00b76ad93c7556c.json rename to backend/.sqlx/query-777190559e27c8c8fb6718b0a0c1d7db9b956abd88b94db3948f2c579c3826d0.json index 5906375f53..0c1d65bb6b 100644 --- a/backend/.sqlx/query-a94dbd1f7aab20682548471c5cc06c7a496edac36e3de537b00b76ad93c7556c.json +++ b/backend/.sqlx/query-777190559e27c8c8fb6718b0a0c1d7db9b956abd88b94db3948f2c579c3826d0.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE queue\n SET flow_status = JSONB_SET(flow_status, ARRAY['modules', $1::TEXT, 'branchall', 'branch'], ((flow_status->'modules'->$1::int->'branchall'->>'branch')::int + 1)::text::jsonb)\n WHERE id = $2\n RETURNING (flow_status->'modules'->$1::int->'branchall'->>'branch')::int", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(flow_status, ARRAY['modules', $1::TEXT, 'branchall', 'branch'], ((flow_status->'modules'->$1::int->'branchall'->>'branch')::int + 1)::text::jsonb),\n last_ping = NULL\n WHERE id = $2\n RETURNING (flow_status->'modules'->$1::int->'branchall'->>'branch')::int", "describe": { "columns": [ { @@ -19,5 +19,5 @@ null ] }, - "hash": "a94dbd1f7aab20682548471c5cc06c7a496edac36e3de537b00b76ad93c7556c" + "hash": "777190559e27c8c8fb6718b0a0c1d7db9b956abd88b94db3948f2c579c3826d0" } diff --git a/backend/.sqlx/query-7b1239ad6460e8f5fb41bfe12f662a779528784ec8cf3f6dcce5545ab90bf234.json b/backend/.sqlx/query-7b1239ad6460e8f5fb41bfe12f662a779528784ec8cf3f6dcce5545ab90bf234.json index 7bdf4f49a7..a7a5b812f7 100644 --- a/backend/.sqlx/query-7b1239ad6460e8f5fb41bfe12f662a779528784ec8cf3f6dcce5545ab90bf234.json +++ b/backend/.sqlx/query-7b1239ad6460e8f5fb41bfe12f662a779528784ec8cf3f6dcce5545ab90bf234.json @@ -32,6 +32,11 @@ "ordinal": 5, "name": "created_by", "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "format_extension", + "type_info": "Varchar" } ], "parameters": { @@ -45,6 +50,7 @@ true, true, true, + true, true ] }, diff --git a/backend/.sqlx/query-7fa8fca5b5cdf147da0cf8ae5a0d9fdee37dd8df66974c8d33f58a88b1bca537.json b/backend/.sqlx/query-7fa8fca5b5cdf147da0cf8ae5a0d9fdee37dd8df66974c8d33f58a88b1bca537.json new file mode 100644 index 0000000000..e4aa1f4f24 --- /dev/null +++ b/backend/.sqlx/query-7fa8fca5b5cdf147da0cf8ae5a0d9fdee37dd8df66974c8d33f58a88b1bca537.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM healthchecks WHERE check_type LIKE 'min_alive_workers_%' AND created_at < NOW() - INTERVAL '48 hours'", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "7fa8fca5b5cdf147da0cf8ae5a0d9fdee37dd8df66974c8d33f58a88b1bca537" +} diff --git a/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json b/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json new file mode 100644 index 0000000000..c4a2ff0a10 --- /dev/null +++ b/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json @@ -0,0 +1,45 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO script (summary, description, dedicated_worker, content, workspace_id, path, hash, language, tag, created_by, lock) VALUES ('', '', true, $1, $2, $3, $4, $5, $6, $7, '') ON CONFLICT (workspace_id, hash) DO NOTHING", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Varchar", + "Varchar", + "Int8", + { + "Custom": { + "name": "script_lang", + "kind": { + "Enum": [ + "python3", + "deno", + "go", + "bash", + "postgresql", + "nativets", + "bun", + "mysql", + "bigquery", + "snowflake", + "graphql", + "powershell", + "mssql", + "php", + "bunnative", + "rust", + "ansible" + ] + } + } + }, + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf" +} diff --git a/backend/.sqlx/query-ae2f005af8ab4b035a907e0c8fc9a9d035f3eb1d9d833041969fce967daa91a4.json b/backend/.sqlx/query-829130d74c107e4e1a86f3e772657ae030463c139c39072777e453bfb7e9c0c3.json similarity index 50% rename from backend/.sqlx/query-ae2f005af8ab4b035a907e0c8fc9a9d035f3eb1d9d833041969fce967daa91a4.json rename to backend/.sqlx/query-829130d74c107e4e1a86f3e772657ae030463c139c39072777e453bfb7e9c0c3.json index 74c890726f..e00aba3aab 100644 --- a/backend/.sqlx/query-ae2f005af8ab4b035a907e0c8fc9a9d035f3eb1d9d833041969fce967daa91a4.json +++ b/backend/.sqlx/query-829130d74c107e4e1a86f3e772657ae030463c139c39072777e453bfb7e9c0c3.json @@ -1,23 +1,22 @@ { "db_name": "PostgreSQL", - "query": "SELECT raw_flow->'modules'->$2::int->'retry' FROM queue WHERE id = $1", + "query": "SELECT job_kind = 'identity' FROM completed_job WHERE id = $1", "describe": { "columns": [ { "ordinal": 0, "name": "?column?", - "type_info": "Jsonb" + "type_info": "Bool" } ], "parameters": { "Left": [ - "Uuid", - "Int4" + "Uuid" ] }, "nullable": [ null ] }, - "hash": "ae2f005af8ab4b035a907e0c8fc9a9d035f3eb1d9d833041969fce967daa91a4" + "hash": "829130d74c107e4e1a86f3e772657ae030463c139c39072777e453bfb7e9c0c3" } diff --git a/backend/.sqlx/query-83ec97f6aad154e0e06ee05a3647dab8f89b1b2d7a569c7eac8c4169e37b9f8b.json b/backend/.sqlx/query-83ec97f6aad154e0e06ee05a3647dab8f89b1b2d7a569c7eac8c4169e37b9f8b.json new file mode 100644 index 0000000000..4e0bc23b69 --- /dev/null +++ b/backend/.sqlx/query-83ec97f6aad154e0e06ee05a3647dab8f89b1b2d7a569c7eac8c4169e37b9f8b.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT value FROM global_settings WHERE name = 'smtp_settings'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "83ec97f6aad154e0e06ee05a3647dab8f89b1b2d7a569c7eac8c4169e37b9f8b" +} diff --git a/backend/.sqlx/query-845120388af12c2b2f57fedf95c8cce4a406b74c9a8c8590a3bae323d59d046a.json b/backend/.sqlx/query-845120388af12c2b2f57fedf95c8cce4a406b74c9a8c8590a3bae323d59d046a.json new file mode 100644 index 0000000000..afede37f44 --- /dev/null +++ b/backend/.sqlx/query-845120388af12c2b2f57fedf95c8cce4a406b74c9a8c8590a3bae323d59d046a.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM log_file WHERE log_ts <= now() - ($1::bigint::text || ' s')::interval ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "845120388af12c2b2f57fedf95c8cce4a406b74c9a8c8590a3bae323d59d046a" +} diff --git a/backend/.sqlx/query-867e0f8299e22a6b8e02d21adeb0281b1a10593715db823a5adeeac3ab1058cd.json b/backend/.sqlx/query-867e0f8299e22a6b8e02d21adeb0281b1a10593715db823a5adeeac3ab1058cd.json new file mode 100644 index 0000000000..ec6143fe39 --- /dev/null +++ b/backend/.sqlx/query-867e0f8299e22a6b8e02d21adeb0281b1a10593715db823a5adeeac3ab1058cd.json @@ -0,0 +1,37 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE route_path_key = $1 AND workspace_id = $2 AND http_method = $3)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + } + ] + }, + "nullable": [ + null + ] + }, + "hash": "867e0f8299e22a6b8e02d21adeb0281b1a10593715db823a5adeeac3ab1058cd" +} diff --git a/backend/.sqlx/query-870d7feec169f70d140b7477562315ed2fd4662975bf0d01cfbffac86a959368.json b/backend/.sqlx/query-870d7feec169f70d140b7477562315ed2fd4662975bf0d01cfbffac86a959368.json new file mode 100644 index 0000000000..f5c36ed27f --- /dev/null +++ b/backend/.sqlx/query-870d7feec169f70d140b7477562315ed2fd4662975bf0d01cfbffac86a959368.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(\n JSONB_SET(flow_status, ARRAY['modules', $1::TEXT], $2), ARRAY['step'], $3)\n WHERE id = $4", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Jsonb", + "Jsonb", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "870d7feec169f70d140b7477562315ed2fd4662975bf0d01cfbffac86a959368" +} diff --git a/backend/.sqlx/query-7ab02d2c060ed12531e6af98a5d3369afe534519bf48f61f88f60786db870c24.json b/backend/.sqlx/query-8c15ea27be82665fe74a4be3182a5049fa937e30b4115caf0ba8d61d34f2089a.json similarity index 50% rename from backend/.sqlx/query-7ab02d2c060ed12531e6af98a5d3369afe534519bf48f61f88f60786db870c24.json rename to backend/.sqlx/query-8c15ea27be82665fe74a4be3182a5049fa937e30b4115caf0ba8d61d34f2089a.json index f20c2c1562..9b20861537 100644 --- a/backend/.sqlx/query-7ab02d2c060ed12531e6af98a5d3369afe534519bf48f61f88f60786db870c24.json +++ b/backend/.sqlx/query-8c15ea27be82665fe74a4be3182a5049fa937e30b4115caf0ba8d61d34f2089a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE queue SET running = false, started_at = null, logs = logs || '\nRestarted job after not receiving job''s ping for too long the ' || now() || '\n\n' \n WHERE last_ping < now() - ($1 || ' seconds')::interval\n AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'singlescriptflow') AND same_worker = false RETURNING id, workspace_id, last_ping", + "query": "UPDATE queue SET running = false, started_at = null\n WHERE last_ping < now() - ($1 || ' seconds')::interval\n AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'singlescriptflow') AND same_worker = false RETURNING id, workspace_id, last_ping", "describe": { "columns": [ { @@ -30,5 +30,5 @@ true ] }, - "hash": "7ab02d2c060ed12531e6af98a5d3369afe534519bf48f61f88f60786db870c24" + "hash": "8c15ea27be82665fe74a4be3182a5049fa937e30b4115caf0ba8d61d34f2089a" } diff --git a/backend/.sqlx/query-8dd1de2aca8c6c9ffaddd2c41c3a614a50fa5fd03c2d3b9a41bd85a7f156345e.json b/backend/.sqlx/query-8dd1de2aca8c6c9ffaddd2c41c3a614a50fa5fd03c2d3b9a41bd85a7f156345e.json new file mode 100644 index 0000000000..c1a63e668f --- /dev/null +++ b/backend/.sqlx/query-8dd1de2aca8c6c9ffaddd2c41c3a614a50fa5fd03c2d3b9a41bd85a7f156345e.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT count(*) \n FROM worker_ping \n WHERE worker_group LIKE $1 AND ping_at > now() - INTERVAL '2 minutes'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "8dd1de2aca8c6c9ffaddd2c41c3a614a50fa5fd03c2d3b9a41bd85a7f156345e" +} diff --git a/backend/.sqlx/query-900ac59515e4283f4b57516210575dfe92f74a7220ed69e61899a6e0f053d9cd.json b/backend/.sqlx/query-900ac59515e4283f4b57516210575dfe92f74a7220ed69e61899a6e0f053d9cd.json new file mode 100644 index 0000000000..0bcd4d447f --- /dev/null +++ b/backend/.sqlx/query-900ac59515e4283f4b57516210575dfe92f74a7220ed69e61899a6e0f053d9cd.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO concurrency_locks (id, last_locked_at) VALUES ($1, NOW()) ON CONFLICT (id) DO NOTHING", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "900ac59515e4283f4b57516210575dfe92f74a7220ed69e61899a6e0f053d9cd" +} diff --git a/backend/.sqlx/query-9422431d79de41518f651ef24e86819d7b6a2f5531740a7deea1b51775335977.json b/backend/.sqlx/query-9422431d79de41518f651ef24e86819d7b6a2f5531740a7deea1b51775335977.json new file mode 100644 index 0000000000..7f2936f195 --- /dev/null +++ b/backend/.sqlx/query-9422431d79de41518f651ef24e86819d7b6a2f5531740a7deea1b51775335977.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT scalar_int FROM job_stats WHERE workspace_id = $1 AND job_id = $2 AND metric_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "scalar_int", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Uuid", + "Text" + ] + }, + "nullable": [ + true + ] + }, + "hash": "9422431d79de41518f651ef24e86819d7b6a2f5531740a7deea1b51775335977" +} diff --git a/backend/.sqlx/query-e87c317550af671e4b65752a9c0b659cedf430fb7242faee4379b4a13e5fd763.json b/backend/.sqlx/query-958ed17dafffdd37e636ccd244dc4ca60cbf562e6f6a371d5f9a9943fb30254c.json similarity index 69% rename from backend/.sqlx/query-e87c317550af671e4b65752a9c0b659cedf430fb7242faee4379b4a13e5fd763.json rename to backend/.sqlx/query-958ed17dafffdd37e636ccd244dc4ca60cbf562e6f6a371d5f9a9943fb30254c.json index 83ae3520d7..31501b4094 100644 --- a/backend/.sqlx/query-e87c317550af671e4b65752a9c0b659cedf430fb7242faee4379b4a13e5fd763.json +++ b/backend/.sqlx/query-958ed17dafffdd37e636ccd244dc4ca60cbf562e6f6a371d5f9a9943fb30254c.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO dependency_map (workspace_id, importer_path, importer_kind, imported_path, importer_node_id)\n VALUES ($1, $2, $4::text::IMPORTER_KIND, $3, $5)", + "query": "INSERT INTO dependency_map (workspace_id, importer_path, importer_kind, imported_path, importer_node_id)\n VALUES ($1, $2, $4::text::IMPORTER_KIND, $3, $5) ON CONFLICT DO NOTHING", "describe": { "columns": [], "parameters": { @@ -14,5 +14,5 @@ }, "nullable": [] }, - "hash": "e87c317550af671e4b65752a9c0b659cedf430fb7242faee4379b4a13e5fd763" + "hash": "958ed17dafffdd37e636ccd244dc4ca60cbf562e6f6a371d5f9a9943fb30254c" } diff --git a/backend/.sqlx/query-98081ee9a4a4a52ae70d74d26e8608a010722d7ea9dc343ae8f03e38978ffaba.json b/backend/.sqlx/query-98081ee9a4a4a52ae70d74d26e8608a010722d7ea9dc343ae8f03e38978ffaba.json new file mode 100644 index 0000000000..05cbaffc69 --- /dev/null +++ b/backend/.sqlx/query-98081ee9a4a4a52ae70d74d26e8608a010722d7ea9dc343ae8f03e38978ffaba.json @@ -0,0 +1,41 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT tag, dedicated_worker, flow_version.value->>'early_return' as early_return, flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor\n FROM flow \n LEFT JOIN flow_version\n ON flow_version.id = flow.versions[array_upper(flow.versions, 1)]\n WHERE flow.path = $1 and flow.workspace_id = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "tag", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "dedicated_worker", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "early_return", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "has_preprocessor", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + true, + true, + null, + null + ] + }, + "hash": "98081ee9a4a4a52ae70d74d26e8608a010722d7ea9dc343ae8f03e38978ffaba" +} diff --git a/backend/.sqlx/query-9a050ab74cfc13a4b855408e61ebcb0a9d27e5563fa7af5e00a4916b03a62ddb.json b/backend/.sqlx/query-9a050ab74cfc13a4b855408e61ebcb0a9d27e5563fa7af5e00a4916b03a62ddb.json new file mode 100644 index 0000000000..a0c5bd7642 --- /dev/null +++ b/backend/.sqlx/query-9a050ab74cfc13a4b855408e61ebcb0a9d27e5563fa7af5e00a4916b03a62ddb.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE path = $1 AND workspace_id = $2)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "9a050ab74cfc13a4b855408e61ebcb0a9d27e5563fa7af5e00a4916b03a62ddb" +} diff --git a/backend/.sqlx/query-9c17ddca92e0a93051b36bb688ad6c1c24108e45c94be52595ca6cb82135f4eb.json b/backend/.sqlx/query-9c17ddca92e0a93051b36bb688ad6c1c24108e45c94be52595ca6cb82135f4eb.json new file mode 100644 index 0000000000..5de165462e --- /dev/null +++ b/backend/.sqlx/query-9c17ddca92e0a93051b36bb688ad6c1c24108e45c94be52595ca6cb82135f4eb.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue SET args = (select result FROM completed_job WHERE id = $1) WHERE id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "9c17ddca92e0a93051b36bb688ad6c1c24108e45c94be52595ca6cb82135f4eb" +} diff --git a/backend/.sqlx/query-9d25fbd21a63e6e9ccfdbf0460c8b3ca6d7fa05600067f379659b59b6f2bf418.json b/backend/.sqlx/query-9d25fbd21a63e6e9ccfdbf0460c8b3ca6d7fa05600067f379659b59b6f2bf418.json index 2220f81e41..4f8a78ca66 100644 --- a/backend/.sqlx/query-9d25fbd21a63e6e9ccfdbf0460c8b3ca6d7fa05600067f379659b59b6f2bf418.json +++ b/backend/.sqlx/query-9d25fbd21a63e6e9ccfdbf0460c8b3ca6d7fa05600067f379659b59b6f2bf418.json @@ -55,7 +55,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-9d3556319411a27a875bf6cf0e5eda837cc63e4d8be912c0b5bfeea4a0c8db2e.json b/backend/.sqlx/query-9d3556319411a27a875bf6cf0e5eda837cc63e4d8be912c0b5bfeea4a0c8db2e.json index b1a706e87a..2393bc83df 100644 --- a/backend/.sqlx/query-9d3556319411a27a875bf6cf0e5eda837cc63e4d8be912c0b5bfeea4a0c8db2e.json +++ b/backend/.sqlx/query-9d3556319411a27a875bf6cf0e5eda837cc63e4d8be912c0b5bfeea4a0c8db2e.json @@ -50,7 +50,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-9f1f388924176dbe3dea882e0c62728a82ba256029096812dd705ccb1a552cfe.json b/backend/.sqlx/query-9f1f388924176dbe3dea882e0c62728a82ba256029096812dd705ccb1a552cfe.json new file mode 100644 index 0000000000..51ddd8af63 --- /dev/null +++ b/backend/.sqlx/query-9f1f388924176dbe3dea882e0c62728a82ba256029096812dd705ccb1a552cfe.json @@ -0,0 +1,19 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, account, is_oauth)\n VALUES ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Int4", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "9f1f388924176dbe3dea882e0c62728a82ba256029096812dd705ccb1a552cfe" +} diff --git a/backend/.sqlx/query-a439552f74ed0ba305e3d9cb99ae9e5d24834082ebf2fe9fd3964fdd80b69ccb.json b/backend/.sqlx/query-a439552f74ed0ba305e3d9cb99ae9e5d24834082ebf2fe9fd3964fdd80b69ccb.json new file mode 100644 index 0000000000..691a6d5e31 --- /dev/null +++ b/backend/.sqlx/query-a439552f74ed0ba305e3d9cb99ae9e5d24834082ebf2fe9fd3964fdd80b69ccb.json @@ -0,0 +1,24 @@ +{ + "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", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "TextArray", + "Float4", + "Int8", + "Int8", + "Text", + "Int8", + "Int8", + "Float4", + "Float4", + "Float4" + ] + }, + "nullable": [] + }, + "hash": "a439552f74ed0ba305e3d9cb99ae9e5d24834082ebf2fe9fd3964fdd80b69ccb" +} diff --git a/backend/.sqlx/query-a7f5431e3b8960e9dc46fae69dd4391516d8b169186548ec44528c84078b80d8.json b/backend/.sqlx/query-a7f5431e3b8960e9dc46fae69dd4391516d8b169186548ec44528c84078b80d8.json new file mode 100644 index 0000000000..7dc8e3efa7 --- /dev/null +++ b/backend/.sqlx/query-a7f5431e3b8960e9dc46fae69dd4391516d8b169186548ec44528c84078b80d8.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM token WHERE label LIKE 'email-%' AND workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "a7f5431e3b8960e9dc46fae69dd4391516d8b169186548ec44528c84078b80d8" +} diff --git a/backend/.sqlx/query-aa5bdf0ab8781cf984711ae4f4351eb3bd5621ae081a418f1d4dbcb8359a8adb.json b/backend/.sqlx/query-aa5bdf0ab8781cf984711ae4f4351eb3bd5621ae081a418f1d4dbcb8359a8adb.json new file mode 100644 index 0000000000..9a38a434b0 --- /dev/null +++ b/backend/.sqlx/query-aa5bdf0ab8781cf984711ae4f4351eb3bd5621ae081a418f1d4dbcb8359a8adb.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE password SET name = $1 WHERE email = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text" + ] + }, + "nullable": [] + }, + "hash": "aa5bdf0ab8781cf984711ae4f4351eb3bd5621ae081a418f1d4dbcb8359a8adb" +} diff --git a/backend/.sqlx/query-acbf74cf3302bfcf7615285070d3f8958932bb8a2dda715f1b9152ab44442780.json b/backend/.sqlx/query-acbf74cf3302bfcf7615285070d3f8958932bb8a2dda715f1b9152ab44442780.json new file mode 100644 index 0000000000..eef46ce41d --- /dev/null +++ b/backend/.sqlx/query-acbf74cf3302bfcf7615285070d3f8958932bb8a2dda715f1b9152ab44442780.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE websocket_trigger SET url = $1, script_path = $2, path = $3, is_flow = $4, filters = $5, edited_by = $6, email = $7, edited_at = now(), server_id = NULL, last_server_ping = NULL, error = NULL\n WHERE workspace_id = $8 AND path = $9", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + "Bool", + "JsonbArray", + "Varchar", + "Varchar", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "acbf74cf3302bfcf7615285070d3f8958932bb8a2dda715f1b9152ab44442780" +} diff --git a/backend/.sqlx/query-ad42118ccf6a9d2d1e072c4df064ddf964a5b3cd088fc162d0d8222325d4a5ea.json b/backend/.sqlx/query-ad42118ccf6a9d2d1e072c4df064ddf964a5b3cd088fc162d0d8222325d4a5ea.json new file mode 100644 index 0000000000..c43c2a2a65 --- /dev/null +++ b/backend/.sqlx/query-ad42118ccf6a9d2d1e072c4df064ddf964a5b3cd088fc162d0d8222325d4a5ea.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE healthchecks SET healthy = true WHERE check_type = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [] + }, + "hash": "ad42118ccf6a9d2d1e072c4df064ddf964a5b3cd088fc162d0d8222325d4a5ea" +} diff --git a/backend/.sqlx/query-ad8f9e0b06f288051cbec3c91877430a1d61353b9122fd42777d92e4cbc9f4fa.json b/backend/.sqlx/query-ad8f9e0b06f288051cbec3c91877430a1d61353b9122fd42777d92e4cbc9f4fa.json new file mode 100644 index 0000000000..00453be45b --- /dev/null +++ b/backend/.sqlx/query-ad8f9e0b06f288051cbec3c91877430a1d61353b9122fd42777d92e4cbc9f4fa.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(\n JSONB_SET(flow_status, ARRAY['failure_module'], $1), ARRAY['step'], $2)\n WHERE id = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb", + "Jsonb", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "ad8f9e0b06f288051cbec3c91877430a1d61353b9122fd42777d92e4cbc9f4fa" +} diff --git a/backend/.sqlx/query-ae25fae1aca2cffc43a6054cd54639ba9deaaef419ad4cb2655e7e95f602a688.json b/backend/.sqlx/query-ae25fae1aca2cffc43a6054cd54639ba9deaaef419ad4cb2655e7e95f602a688.json new file mode 100644 index 0000000000..5634e60233 --- /dev/null +++ b/backend/.sqlx/query-ae25fae1aca2cffc43a6054cd54639ba9deaaef419ad4cb2655e7e95f602a688.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO job_logs (job_id, logs) VALUES ($1,'Restarted job after not receiving job''s ping for too long the ' || now() || '\n\n') \n ON CONFLICT (job_id) DO UPDATE SET logs = job_logs.logs || '\nRestarted job after not receiving job''s ping for too long the ' || now() || '\n\n' WHERE job_logs.job_id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "ae25fae1aca2cffc43a6054cd54639ba9deaaef419ad4cb2655e7e95f602a688" +} diff --git a/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json b/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json index 99269c9851..54e94cfb8f 100644 --- a/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json +++ b/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json @@ -18,8 +18,8 @@ "Left": [] }, "nullable": [ - true, - false + false, + true ] }, "hash": "b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76" diff --git a/backend/.sqlx/query-8e7ff45c5378c3a3406ba94dc0653afa5d28c072203617c598caefaaf1bafcfb.json b/backend/.sqlx/query-b49b1eaf58e62063c7a03039d0c36e65991b1d21a3306390fb1c7ca38babafe3.json similarity index 79% rename from backend/.sqlx/query-8e7ff45c5378c3a3406ba94dc0653afa5d28c072203617c598caefaaf1bafcfb.json rename to backend/.sqlx/query-b49b1eaf58e62063c7a03039d0c36e65991b1d21a3306390fb1c7ca38babafe3.json index 251d21f167..cc825ff56f 100644 --- a/backend/.sqlx/query-8e7ff45c5378c3a3406ba94dc0653afa5d28c072203617c598caefaaf1bafcfb.json +++ b/backend/.sqlx/query-b49b1eaf58e62063c7a03039d0c36e65991b1d21a3306390fb1c7ca38babafe3.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30)", + "query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase, has_preprocessor) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31)", "describe": { "columns": [], "parameters": { @@ -36,7 +36,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } @@ -50,7 +52,8 @@ "trigger", "failure", "command", - "approval" + "approval", + "preprocessor" ] } } @@ -70,10 +73,11 @@ "Varchar", "Bool", "Bool", - "Varchar" + "Varchar", + "Bool" ] }, "nullable": [] }, - "hash": "8e7ff45c5378c3a3406ba94dc0653afa5d28c072203617c598caefaaf1bafcfb" + "hash": "b49b1eaf58e62063c7a03039d0c36e65991b1d21a3306390fb1c7ca38babafe3" } diff --git a/backend/.sqlx/query-b57a188ca137162a2848ebf81fa3aeca9a14ac628c61a358e2c6612c57249b0f.json b/backend/.sqlx/query-b57a188ca137162a2848ebf81fa3aeca9a14ac628c61a358e2c6612c57249b0f.json new file mode 100644 index 0000000000..a730d4b588 --- /dev/null +++ b/backend/.sqlx/query-b57a188ca137162a2848ebf81fa3aeca9a14ac628c61a358e2c6612c57249b0f.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1 AND path = $2)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "b57a188ca137162a2848ebf81fa3aeca9a14ac628c61a358e2c6612c57249b0f" +} diff --git a/backend/.sqlx/query-b64c7f3b483c74c51aecda65664c36d9686112182dbf35651e494da739b922f9.json b/backend/.sqlx/query-b64c7f3b483c74c51aecda65664c36d9686112182dbf35651e494da739b922f9.json deleted file mode 100644 index 948e713ef6..0000000000 --- a/backend/.sqlx/query-b64c7f3b483c74c51aecda65664c36d9686112182dbf35651e494da739b922f9.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE queue\n SET flow_status = JSONB_SET(\n JSONB_SET(flow_status, ARRAY['modules', $1::TEXT], $2), ARRAY['step'], $3)\n WHERE id = $4", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Jsonb", - "Jsonb", - "Uuid" - ] - }, - "nullable": [] - }, - "hash": "b64c7f3b483c74c51aecda65664c36d9686112182dbf35651e494da739b922f9" -} diff --git a/backend/.sqlx/query-b8d392ccfcccafe0c19511b3567bc11779b1052b0948c410468a8aeba1d26d33.json b/backend/.sqlx/query-b8d392ccfcccafe0c19511b3567bc11779b1052b0948c410468a8aeba1d26d33.json index fc91f7103d..c403f6a428 100644 --- a/backend/.sqlx/query-b8d392ccfcccafe0c19511b3567bc11779b1052b0948c410468a8aeba1d26d33.json +++ b/backend/.sqlx/query-b8d392ccfcccafe0c19511b3567bc11779b1052b0948c410468a8aeba1d26d33.json @@ -32,6 +32,11 @@ "ordinal": 5, "name": "created_by", "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "format_extension", + "type_info": "Varchar" } ], "parameters": { @@ -45,6 +50,7 @@ true, true, true, + true, true ] }, diff --git a/backend/.sqlx/query-c060b8bbc5af7d2e7d0aaff64f0f62ec9db58611a99b0ba7f0375638b128ab89.json b/backend/.sqlx/query-c060b8bbc5af7d2e7d0aaff64f0f62ec9db58611a99b0ba7f0375638b128ab89.json new file mode 100644 index 0000000000..1a37220559 --- /dev/null +++ b/backend/.sqlx/query-c060b8bbc5af7d2e7d0aaff64f0f62ec9db58611a99b0ba7f0375638b128ab89.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT schedule FROM schedule WHERE path = $1 AND script_path = $1 AND is_flow = $2 AND workspace_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "schedule", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c060b8bbc5af7d2e7d0aaff64f0f62ec9db58611a99b0ba7f0375638b128ab89" +} diff --git a/backend/.sqlx/query-c14009d133956710f4435a5984c18b9517e256978512f014e1bf5c270f499772.json b/backend/.sqlx/query-c14009d133956710f4435a5984c18b9517e256978512f014e1bf5c270f499772.json new file mode 100644 index 0000000000..7e9e9b84aa --- /dev/null +++ b/backend/.sqlx/query-c14009d133956710f4435a5984c18b9517e256978512f014e1bf5c270f499772.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(flow_status, ARRAY['preprocessor_module'], $1)\n WHERE id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "c14009d133956710f4435a5984c18b9517e256978512f014e1bf5c270f499772" +} diff --git a/backend/.sqlx/query-c1ceb03e0eafd2e494c06cef1ec96f78c2cfd42ed7d1ca6cfd35288b561120db.json b/backend/.sqlx/query-c1ceb03e0eafd2e494c06cef1ec96f78c2cfd42ed7d1ca6cfd35288b561120db.json new file mode 100644 index 0000000000..d1a89a6ad6 --- /dev/null +++ b/backend/.sqlx/query-c1ceb03e0eafd2e494c06cef1ec96f78c2cfd42ed7d1ca6cfd35288b561120db.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT healthy, created_at FROM healthchecks WHERE check_type = 'min_alive_workers_' || $1 AND created_at > NOW() - INTERVAL '24 hours' ORDER BY created_at DESC", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "healthy", + "type_info": "Bool" + }, + { + "ordinal": 1, + "name": "created_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "c1ceb03e0eafd2e494c06cef1ec96f78c2cfd42ed7d1ca6cfd35288b561120db" +} diff --git a/backend/.sqlx/query-c1de24c68933ab35934395d74c5d2747b3da80c96e255ccf0c4e053206a9ad1b.json b/backend/.sqlx/query-c1de24c68933ab35934395d74c5d2747b3da80c96e255ccf0c4e053206a9ad1b.json deleted file mode 100644 index a690ad155e..0000000000 --- a/backend/.sqlx/query-c1de24c68933ab35934395d74c5d2747b3da80c96e255ccf0c4e053206a9ad1b.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2, occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, current_job_id = NULL, current_job_workspace_id = NULL, vcpus = COALESCE($7, vcpus), memory = COALESCE($8, memory) WHERE worker = $6", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int4", - "TextArray", - "Float4", - "Int8", - "Int8", - "Text", - "Int8", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "c1de24c68933ab35934395d74c5d2747b3da80c96e255ccf0c4e053206a9ad1b" -} diff --git a/backend/.sqlx/query-c229744534f17f7622c3dee21bb1e7292ff17e6dffe58e80e53bff8baade07c8.json b/backend/.sqlx/query-c229744534f17f7622c3dee21bb1e7292ff17e6dffe58e80e53bff8baade07c8.json new file mode 100644 index 0000000000..df94d893a6 --- /dev/null +++ b/backend/.sqlx/query-c229744534f17f7622c3dee21bb1e7292ff17e6dffe58e80e53bff8baade07c8.json @@ -0,0 +1,37 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO http_trigger (workspace_id, path, route_path, route_path_key, script_path, is_flow, is_async, requires_auth, http_method, edited_by, email, edited_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, now())", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Bool", + "Bool", + { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + }, + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "c229744534f17f7622c3dee21bb1e7292ff17e6dffe58e80e53bff8baade07c8" +} diff --git a/backend/.sqlx/query-c3b5abbf2c9079d597a55f7c63bc83b8b4da98bda204a40f045a62172cfb4ebb.json b/backend/.sqlx/query-c3b5abbf2c9079d597a55f7c63bc83b8b4da98bda204a40f045a62172cfb4ebb.json new file mode 100644 index 0000000000..b545c48599 --- /dev/null +++ b/backend/.sqlx/query-c3b5abbf2c9079d597a55f7c63bc83b8b4da98bda204a40f045a62172cfb4ebb.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT tag as \"tag!\", COUNT(*) as \"count!\"\n FROM completed_job\n WHERE started_at > NOW() - make_interval(secs => $1) AND ($2::text IS NULL OR workspace_id = $2)\n GROUP BY tag\n ORDER BY \"count!\" DESC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "tag!", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "count!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Float8", + "Text" + ] + }, + "nullable": [ + false, + null + ] + }, + "hash": "c3b5abbf2c9079d597a55f7c63bc83b8b4da98bda204a40f045a62172cfb4ebb" +} diff --git a/backend/.sqlx/query-c4e1873bfc7b905e7299a021f4baa2a97e95f4797c5e11f37822e19828422b7e.json b/backend/.sqlx/query-c4e1873bfc7b905e7299a021f4baa2a97e95f4797c5e11f37822e19828422b7e.json new file mode 100644 index 0000000000..d3c16a5275 --- /dev/null +++ b/backend/.sqlx/query-c4e1873bfc7b905e7299a021f4baa2a97e95f4797c5e11f37822e19828422b7e.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE concurrency_locks SET last_locked_at = NOW() WHERE id = $1 AND last_locked_at < NOW() - INTERVAL '1 second' * $2 RETURNING 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Float8" + ] + }, + "nullable": [ + null + ] + }, + "hash": "c4e1873bfc7b905e7299a021f4baa2a97e95f4797c5e11f37822e19828422b7e" +} diff --git a/backend/.sqlx/query-34ad8a2a5bd89b9b8e25847a7e5e94ef99e35a178ad6328c1bcde2a6d6f88cb5.json b/backend/.sqlx/query-c624f15f3e321b1eecf123da9bf0b18e8c1d16ef25ffb9d04e5447d0d583d55c.json similarity index 58% rename from backend/.sqlx/query-34ad8a2a5bd89b9b8e25847a7e5e94ef99e35a178ad6328c1bcde2a6d6f88cb5.json rename to backend/.sqlx/query-c624f15f3e321b1eecf123da9bf0b18e8c1d16ef25ffb9d04e5447d0d583d55c.json index 43d0f596ae..edb2fc7f49 100644 --- a/backend/.sqlx/query-34ad8a2a5bd89b9b8e25847a7e5e94ef99e35a178ad6328c1bcde2a6d6f88cb5.json +++ b/backend/.sqlx/query-c624f15f3e321b1eecf123da9bf0b18e8c1d16ef25ffb9d04e5447d0d583d55c.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO token\n (token, email, label, expiration, super_admin, scopes)\n VALUES ($1, $2, $3, $4, $5, $6)", + "query": "INSERT INTO token\n (token, email, label, expiration, super_admin, scopes, workspace_id)\n VALUES ($1, $2, $3, $4, $5, $6, $7)", "describe": { "columns": [], "parameters": { @@ -10,10 +10,11 @@ "Varchar", "Timestamptz", "Bool", - "TextArray" + "TextArray", + "Varchar" ] }, "nullable": [] }, - "hash": "34ad8a2a5bd89b9b8e25847a7e5e94ef99e35a178ad6328c1bcde2a6d6f88cb5" + "hash": "c624f15f3e321b1eecf123da9bf0b18e8c1d16ef25ffb9d04e5447d0d583d55c" } diff --git a/backend/.sqlx/query-c7ee7ce64686cef41cebd99ad7ef31572fc1bf12e6ae473fd58fafb025989965.json b/backend/.sqlx/query-c7ee7ce64686cef41cebd99ad7ef31572fc1bf12e6ae473fd58fafb025989965.json new file mode 100644 index 0000000000..7dd454bbbe --- /dev/null +++ b/backend/.sqlx/query-c7ee7ce64686cef41cebd99ad7ef31572fc1bf12e6ae473fd58fafb025989965.json @@ -0,0 +1,59 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT label, concat(substring(token for 10)) as token_prefix, expiration, created_at, last_used_at, scopes, email FROM token WHERE workspace_id = $1 AND scopes @> ARRAY['run:script/' || $2]::text[]", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "label", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "token_prefix", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "expiration", + "type_info": "Timestamptz" + }, + { + "ordinal": 3, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "last_used_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "scopes", + "type_info": "TextArray" + }, + { + "ordinal": 6, + "name": "email", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + true, + null, + true, + false, + false, + true, + true + ] + }, + "hash": "c7ee7ce64686cef41cebd99ad7ef31572fc1bf12e6ae473fd58fafb025989965" +} diff --git a/backend/.sqlx/query-cecf1addc4aecb087a14786b2a9165895ca61ef042947c7314f66514d7f29edc.json b/backend/.sqlx/query-cecf1addc4aecb087a14786b2a9165895ca61ef042947c7314f66514d7f29edc.json new file mode 100644 index 0000000000..361f5ebd78 --- /dev/null +++ b/backend/.sqlx/query-cecf1addc4aecb087a14786b2a9165895ca61ef042947c7314f66514d7f29edc.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT last_locked_at\n FROM concurrency_locks\n WHERE id = $1\n FOR UPDATE", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "last_locked_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "cecf1addc4aecb087a14786b2a9165895ca61ef042947c7314f66514d7f29edc" +} diff --git a/backend/.sqlx/query-cf1cef7e0fe2e7e3db96b0ec005360361b9eec023a6fc2a4a7a917f59d86af4d.json b/backend/.sqlx/query-cf1cef7e0fe2e7e3db96b0ec005360361b9eec023a6fc2a4a7a917f59d86af4d.json new file mode 100644 index 0000000000..2556ac5580 --- /dev/null +++ b/backend/.sqlx/query-cf1cef7e0fe2e7e3db96b0ec005360361b9eec023a6fc2a4a7a917f59d86af4d.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT name, format_extension FROM resource_type WHERE format_extension IS NOT NULL AND (workspace_id = $1 OR workspace_id = 'admins')", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "format_extension", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + true + ] + }, + "hash": "cf1cef7e0fe2e7e3db96b0ec005360361b9eec023a6fc2a4a7a917f59d86af4d" +} diff --git a/backend/.sqlx/query-d0df57fc4cd0be7b541dee081ffbe86b869b01ca1ab10aa17634bb6dae879f12.json b/backend/.sqlx/query-d0df57fc4cd0be7b541dee081ffbe86b869b01ca1ab10aa17634bb6dae879f12.json deleted file mode 100644 index 29227c3d8c..0000000000 --- a/backend/.sqlx/query-d0df57fc4cd0be7b541dee081ffbe86b869b01ca1ab10aa17634bb6dae879f12.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE queue\n SET last_ping = null\n WHERE id = $1", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid" - ] - }, - "nullable": [] - }, - "hash": "d0df57fc4cd0be7b541dee081ffbe86b869b01ca1ab10aa17634bb6dae879f12" -} diff --git a/backend/.sqlx/query-d54840373df5da9662ed11ed0a605cddac517bdc06dca0a8be071330338e948a.json b/backend/.sqlx/query-d54840373df5da9662ed11ed0a605cddac517bdc06dca0a8be071330338e948a.json new file mode 100644 index 0000000000..5b298f8db3 --- /dev/null +++ b/backend/.sqlx/query-d54840373df5da9662ed11ed0a605cddac517bdc06dca0a8be071330338e948a.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM websocket_trigger WHERE workspace_id = $1 AND path = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "d54840373df5da9662ed11ed0a605cddac517bdc06dca0a8be071330338e948a" +} diff --git a/backend/.sqlx/query-d5a8614286c170e0d175903cd1b53ff66b37ed8110a0b67aedb9f25e6a7383e1.json b/backend/.sqlx/query-d5a8614286c170e0d175903cd1b53ff66b37ed8110a0b67aedb9f25e6a7383e1.json index 6d48bd9f44..164157b02f 100644 --- a/backend/.sqlx/query-d5a8614286c170e0d175903cd1b53ff66b37ed8110a0b67aedb9f25e6a7383e1.json +++ b/backend/.sqlx/query-d5a8614286c170e0d175903cd1b53ff66b37ed8110a0b67aedb9f25e6a7383e1.json @@ -76,7 +76,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-d600a0ad953ed131952d9c46deb8f65143894f86517f2b5b2d51bc9a2857695c.json b/backend/.sqlx/query-d600a0ad953ed131952d9c46deb8f65143894f86517f2b5b2d51bc9a2857695c.json new file mode 100644 index 0000000000..34afed8276 --- /dev/null +++ b/backend/.sqlx/query-d600a0ad953ed131952d9c46deb8f65143894f86517f2b5b2d51bc9a2857695c.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT (scalar_int)::int FROM job_stats WHERE job_id = $1 AND workspace_id = $2 AND metric_id = 'progress_perc'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "scalar_int", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Text" + ] + }, + "nullable": [ + true + ] + }, + "hash": "d600a0ad953ed131952d9c46deb8f65143894f86517f2b5b2d51bc9a2857695c" +} diff --git a/backend/.sqlx/query-ec47955683d811b12e82ff3e6aeafa0df46a320c436bad5eb1acc127df138a61.json b/backend/.sqlx/query-d697b7311430e7bd5375ec5494179f4071e3bfe123d9600249cfa80c1103edd8.json similarity index 51% rename from backend/.sqlx/query-ec47955683d811b12e82ff3e6aeafa0df46a320c436bad5eb1acc127df138a61.json rename to backend/.sqlx/query-d697b7311430e7bd5375ec5494179f4071e3bfe123d9600249cfa80c1103edd8.json index 2ed5e047db..e35c4e2730 100644 --- a/backend/.sqlx/query-ec47955683d811b12e82ff3e6aeafa0df46a320c436bad5eb1acc127df138a61.json +++ b/backend/.sqlx/query-d697b7311430e7bd5375ec5494179f4071e3bfe123d9600249cfa80c1103edd8.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE script SET lock = $1, created_at = now() WHERE hash = $2 AND workspace_id = $3", + "query": "UPDATE script SET lock = $1 WHERE hash = $2 AND workspace_id = $3", "describe": { "columns": [], "parameters": { @@ -12,5 +12,5 @@ }, "nullable": [] }, - "hash": "ec47955683d811b12e82ff3e6aeafa0df46a320c436bad5eb1acc127df138a61" + "hash": "d697b7311430e7bd5375ec5494179f4071e3bfe123d9600249cfa80c1103edd8" } diff --git a/backend/.sqlx/query-d6c25421bb6513908697ebe74c159da0ef78b5252b6ac669a3c9e545d05c0d43.json b/backend/.sqlx/query-d6c25421bb6513908697ebe74c159da0ef78b5252b6ac669a3c9e545d05c0d43.json deleted file mode 100644 index 7d7274d774..0000000000 --- a/backend/.sqlx/query-d6c25421bb6513908697ebe74c159da0ef78b5252b6ac669a3c9e545d05c0d43.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE queue\n SET flow_status = JSONB_SET(flow_status, ARRAY['modules', $1::TEXT, 'iterator', 'index'], ((flow_status->'modules'->$1::int->'iterator'->>'index')::int + 1)::text::jsonb)\n WHERE id = $2\n RETURNING (flow_status->'modules'->$1::int->'iterator'->>'index')::int", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "int4", - "type_info": "Int4" - } - ], - "parameters": { - "Left": [ - "Int4", - "Uuid" - ] - }, - "nullable": [ - null - ] - }, - "hash": "d6c25421bb6513908697ebe74c159da0ef78b5252b6ac669a3c9e545d05c0d43" -} diff --git a/backend/.sqlx/query-d7a0f19f9e18d2ea49316012375ad78b69292ba091d69880945e42bebe890d66.json b/backend/.sqlx/query-d7a0f19f9e18d2ea49316012375ad78b69292ba091d69880945e42bebe890d66.json new file mode 100644 index 0000000000..f619796a27 --- /dev/null +++ b/backend/.sqlx/query-d7a0f19f9e18d2ea49316012375ad78b69292ba091d69880945e42bebe890d66.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM token WHERE label LIKE 'webhook-%' AND workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "d7a0f19f9e18d2ea49316012375ad78b69292ba091d69880945e42bebe890d66" +} diff --git a/backend/.sqlx/query-db24f1f6ef1e26b7de7926bd3f32d1fa673c4970c25ff9ad98f0fdf199801b53.json b/backend/.sqlx/query-db24f1f6ef1e26b7de7926bd3f32d1fa673c4970c25ff9ad98f0fdf199801b53.json new file mode 100644 index 0000000000..70f4b91b71 --- /dev/null +++ b/backend/.sqlx/query-db24f1f6ef1e26b7de7926bd3f32d1fa673c4970c25ff9ad98f0fdf199801b53.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "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!\"", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "websocket_used!", + "type_info": "Bool" + }, + { + "ordinal": 1, + "name": "http_routes_used!", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "db24f1f6ef1e26b7de7926bd3f32d1fa673c4970c25ff9ad98f0fdf199801b53" +} diff --git a/backend/.sqlx/query-dc9a906d6c6156a84fccf4e3a2a7c08d8ed4984409b669162f0a1fc1aa48e188.json b/backend/.sqlx/query-dc9a906d6c6156a84fccf4e3a2a7c08d8ed4984409b669162f0a1fc1aa48e188.json new file mode 100644 index 0000000000..03b0c561e1 --- /dev/null +++ b/backend/.sqlx/query-dc9a906d6c6156a84fccf4e3a2a7c08d8ed4984409b669162f0a1fc1aa48e188.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM http_trigger WHERE workspace_id = $1 AND path = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "dc9a906d6c6156a84fccf4e3a2a7c08d8ed4984409b669162f0a1fc1aa48e188" +} diff --git a/backend/.sqlx/query-dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9.json b/backend/.sqlx/query-dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9.json new file mode 100644 index 0000000000..bb8d339e55 --- /dev/null +++ b/backend/.sqlx/query-dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9.json @@ -0,0 +1,23 @@ +{ + "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-95cb1fe8658f98fb736d899fa21cd7378b0c9d3b5f3d6bd6cafcba273f8277d4.json b/backend/.sqlx/query-e968e879d3c52f7dd502c3cd15fc8fbd983a4a3ab25648c562497a27c74b5c8c.json similarity index 50% rename from backend/.sqlx/query-95cb1fe8658f98fb736d899fa21cd7378b0c9d3b5f3d6bd6cafcba273f8277d4.json rename to backend/.sqlx/query-e968e879d3c52f7dd502c3cd15fc8fbd983a4a3ab25648c562497a27c74b5c8c.json index 991be7c977..3bacda16d9 100644 --- a/backend/.sqlx/query-95cb1fe8658f98fb736d899fa21cd7378b0c9d3b5f3d6bd6cafcba273f8277d4.json +++ b/backend/.sqlx/query-e968e879d3c52f7dd502c3cd15fc8fbd983a4a3ab25648c562497a27c74b5c8c.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 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": { @@ -9,10 +9,14 @@ "Varchar", "Int8", "Int8", - "Text" + "Text", + "Float4", + "Float4", + "Float4", + "Float4" ] }, "nullable": [] }, - "hash": "95cb1fe8658f98fb736d899fa21cd7378b0c9d3b5f3d6bd6cafcba273f8277d4" + "hash": "e968e879d3c52f7dd502c3cd15fc8fbd983a4a3ab25648c562497a27c74b5c8c" } diff --git a/backend/.sqlx/query-eb1f7f01461f5a7540c273b37e5d578c31cf151ab3ef813f7aada76533761e12.json b/backend/.sqlx/query-eb1f7f01461f5a7540c273b37e5d578c31cf151ab3ef813f7aada76533761e12.json index cd523b4c22..73c1fd7b2c 100644 --- a/backend/.sqlx/query-eb1f7f01461f5a7540c273b37e5d578c31cf151ab3ef813f7aada76533761e12.json +++ b/backend/.sqlx/query-eb1f7f01461f5a7540c273b37e5d578c31cf151ab3ef813f7aada76533761e12.json @@ -32,6 +32,11 @@ "ordinal": 5, "name": "created_by", "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "format_extension", + "type_info": "Varchar" } ], "parameters": { @@ -43,6 +48,7 @@ true, true, true, + true, true ] }, diff --git a/backend/.sqlx/query-eb932b613a6dbb2cdff97e5512d42b538ba83115c0ea798be00b01659600f45a.json b/backend/.sqlx/query-eb932b613a6dbb2cdff97e5512d42b538ba83115c0ea798be00b01659600f45a.json new file mode 100644 index 0000000000..7717a34760 --- /dev/null +++ b/backend/.sqlx/query-eb932b613a6dbb2cdff97e5512d42b538ba83115c0ea798be00b01659600f45a.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM healthchecks WHERE check_type = $1 AND healthy = false)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "eb932b613a6dbb2cdff97e5512d42b538ba83115c0ea798be00b01659600f45a" +} diff --git a/backend/.sqlx/query-eff32aeac25a75d06f73e08c26dd3fd25f6b85cbea870505751c6a82457ae1da.json b/backend/.sqlx/query-eff32aeac25a75d06f73e08c26dd3fd25f6b85cbea870505751c6a82457ae1da.json new file mode 100644 index 0000000000..2190ea06eb --- /dev/null +++ b/backend/.sqlx/query-eff32aeac25a75d06f73e08c26dd3fd25f6b85cbea870505751c6a82457ae1da.json @@ -0,0 +1,59 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT label, concat(substring(token for 10)) as token_prefix, expiration, created_at, last_used_at, scopes, email FROM token WHERE workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "label", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "token_prefix", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "expiration", + "type_info": "Timestamptz" + }, + { + "ordinal": 3, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "last_used_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "scopes", + "type_info": "TextArray" + }, + { + "ordinal": 6, + "name": "email", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + true, + null, + true, + false, + false, + true, + true + ] + }, + "hash": "eff32aeac25a75d06f73e08c26dd3fd25f6b85cbea870505751c6a82457ae1da" +} diff --git a/backend/.sqlx/query-f06e0e4fa358b26792df22fff48b71a6fcfa1e5603ea472892917c1accd1aafb.json b/backend/.sqlx/query-f06e0e4fa358b26792df22fff48b71a6fcfa1e5603ea472892917c1accd1aafb.json new file mode 100644 index 0000000000..71cdfe60bf --- /dev/null +++ b/backend/.sqlx/query-f06e0e4fa358b26792df22fff48b71a6fcfa1e5603ea472892917c1accd1aafb.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM token WHERE label LIKE 'email-%' AND workspace_id = $1 AND scopes @> ARRAY['run:script/' || $2]::text[]", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "f06e0e4fa358b26792df22fff48b71a6fcfa1e5603ea472892917c1accd1aafb" +} diff --git a/backend/.sqlx/query-f2baee15e6d1fecd6d2d7b39fda1b50a15ec8bd349f1081af54da5dc2f5e3021.json b/backend/.sqlx/query-f2baee15e6d1fecd6d2d7b39fda1b50a15ec8bd349f1081af54da5dc2f5e3021.json new file mode 100644 index 0000000000..2e75b4e74b --- /dev/null +++ b/backend/.sqlx/query-f2baee15e6d1fecd6d2d7b39fda1b50a15ec8bd349f1081af54da5dc2f5e3021.json @@ -0,0 +1,101 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT *\n FROM websocket_trigger\n WHERE workspace_id = $1 AND path = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "url", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 4, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "server_id", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "last_server_ping", + "type_info": "Timestamptz" + }, + { + "ordinal": 11, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 12, + "name": "enabled", + "type_info": "Bool" + }, + { + "ordinal": 13, + "name": "filters", + "type_info": "JsonbArray" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false + ] + }, + "hash": "f2baee15e6d1fecd6d2d7b39fda1b50a15ec8bd349f1081af54da5dc2f5e3021" +} diff --git a/backend/.sqlx/query-f916ec232837ece9323675e5f5142e7285f4266a1471e5ffdefadf421a67e44b.json b/backend/.sqlx/query-f916ec232837ece9323675e5f5142e7285f4266a1471e5ffdefadf421a67e44b.json new file mode 100644 index 0000000000..2cf1fb31e9 --- /dev/null +++ b/backend/.sqlx/query-f916ec232837ece9323675e5f5142e7285f4266a1471e5ffdefadf421a67e44b.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(\n JSONB_SET(flow_status, ARRAY['modules', $1::TEXT, 'flow_jobs_success', $3::TEXT], $4),\n ARRAY['modules', $1::TEXT, 'iterator', 'index'],\n ((flow_status->'modules'->$1::int->'iterator'->>'index')::int + 1)::text::jsonb\n ),\n last_ping = NULL\n WHERE id = $2\n RETURNING (flow_status->'modules'->$1::int->'iterator'->>'index')::int", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "int4", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4", + "Uuid", + "Text", + "Jsonb" + ] + }, + "nullable": [ + null + ] + }, + "hash": "f916ec232837ece9323675e5f5142e7285f4266a1471e5ffdefadf421a67e44b" +} diff --git a/backend/.sqlx/query-f80e94176224ef23416da99b26ad5c330d65016fb93345b054cbb63a4bf37fc8.json b/backend/.sqlx/query-f9e0e35b4789a4da89f7bb21fa6b250fd64ee0e0b299471979db5ff8ee906929.json similarity index 74% rename from backend/.sqlx/query-f80e94176224ef23416da99b26ad5c330d65016fb93345b054cbb63a4bf37fc8.json rename to backend/.sqlx/query-f9e0e35b4789a4da89f7bb21fa6b250fd64ee0e0b299471979db5ff8ee906929.json index a0a4a3770c..39c96b8989 100644 --- a/backend/.sqlx/query-f80e94176224ef23416da99b26ad5c330d65016fb93345b054cbb63a4bf37fc8.json +++ b/backend/.sqlx/query-f9e0e35b4789a4da89f7bb21fa6b250fd64ee0e0b299471979db5ff8ee906929.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT (flow_status->'step')::integer as step, jsonb_array_length(flow_status->'modules') as len FROM queue WHERE id = $1", + "query": "SELECT (flow_status->'step')::integer as step, jsonb_array_length(flow_status->'modules') as len FROM queue WHERE id = $1", "describe": { "columns": [ { @@ -24,5 +24,5 @@ null ] }, - "hash": "f80e94176224ef23416da99b26ad5c330d65016fb93345b054cbb63a4bf37fc8" + "hash": "f9e0e35b4789a4da89f7bb21fa6b250fd64ee0e0b299471979db5ff8ee906929" } diff --git a/backend/.sqlx/query-fb581eb6f883ebb5909a00c65a6e1217f088290fce0e052171230bcd88f945b9.json b/backend/.sqlx/query-fb581eb6f883ebb5909a00c65a6e1217f088290fce0e052171230bcd88f945b9.json new file mode 100644 index 0000000000..b3f640dd76 --- /dev/null +++ b/backend/.sqlx/query-fb581eb6f883ebb5909a00c65a6e1217f088290fce0e052171230bcd88f945b9.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO global_settings (name, value) VALUES ('slack', $1) ON CONFLICT (name) DO UPDATE SET value = $1, updated_at = now()", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "fb581eb6f883ebb5909a00c65a6e1217f088290fce0e052171230bcd88f945b9" +} diff --git a/backend/.sqlx/query-e1c715020f1efb00123171edfb6173bfeaaa95d4f870240e42b76e5df304ce99.json b/backend/.sqlx/query-fc7ac95d8d5f4532a2b0e50f84c1e273d25543401639a68f868e1e4fd8b0640a.json similarity index 80% rename from backend/.sqlx/query-e1c715020f1efb00123171edfb6173bfeaaa95d4f870240e42b76e5df304ce99.json rename to backend/.sqlx/query-fc7ac95d8d5f4532a2b0e50f84c1e273d25543401639a68f868e1e4fd8b0640a.json index 9d5cfdf5af..5e4f522147 100644 --- a/backend/.sqlx/query-e1c715020f1efb00123171edfb6173bfeaaa95d4f870240e42b76e5df304ce99.json +++ b/backend/.sqlx/query-fc7ac95d8d5f4532a2b0e50f84c1e273d25543401639a68f868e1e4fd8b0640a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "select hash, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, cache_ttl, language as \"language: ScriptLang\", dedicated_worker, priority, delete_after_use, timeout from script where path = $1 AND workspace_id = $2 AND\n created_at = (SELECT max(created_at) FROM script WHERE path = $1 AND workspace_id = $2 AND\n deleted = false AND lock IS not NULL AND lock_error_logs IS NULL)", + "query": "select hash, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, cache_ttl, language as \"language: ScriptLang\", dedicated_worker, priority, delete_after_use, timeout, has_preprocessor from script where path = $1 AND workspace_id = $2 AND\n created_at = (SELECT max(created_at) FROM script WHERE path = $1 AND workspace_id = $2 AND\n deleted = false AND lock IS not NULL AND lock_error_logs IS NULL)", "describe": { "columns": [ { @@ -55,7 +55,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } @@ -80,6 +82,11 @@ "ordinal": 10, "name": "timeout", "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "has_preprocessor", + "type_info": "Bool" } ], "parameters": { @@ -99,8 +106,9 @@ true, true, true, + true, true ] }, - "hash": "e1c715020f1efb00123171edfb6173bfeaaa95d4f870240e42b76e5df304ce99" + "hash": "fc7ac95d8d5f4532a2b0e50f84c1e273d25543401639a68f868e1e4fd8b0640a" } diff --git a/backend/.sqlx/query-fe4f91ca7e179e58041a5c0b1a36015175e9301c01a99e8f2b82cb853349a183.json b/backend/.sqlx/query-fe4f91ca7e179e58041a5c0b1a36015175e9301c01a99e8f2b82cb853349a183.json new file mode 100644 index 0000000000..65cb5c6633 --- /dev/null +++ b/backend/.sqlx/query-fe4f91ca7e179e58041a5c0b1a36015175e9301c01a99e8f2b82cb853349a183.json @@ -0,0 +1,87 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, http_method as \"http_method: _\" FROM http_trigger", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 3, + "name": "route_path", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "is_async", + "type_info": "Bool" + }, + { + "ordinal": 6, + "name": "requires_auth", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 9, + "name": "http_method: _", + "type_info": { + "Custom": { + "name": "http_method", + "kind": { + "Enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + } + } + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "fe4f91ca7e179e58041a5c0b1a36015175e9301c01a99e8f2b82cb853349a183" +} diff --git a/backend/.sqlx/query-febd70e6d5304ad912c232d3d8fc3f8ce0133d8a1a9e5ca1124eff9a988dc2d7.json b/backend/.sqlx/query-febd70e6d5304ad912c232d3d8fc3f8ce0133d8a1a9e5ca1124eff9a988dc2d7.json new file mode 100644 index 0000000000..7958f9d2f3 --- /dev/null +++ b/backend/.sqlx/query-febd70e6d5304ad912c232d3d8fc3f8ce0133d8a1a9e5ca1124eff9a988dc2d7.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE websocket_trigger SET last_server_ping = now(), error = $1 WHERE workspace_id = $2 AND path = $3 AND server_id = $4 AND enabled IS TRUE RETURNING 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "febd70e6d5304ad912c232d3d8fc3f8ce0133d8a1a9e5ca1124eff9a988dc2d7" +} diff --git a/backend/.sqlx/query-d249343a1d9fce2f7ca9e6e447eb32d7d11b61acdab80dda24db4a9ba3e1f7e6.json b/backend/.sqlx/query-ffedbb3a2676a6d7b71f81f89109a02a8dba90d40144e942527f8a3fc36dfbc1.json similarity index 57% rename from backend/.sqlx/query-d249343a1d9fce2f7ca9e6e447eb32d7d11b61acdab80dda24db4a9ba3e1f7e6.json rename to backend/.sqlx/query-ffedbb3a2676a6d7b71f81f89109a02a8dba90d40144e942527f8a3fc36dfbc1.json index a3cd9e0c30..c58dfad63a 100644 --- a/backend/.sqlx/query-d249343a1d9fce2f7ca9e6e447eb32d7d11b61acdab80dda24db4a9ba3e1f7e6.json +++ b/backend/.sqlx/query-ffedbb3a2676a6d7b71f81f89109a02a8dba90d40144e942527f8a3fc36dfbc1.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO resource_type\n (workspace_id, name, schema, description, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, now())", + "query": "INSERT INTO resource_type\n (workspace_id, name, schema, description, created_by, format_extension, edited_at)\n VALUES ($1, $2, $3, $4, $5, $6, now())", "describe": { "columns": [], "parameters": { @@ -9,10 +9,11 @@ "Varchar", "Jsonb", "Text", + "Varchar", "Varchar" ] }, "nullable": [] }, - "hash": "d249343a1d9fce2f7ca9e6e447eb32d7d11b61acdab80dda24db4a9ba3e1f7e6" + "hash": "ffedbb3a2676a6d7b71f81f89109a02a8dba90d40144e942527f8a3fc36dfbc1" } diff --git a/backend/Cargo.lock b/backend/Cargo.lock index a553da04f0..d12b1b2698 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -27,6 +27,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aes" version = "0.7.5" @@ -34,22 +40,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher 0.3.0", + "cipher", "cpufeatures", "opaque-debug", ] -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher 0.4.4", - "cpufeatures", -] - [[package]] name = "ahash" version = "0.7.8" @@ -122,9 +117,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" dependencies = [ "anstyle", "anstyle-parse", @@ -137,43 +132,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" [[package]] name = "arc-swap" @@ -181,19 +176,6 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" -[[package]] -name = "archiver-rs" -version = "0.5.1" -source = "git+https://github.com/gz/archiver-rs.git?branch=patch-1#a73cef92c2a5b8f48c2a4a9e889952072e03b4b7" -dependencies = [ - "bzip2", - "flate2", - "tar", - "thiserror", - "xz2", - "zip", -] - [[package]] name = "argon2" version = "0.5.3" @@ -203,7 +185,7 @@ dependencies = [ "base64ct", "blake2", "cpufeatures", - "password-hash 0.5.0", + "password-hash", ] [[package]] @@ -223,15 +205,15 @@ checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "arrow" @@ -280,7 +262,7 @@ dependencies = [ "arrow-data", "arrow-schema", "chrono", - "chrono-tz", + "chrono-tz 0.9.0", "half", "hashbrown 0.14.5", "num", @@ -377,7 +359,7 @@ dependencies = [ "arrow-schema", "chrono", "half", - "indexmap 2.4.0", + "indexmap 2.6.0", "lexical-core", "num", "serde", @@ -447,7 +429,7 @@ dependencies = [ "memchr", "num", "regex", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -459,7 +441,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -504,11 +486,11 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.12" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" dependencies = [ - "brotli", + "brotli 7.0.0", "bzip2", "flate2", "futures-core", @@ -523,14 +505,14 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.0", - "futures-lite 2.3.0", + "fastrand 2.1.1", + "futures-lite 2.4.0", "slab", ] @@ -542,61 +524,32 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io", + "async-lock", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "once_cell", ] -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - [[package]] name = "async-io" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ - "async-lock 3.4.0", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "parking", - "polling 3.7.3", - "rustix 0.38.34", + "polling", + "rustix", "slab", "tracing", "windows-sys 0.59.0", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.4.0" @@ -618,7 +571,7 @@ dependencies = [ "bytes", "http 1.1.0", "rand 0.8.5", - "reqwest 0.12.5", + "reqwest 0.12.9", "serde", "serde-aux", "serde_json", @@ -635,24 +588,24 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "async-std" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-channel 1.9.0", "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io", + "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 1.13.0", + "futures-lite 2.4.0", "gloo-timers", "kv-log-macro", "log", @@ -666,9 +619,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -677,27 +630,27 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "async-stripe" -version = "0.34.1" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109605d984dd71a9a278e2d43a2831a20e80f25c3bcc25174096d12352cfc469" +checksum = "58d670cf4d47a1b8ffef54286a5625382e360a34ee76902fd93ad8c7032a0c30" dependencies = [ "chrono", "futures-util", "hex", "hmac", "http-types", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-tls 0.5.0", "serde", "serde_json", @@ -719,13 +672,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -773,15 +726,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.5.5" +version = "1.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e95816a168520d72c0e7680c405a5a8c1fb6a035b4bc4b9d7b0de8e1a941697" +checksum = "2d6448cfb224dd6a9b9ac734f58622dd0d4751f3589f3b777345745f46b2eb14" dependencies = [ "aws-credential-types", "aws-runtime", @@ -796,7 +749,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "hex", "http 0.2.12", "ring 0.17.8", @@ -809,9 +762,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16838e6c9e12125face1c1eff1343c75e3ff540de98ff7ebd61874a89bcfeb9" +checksum = "60e8f6b615cb5fc60a98132268508ad104310f0cfb25a1c22eee76efdf9154da" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -821,33 +774,34 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.4.0" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f42c2d4218de4dcd890a109461e2f799a1a2ba3bcd2cde9af88360f5df9266c6" +checksum = "a10d5c055aa540164d9561a0e2e74ad30f0dcf7393c3a92f6733ddf9c5762468" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", "aws-smithy-http", + "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "http 0.2.12", "http-body 0.4.6", "once_cell", "percent-encoding", "pin-project-lite", "tracing", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] name = "aws-sdk-sso" -version = "1.38.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca5e0b9fb285638f1007e9d961d963b9e504ab968fe5a3807cce94070bd0ce3" +checksum = "ded855583fa1d22e88fe39fd6062b062376e50a8211989e07cf5e38d52eb3453" dependencies = [ "aws-credential-types", "aws-runtime", @@ -867,9 +821,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.39.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc3e48ec239bb734db029ceef83599f4c9b3ce5d25c961b5bcd3f031c15bed54" +checksum = "9177ea1192e6601ae16c7273385690d88a7ed386a00b74a6bc894d12103cd933" dependencies = [ "aws-credential-types", "aws-runtime", @@ -889,9 +843,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.38.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede095dfcc5c92b224813c24a82b65005a475c98d737e2726a898cf583e2e8bd" +checksum = "823ef553cf36713c97453e2ddff1eb8f62be7f4523544e2a5db64caf80100f0a" dependencies = [ "aws-credential-types", "aws-runtime", @@ -912,9 +866,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.3" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df1b0fa6be58efe9d4ccc257df0a53b89cd8909e86591a13ca54817c87517be" +checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -946,9 +900,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.60.9" +version = "0.60.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9cd0ae3d97daa0a2bf377a4d8e8e1362cae590c4a1aad0d40058ebca18eb91e" +checksum = "5c8bc3e8fdc6b8d07d976e301c02fe553f72a39b7a9fea820e023268467d7ab6" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", @@ -985,22 +939,22 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.6.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0abbf454960d0db2ad12684a1640120e7557294b0ff8e2f11236290a1b293225" +checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" dependencies = [ "aws-smithy-async", "aws-smithy-http", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "http-body 1.0.1", "httparse", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.24.2", "once_cell", "pin-project-lite", @@ -1029,9 +983,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.2" +version = "1.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cee7cadb433c781d3299b916fbf620fea813bf38f49db282fb6858141a05cc8" +checksum = "07c9cdc179e6afbf5d391ab08c85eac817b51c87e1892a5edb5f7bbdc64314b4" dependencies = [ "base64-simd 0.8.0", "bytes", @@ -1055,9 +1009,9 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.8" +version = "0.60.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d123fbc2a4adc3c301652ba8e149bf4bc1d1725affb9784eb20c953ace06bf55" +checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" dependencies = [ "xmlparser", ] @@ -1072,15 +1026,15 @@ dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "tracing", ] [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -1089,7 +1043,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "itoa", "matchit", @@ -1105,7 +1059,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower 0.4.13", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -1113,9 +1067,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -1126,7 +1080,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -1134,17 +1088,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.8.0", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -1204,9 +1158,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bb8" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10cf871f3ff2ce56432fddc2615ac7acc3aa22ca321f8fea800846fbb32f188" +checksum = "d89aabfae550a5c44b43ab941844ffcd2e993cb6900b342debf59e9ea74acdb8" dependencies = [ "async-trait", "futures-util", @@ -1216,18 +1170,18 @@ dependencies = [ [[package]] name = "better_scoped_tls" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794edcc9b3fb07bb4aecaa11f093fd45663b4feadb782d68303a2268bc2701de" +checksum = "297b153aa5e573b5863108a6ddc9d5c968bd0b20e75cc614ee9821d2f45679c7" dependencies = [ "scoped-tls", ] [[package]] name = "bigdecimal" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" +checksum = "8f850665a0385e070b64c38d2354e6c104c8479c59868d1e48a0c13ee2c7a1c1" dependencies = [ "autocfg", "libm", @@ -1247,9 +1201,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.4" +version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ "bitflags 2.6.0", "cexpr", @@ -1258,16 +1212,34 @@ dependencies = [ "lazy_static", "lazycell", "log", - "prettyplease 0.2.20", + "prettyplease 0.2.25", "proc-macro2", "quote", "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.74", + "syn 2.0.86", "which 4.4.2", ] +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.86", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -1330,15 +1302,15 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9ec96fe9a81b5e365f9db71fe00edc4fe4ca2cc7dcb7861f0603012a7caa210" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", - "constant_time_eq 0.3.0", + "constant_time_eq", ] [[package]] @@ -1367,7 +1339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" dependencies = [ "block-padding", - "cipher 0.3.0", + "cipher", ] [[package]] @@ -1385,7 +1357,7 @@ dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "piper", ] @@ -1409,7 +1381,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", "syn_derive", ] @@ -1424,6 +1396,17 @@ dependencies = [ "brotli-decompressor", ] +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + [[package]] name = "brotli-decompressor" version = "4.0.1" @@ -1458,6 +1441,9 @@ name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] [[package]] name = "bytecheck" @@ -1483,22 +1469,22 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -1509,9 +1495,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "bytes-utils" @@ -1613,9 +1599,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.13" +version = "1.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +checksum = "e3788d6ac30243803df38a3e9991cf37e41210232916d41a8222ae378f912624" dependencies = [ "jobserver", "libc", @@ -1671,7 +1657,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" dependencies = [ "chrono", - "chrono-tz-build", + "chrono-tz-build 0.3.0", + "phf", +] + +[[package]] +name = "chrono-tz" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" +dependencies = [ + "chrono", + "chrono-tz-build 0.4.0", "phf", ] @@ -1686,6 +1683,16 @@ dependencies = [ "phf_codegen", ] +[[package]] +name = "chrono-tz-build" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" +dependencies = [ + "parse-zoneinfo", + "phf_codegen", +] + [[package]] name = "cipher" version = "0.3.0" @@ -1695,16 +1702,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clang-sys" version = "1.8.1" @@ -1718,9 +1715,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -1728,9 +1725,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -1740,14 +1737,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -1767,9 +1764,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -1862,9 +1859,9 @@ dependencies = [ [[package]] name = "const_format" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" dependencies = [ "const_format_proc_macros", "konst", @@ -1872,9 +1869,9 @@ dependencies = [ [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" dependencies = [ "proc-macro2", "quote", @@ -1883,15 +1880,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.1.5" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "constant_time_eq" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -1953,9 +1944,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -2120,7 +2111,7 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "subtle", "zeroize", ] @@ -2133,7 +2124,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -2181,7 +2172,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -2203,7 +2194,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -2242,7 +2233,7 @@ dependencies = [ "arrow-array", "arrow-ipc", "arrow-schema", - "async-compression 0.4.12", + "async-compression 0.4.17", "async-trait", "bytes", "bzip2", @@ -2265,7 +2256,7 @@ dependencies = [ "glob", "half", "hashbrown 0.14.5", - "indexmap 2.4.0", + "indexmap 2.6.0", "itertools 0.12.1", "log", "num_cpus", @@ -2280,7 +2271,7 @@ dependencies = [ "tokio", "tokio-util", "url", - "uuid 1.10.0", + "uuid 1.11.0", "xz2", "zstd 0.13.2", ] @@ -2380,7 +2371,7 @@ dependencies = [ "regex", "sha2 0.10.8", "unicode-segmentation", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] @@ -2434,10 +2425,10 @@ dependencies = [ "datafusion-expr", "datafusion-physical-expr", "hashbrown 0.14.5", - "indexmap 2.4.0", + "indexmap 2.6.0", "itertools 0.12.1", "log", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2463,7 +2454,7 @@ dependencies = [ "half", "hashbrown 0.14.5", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "itertools 0.12.1", "log", "paste", @@ -2507,7 +2498,7 @@ dependencies = [ "futures", "half", "hashbrown 0.14.5", - "indexmap 2.4.0", + "indexmap 2.6.0", "itertools 0.12.1", "log", "once_cell", @@ -2547,16 +2538,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" dependencies = [ "serde", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] name = "deno_ast" -version = "0.40.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d08372522975cce97fe0efbe42fea508c76eea4421619de6d63baae32792f7d" +checksum = "b2b9d03b1bbeeecdac54367f075d572131736d06c5be3bc49037855bc5ab1bbb" dependencies = [ - "anyhow", "base64 0.21.7", "deno_media_type", "deno_terminal 0.1.1", @@ -2564,15 +2554,16 @@ dependencies = [ "once_cell", "percent-encoding", "serde", + "sourcemap 9.0.0", "swc_atoms", - "swc_common 0.34.4", + "swc_common", "swc_config", "swc_config_macro", - "swc_ecma_ast 0.115.1", + "swc_ecma_ast", "swc_ecma_codegen", "swc_ecma_codegen_macros", "swc_ecma_loader", - "swc_ecma_parser 0.146.12", + "swc_ecma_parser", "swc_ecma_transforms_base", "swc_ecma_transforms_classes", "swc_ecma_transforms_macros", @@ -2580,7 +2571,7 @@ dependencies = [ "swc_ecma_transforms_react", "swc_ecma_transforms_typescript", "swc_ecma_utils", - "swc_ecma_visit 0.101.0", + "swc_ecma_visit", "swc_eq_ignore_macros", "swc_macros_common", "swc_visit", @@ -2593,18 +2584,18 @@ dependencies = [ [[package]] name = "deno_console" -version = "0.163.0" +version = "0.171.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4eea4d3eeb96874c63fde5001d0242042957b600000f179af4ad3235a411139" +checksum = "144108c8bb93b1df2cda4583d9beb8cd4e18798d3e030af8b07d2c55c1e3259b" dependencies = [ "deno_core", ] [[package]] name = "deno_core" -version = "0.299.0" +version = "0.311.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428488cc6b392a199a159054da754f56a1fdc63ee03f16be2c21cbd22e936e7b" +checksum = "5e09bd55da542fa1fde753aff617c355b5d782e763ab2a19e4371a56d7844cac" dependencies = [ "anyhow", "bincode", @@ -2625,7 +2616,7 @@ dependencies = [ "serde_json", "serde_v8", "smallvec", - "sourcemap", + "sourcemap 8.0.1", "static_assertions", "tokio", "url", @@ -2640,9 +2631,9 @@ checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1" [[package]] name = "deno_fetch" -version = "0.187.0" +version = "0.195.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f11f1ca946366c42e7daaab0d747720710dbb11511d9bfce1b328dd71b58f87" +checksum = "8a91340a1d60cebe1392e4b6e1614709ab5fdcfc1f55842561e498d7ef9b2cb9" dependencies = [ "base64 0.21.7", "bytes", @@ -2651,14 +2642,15 @@ dependencies = [ "deno_permissions", "deno_tls", "dyn-clone", + "error_reporter", "http 1.1.0", "http-body-util", - "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper 1.5.0", + "hyper-rustls 0.27.3", "hyper-util", "ipnet", "percent-encoding", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "serde", "serde_json", "tokio", @@ -2666,7 +2658,7 @@ dependencies = [ "tokio-socks", "tokio-util", "tower 0.4.13", - "tower-http", + "tower-http 0.6.1", "tower-service", ] @@ -2690,15 +2682,15 @@ dependencies = [ "dlopen2", "dlopen2_derive", "once_cell", - "rustls-native-certs 0.7.1", - "rustls-pemfile 2.1.3", + "rustls-native-certs 0.7.3", + "rustls-pemfile 2.2.0", ] [[package]] name = "deno_net" -version = "0.155.0" +version = "0.163.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3f337ffe00186bc67f989f5ba2759418bb43e1352b045aa9e715e216c632dc" +checksum = "5b769fd37232a38bf15a3834c9da8cc99409b52d0cf4a936f3117744369f8063" dependencies = [ "deno_core", "deno_permissions", @@ -2714,31 +2706,44 @@ dependencies = [ [[package]] name = "deno_ops" -version = "0.175.0" +version = "0.187.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2b71759647722be6ae051919b75cb66b3dccafe61b53c75ad5a6fad9d0ee4a" +checksum = "e040fd4def8a67538fe38c9955fd970efc9f44284bd69d44f8992a456afd665d" dependencies = [ "proc-macro-rules", "proc-macro2", "quote", "strum 0.25.0", "strum_macros 0.25.3", - "syn 2.0.74", + "syn 2.0.86", "thiserror", ] [[package]] -name = "deno_permissions" -version = "0.23.0" +name = "deno_path_util" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e67d40735d56445409349cec3eafe25668814c7f3794158c62dfd1b147b13c" +checksum = "4889646c1ce8437a6fde3acb057fd7e2d039e62c61f5063fc125ed1ede114dc6" +dependencies = [ + "percent-encoding", + "thiserror", + "url", +] + +[[package]] +name = "deno_permissions" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1328c2d1d26cd066ba9d7d5fb3451081219e373342423f78d7a1b73bfac9849" dependencies = [ "deno_core", + "deno_path_util", "deno_terminal 0.2.0", "fqdn", "libc", "log", "once_cell", + "percent-encoding", "serde", "which 4.4.2", "winapi", @@ -2766,26 +2771,26 @@ dependencies = [ [[package]] name = "deno_tls" -version = "0.150.0" +version = "0.158.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b995ce6016bc4f05453c8632a9d42a58536c1cbb7ece09f1aa66dda3f8d474b" +checksum = "22a1abc6bd8af41aa2496ceceef94f4277092c781a9495c437327a17659553a2" dependencies = [ "deno_core", "deno_native_certs", - "rustls 0.23.12", - "rustls-pemfile 2.1.3", + "rustls 0.23.16", + "rustls-pemfile 2.2.0", "rustls-tokio-stream", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "serde", "tokio", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] name = "deno_unsync" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ee1607db298c8f12124b345a52d5f2f504a7504c9d535f1d8f07127b237010" +checksum = "2f36b4ef61a04ce201b925a5dffa90f88437d37fee4836c758470dd15ba7f05e" dependencies = [ "parking_lot", "tokio", @@ -2793,9 +2798,9 @@ dependencies = [ [[package]] name = "deno_url" -version = "0.163.0" +version = "0.171.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a05423871cf79fc0e73b9117b114045b7936a60b87a188b673a2b377a65eaa1" +checksum = "68eb6834d66ff13c19633b0e1b621292461b744858130b0a1c51f34a57ba1a03" dependencies = [ "deno_core", "urlpattern", @@ -2803,9 +2808,9 @@ dependencies = [ [[package]] name = "deno_web" -version = "0.194.0" +version = "0.202.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884761df6d0bbe2869a8bfb3f4437aef75686dcbedd82dd4d23d1e7b06d50b14" +checksum = "e0862246372f5b559b788aa07ca1b9385909d59630251156a54c4d2c5342d1eb" dependencies = [ "async-trait", "base64-simd 0.8.0", @@ -2817,14 +2822,14 @@ dependencies = [ "futures", "serde", "tokio", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] name = "deno_webidl" -version = "0.163.0" +version = "0.171.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564c240839f20b8808d0182a0c1a85428a92fb7fe6cc6ea256adda11ad08a8d" +checksum = "5e969b61b740479379eaf303a6900d11f162f9de610640398f89f0aa58abb7c4" dependencies = [ "deno_core", ] @@ -2901,8 +2906,8 @@ dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 2.0.74", + "rustc_version 0.4.1", + "syn 2.0.86", ] [[package]] @@ -2912,7 +2917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac41dd49fb554432020d52c875fc290e110113f864c6b1b525cd62c7e7747a5d" dependencies = [ "byteorder", - "cipher 0.3.0", + "cipher", "opaque-debug", ] @@ -2999,7 +3004,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -3028,16 +3033,16 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dprint-swc-ext" -version = "0.17.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b909f9f9b22a6265839887544dce97b0b8e2b2635abf622f45613deb3de63e0" +checksum = "0ba28c12892aadb751c2ba7001d8460faee4748a04b4edc51c7121cc67ee03db" dependencies = [ "num-bigint", "rustc-hash 1.1.0", "swc_atoms", - "swc_common 0.34.4", - "swc_ecma_ast 0.115.1", - "swc_ecma_parser 0.146.12", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", "text_lines", ] @@ -3148,14 +3153,14 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -3175,7 +3180,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -3194,6 +3199,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "error_reporter" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8" + [[package]] name = "esaxx-rs" version = "0.1.10" @@ -3249,9 +3260,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastdivide" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59668941c55e5c186b8b58c391629af56774ec768f73c08bbcd56f09348eb00b" +checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471" [[package]] name = "fastrand" @@ -3264,9 +3275,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "ff" @@ -3286,9 +3297,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", @@ -3309,25 +3320,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8add37afff2d4ffa83bc748a70b4b1370984f6980768554182424ef71447c35f" dependencies = [ "bitflags 1.3.2", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] name = "flate2" -version = "1.0.31" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "libz-sys", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", @@ -3340,6 +3351,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -3366,9 +3383,9 @@ dependencies = [ [[package]] name = "fqdn" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08b1eaa7dfddeab6036292995620bf0435712e619db6d7690605897e76975eb0" +checksum = "eb540cf7bc4fe6df9d8f7f0c974cfd0dce8ed4e9e8884e73433b503ee78b4e7d" [[package]] name = "from_variant" @@ -3378,59 +3395,63 @@ checksum = "32016f1242eb82af5474752d00fd8ebcd9004bd69b462b1c91de833972d08ed4" dependencies = [ "proc-macro2", "swc_macros_common", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "frunk" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a351b59e12f97b4176ee78497dff72e4276fb1ceb13e19056aca7fa0206287" +checksum = "874b6a17738fc273ec753618bac60ddaeac48cb1d7684c3e7bd472e57a28b817" dependencies = [ "frunk_core", "frunk_derives", "frunk_proc_macros", + "serde", ] [[package]] name = "frunk_core" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2469fab0bd07e64ccf0ad57a1438f63160c69b2e57f04a439653d68eb558d6" +checksum = "3529a07095650187788833d585c219761114005d5976185760cf794d265b6a5c" +dependencies = [ + "serde", +] [[package]] name = "frunk_derives" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fa992f1656e1707946bbba340ad244f0814009ef8c0118eb7b658395f19a2e" +checksum = "e99b8b3c28ae0e84b604c75f721c21dc77afb3706076af5e8216d15fd1deaae3" dependencies = [ "frunk_proc_macro_helpers", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "frunk_proc_macro_helpers" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b54add839292b743aeda6ebedbd8b11e93404f902c56223e51b9ec18a13d2c" +checksum = "05a956ef36c377977e512e227dcad20f68c2786ac7a54dacece3746046fea5ce" dependencies = [ "frunk_core", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "frunk_proc_macros" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b85a1d4a9a6b300b41c05e8e13ef2feca03e0334127f29eca9506a7fe13a93" +checksum = "67e86c2c9183662713fea27ea527aad20fb15fee635a71081ff91bf93df4dc51" dependencies = [ "frunk_core", "frunk_proc_macro_helpers", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -3439,7 +3460,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7e180ac76c23b45e767bd7ae9579bc0bb458618c4bc71835926e098e61d15f8" dependencies = [ - "rustix 0.38.34", + "rustix", "windows-sys 0.52.0", ] @@ -3461,9 +3482,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -3476,9 +3497,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -3486,15 +3507,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -3514,9 +3535,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" @@ -3535,11 +3556,11 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210" dependencies = [ - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-core", "futures-io", "parking", @@ -3548,32 +3569,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -3596,7 +3617,7 @@ dependencies = [ "async-trait", "base64 0.21.7", "dirs-next", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.24.2", "ring 0.16.20", "rustls 0.21.12", @@ -3786,9 +3807,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "git-version" @@ -3807,7 +3828,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -3831,9 +3852,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "gloo-timers" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", @@ -3885,7 +3906,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3894,9 +3915,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -3904,7 +3925,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3953,6 +3974,17 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "hashlink" version = "0.9.1" @@ -4146,9 +4178,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -4164,9 +4196,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -4188,14 +4220,14 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -4215,7 +4247,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "log", "rustls 0.21.12", "rustls-native-certs 0.6.3", @@ -4225,16 +4257,16 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", - "rustls 0.23.12", - "rustls-native-certs 0.7.1", + "rustls 0.23.16", + "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -4248,7 +4280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.30", + "hyper 0.14.31", "native-tls", "tokio", "tokio-native-tls", @@ -4262,7 +4294,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "native-tls", "tokio", @@ -4272,16 +4304,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "pin-project-lite", "socket2 0.5.7", "tokio", @@ -4292,9 +4324,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -4358,12 +4390,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "serde", ] @@ -4386,15 +4418,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - [[package]] name = "instant" version = "0.1.13" @@ -4413,17 +4436,6 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipconfig" version = "0.3.2" @@ -4433,14 +4445,14 @@ dependencies = [ "socket2 0.5.7", "widestring", "windows-sys 0.48.0", - "winreg 0.50.0", + "winreg", ] [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is-macro" @@ -4451,7 +4463,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -4513,9 +4525,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -4540,7 +4552,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee7893dab2e44ae5f9d0173f26ff4aa327c10b01b06a72b52dd9405b628640d" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", ] [[package]] @@ -4660,9 +4672,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.156" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libgit2-sys" @@ -4688,9 +4700,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libredox" @@ -4700,14 +4712,14 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.3", + "redox_syscall 0.5.7", ] [[package]] name = "libsqlite3-sys" -version = "0.28.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -4727,9 +4739,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -4743,12 +4755,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -4786,11 +4792,11 @@ dependencies = [ [[package]] name = "lru" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -4844,7 +4850,7 @@ version = "3.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c42f95f9d296f2dcb50665f507ed5a68a171453142663ce44d77a4eb217b053" dependencies = [ - "aes 0.7.5", + "aes", "base64 0.21.7", "block-modes", "crc-any", @@ -4866,9 +4872,9 @@ dependencies = [ [[package]] name = "mail-parser" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5a1335c3a964788c90cb42ae04a34b5f2628e89566949ce3bd4ada695c0bcd" +checksum = "93c3b9e5d8b17faf573330bbc43b37d6e918c0a3bf8a88e7d0a220ebc84af9fc" dependencies = [ "encoding_rs", "serde", @@ -4883,19 +4889,19 @@ dependencies = [ "base64 0.22.1", "gethostname", "mail-builder", - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "smtp-proto", "tokio", "tokio-rustls 0.26.0", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] name = "malachite" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6ea071913d15f7e0566bc4768aae3918906ea77f0abbb387ca7c0dc9303f90" +checksum = "5616515d632967cd329b6f6db96be9a03ea0b3a49cdbc45b0016803dad8a77b7" dependencies = [ "malachite-base", "malachite-nz", @@ -4904,9 +4910,9 @@ dependencies = [ [[package]] name = "malachite-base" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c817c713ff9f16e06cfdc23baa3fecf1b71eaaac714816a98a560f4e350aa6" +checksum = "46059721011b0458b7bd6d9179be5d0b60294281c23320c207adceaecc54d13b" dependencies = [ "hashbrown 0.14.5", "itertools 0.11.0", @@ -4929,9 +4935,9 @@ dependencies = [ [[package]] name = "malachite-nz" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "603729facf62429736ac17a9fc9fe1bf7e0eb8bde3da3b18cc2b6153150464d5" +checksum = "1503b27e825cabd1c3d0ff1e95a39fb2ec9eab6fd3da6cfa41aec7091d273e78" dependencies = [ "itertools 0.11.0", "libm", @@ -4940,9 +4946,9 @@ dependencies = [ [[package]] name = "malachite-q" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c73844ccbf0e9baaf34d4a6d187f0d6a925ce8e74ef37a67d238e7d65529b38c" +checksum = "a475503a70a3679dbe3b9b230a23622516742528ba614a7b2490f180ea9cb514" dependencies = [ "itertools 0.11.0", "malachite-base", @@ -5021,9 +5027,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", "stable_deref_trait", @@ -5054,16 +5060,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minicov" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" -dependencies = [ - "cc", - "walkdir", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -5080,15 +5076,23 @@ dependencies = [ ] [[package]] -name = "mio" -version = "1.0.2" +name = "miniz_oxide" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ - "hermit-abi 0.3.9", "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.48.0", ] [[package]] @@ -5109,7 +5113,7 @@ checksum = "a7ce64b975ed4f123575d11afd9491f2e37bbd5813fbfbc0f09ae1fbddea74e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -5148,7 +5152,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", "termcolor", "thiserror", ] @@ -5192,7 +5196,7 @@ checksum = "478b0ff3f7d67b79da2b96f56f334431aef65e15ba4b29dd74a4236e29582bdc" dependencies = [ "base64 0.21.7", "bigdecimal", - "bindgen", + "bindgen 0.70.1", "bitflags 2.6.0", "bitvec", "btoi", @@ -5219,7 +5223,7 @@ dependencies = [ "subprocess", "thiserror", "time", - "uuid 1.10.0", + "uuid 1.11.0", "zstd 0.13.2", ] @@ -5415,9 +5419,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] @@ -5434,14 +5438,14 @@ dependencies = [ "chrono", "futures", "humantime", - "hyper 1.4.1", + "hyper 1.5.0", "itertools 0.13.0", "md-5 0.10.6", "parking_lot", "percent-encoding", - "quick-xml 0.36.1", + "quick-xml 0.36.2", "rand 0.8.5", - "reqwest 0.12.5", + "reqwest 0.12.9", "ring 0.17.8", "serde", "serde_json", @@ -5454,9 +5458,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oneshot" @@ -5537,9 +5541,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -5558,7 +5562,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -5569,9 +5573,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -5647,9 +5651,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -5669,7 +5673,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall 0.5.7", "smallvec", "windows-targets 0.52.6", ] @@ -5689,7 +5693,7 @@ dependencies = [ "arrow-schema", "arrow-select", "base64 0.22.1", - "brotli", + "brotli 6.0.0", "bytes", "chrono", "flate2", @@ -5719,17 +5723,6 @@ dependencies = [ "regex", ] -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "password-hash" version = "0.5.0" @@ -5749,21 +5742,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", - "hmac", - "password-hash 0.4.2", - "sha2 0.10.8", -] +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] name = "pem" @@ -5815,25 +5796,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.4.0", -] - -[[package]] -name = "pg-embed" -version = "0.7.2" -source = "git+https://github.com/faokunega/pg-embed#72db5e053f0afac6eee51d3baa2fd5c90803e02d" -dependencies = [ - "archiver-rs", - "async-trait", - "bytes", - "dirs", - "futures", - "lazy_static", - "log", - "reqwest 0.11.27", - "thiserror", - "tokio", - "zip", + "indexmap 2.6.0", ] [[package]] @@ -5876,7 +5839,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -5902,29 +5865,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -5939,7 +5902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-io", ] @@ -5988,25 +5951,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polling" @@ -6018,16 +5965,16 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.34", + "rustix", "tracing", "windows-sys 0.59.0", ] [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "postgres-native-tls" @@ -6062,9 +6009,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9" +checksum = "f66ea23a2d0e5734297357705193335e0a957696f34bed2f2faefacb2fec336f" dependencies = [ "array-init", "bit-vec", @@ -6074,7 +6021,7 @@ dependencies = [ "postgres-protocol", "serde", "serde_json", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] @@ -6110,12 +6057,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.20" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -6129,11 +6076,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit 0.22.22", ] [[package]] @@ -6168,7 +6115,7 @@ checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f" dependencies = [ "proc-macro-rules-macros", "proc-macro2", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -6180,14 +6127,14 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -6241,7 +6188,7 @@ dependencies = [ "schemars", "serde", "serde_json", - "syn 2.0.74", + "syn 2.0.86", "thiserror", "typify", "unicode-ident", @@ -6261,7 +6208,7 @@ dependencies = [ "serde_json", "serde_tokenstream", "serde_yaml", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -6304,7 +6251,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -6318,9 +6265,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" dependencies = [ "cc", ] @@ -6346,10 +6293,22 @@ dependencies = [ ] [[package]] -name = "pulp" -version = "0.18.21" +name = "pulldown-cmark" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec8d02258294f59e4e223b41ad7e81c874aa6b15bc4ced9ba3965826da0eed5" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags 2.6.0", + "getopts", + "memchr", + "unicase", +] + +[[package]] +name = "pulp" +version = "0.18.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a01a0dc67cf4558d279f0c25b0962bd08fc6dec0137699eae304103e882fe6" dependencies = [ "bytemuck", "libm", @@ -6375,9 +6334,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.36.1" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a05e2e8efddfa51a84ca47cec303fac86c8541b686d37cac5efc0e094417bc" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", "serde", @@ -6385,9 +6344,9 @@ dependencies = [ [[package]] name = "quick_cache" -version = "0.6.2" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec932c60e6faf77dc6601ea149a23d821598b019b450bb1d98fe89c0301c0b61" +checksum = "7d7c94f8935a9df96bb6380e8592c70edf497a643f94bd23b2f76b399385dbf4" dependencies = [ "ahash 0.8.11", "equivalent", @@ -6397,16 +6356,16 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.12", + "rustls 0.23.16", "socket2 0.5.7", "thiserror", "tokio", @@ -6415,15 +6374,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand 0.8.5", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.12", + "rustls 0.23.16", "slab", "thiserror", "tinyvec", @@ -6432,22 +6391,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" dependencies = [ + "cfg_aliases", "libc", "once_cell", "socket2 0.5.7", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -6624,27 +6584,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", @@ -6653,14 +6604,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -6674,13 +6625,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -6703,9 +6654,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "regress" @@ -6740,7 +6691,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", @@ -6757,7 +6708,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration", + "system-configuration 0.5.1", "tokio", "tokio-native-tls", "tokio-rustls 0.24.1", @@ -6769,27 +6720,27 @@ dependencies = [ "wasm-streams", "web-sys", "webpki-roots 0.25.4", - "winreg 0.50.0", + "winreg", ] [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ - "async-compression 0.4.12", + "async-compression 0.4.17", "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper 1.5.0", + "hyper-rustls 0.27.3", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -6801,15 +6752,15 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.12", - "rustls-native-certs 0.7.1", - "rustls-pemfile 2.1.3", + "rustls 0.23.16", + "rustls-native-certs 0.8.0", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.1", - "system-configuration", + "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tokio-rustls 0.26.0", @@ -6820,7 +6771,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "winreg 0.52.0", + "windows-registry", ] [[package]] @@ -6881,9 +6832,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", @@ -6894,14 +6845,14 @@ dependencies = [ "rkyv_derive", "seahash", "tinyvec", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] name = "rkyv_derive" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2", "quote", @@ -6984,7 +6935,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.74", + "syn 2.0.86", "walkdir", ] @@ -7010,9 +6961,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.35.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", "borsh", @@ -7054,9 +7005,9 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] @@ -7076,28 +7027,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.27" +version = "0.38.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys", "windows-sys 0.52.0", ] @@ -7115,15 +7052,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "log", "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -7142,12 +7079,25 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -7164,19 +7114,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-tokio-stream" @@ -7185,7 +7134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22557157d7395bc30727745b365d923f1ecc230c4c80b176545f3f4f08c46e33" dependencies = [ "futures", - "rustls 0.23.12", + "rustls 0.23.16", "socket2 0.5.7", "tokio", ] @@ -7202,9 +7151,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -7266,9 +7215,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -7284,9 +7233,9 @@ checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5" [[package]] name = "safetensors" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7725d4d98fa515472f43a6e2bbf956c48e06b89bb50593a040e5945160214450" +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6" dependencies = [ "serde", "serde_json", @@ -7299,7 +7248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b75583aad4a51c50fc0af69c230d18078c9d5a69a98d0f6013d01053acf744f4" dependencies = [ "base64 0.21.7", - "bindgen", + "bindgen 0.69.5", "chrono", "data-encoding", "derive_builder", @@ -7316,7 +7265,7 @@ dependencies = [ "serde", "thiserror", "url", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] @@ -7336,11 +7285,11 @@ checksum = "ece8e78b2f38ec51c51f5d475df0a7187ba5111b2a28bdc761ee05b075d40a71" [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -7354,7 +7303,7 @@ dependencies = [ "schemars_derive", "serde", "serde_json", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] @@ -7366,7 +7315,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -7426,9 +7375,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -7466,9 +7415,9 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] @@ -7507,13 +7456,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -7524,16 +7473,16 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "itoa", "memchr", "ryu", @@ -7583,9 +7532,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -7599,7 +7548,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -7616,9 +7565,9 @@ dependencies = [ [[package]] name = "serde_v8" -version = "0.208.0" +version = "0.220.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583f3c71a6f7acc1711ad718a33f6e799bacdc711d297b15bb28533f32264c58" +checksum = "6e7a65d91d79acc82aa229aeb084f4a39bda269069bc1520df40f679495388e4" dependencies = [ "num-bigint", "serde", @@ -7629,15 +7578,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -7647,14 +7596,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -7663,7 +7612,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "itoa", "ryu", "serde", @@ -7766,9 +7715,9 @@ dependencies = [ [[package]] name = "simdutf8" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "simple_asn1" @@ -7919,6 +7868,25 @@ dependencies = [ "url", ] +[[package]] +name = "sourcemap" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab08a862c70980b8e23698b507e272317ae52a608a164a844111f5372374f1f" +dependencies = [ + "base64-simd 0.7.0", + "bitvec", + "data-encoding", + "debugid", + "if_chain", + "rustc-hash 1.1.0", + "rustc_version 0.2.3", + "serde", + "serde_json", + "unicode-id-start", + "url", +] + [[package]] name = "spin" version = "0.5.2" @@ -7978,9 +7946,9 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ "nom", "unicode_categories", @@ -8004,14 +7972,14 @@ checksum = "01b2e185515564f15375f593fb966b5718bc624ba77fe49fa4616ad619690554" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "sqlx" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27144619c6e5802f1380337a209d2ac1c431002dd74c6e60aebff3c506dc4f0c" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -8022,9 +7990,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a999083c1af5b5d6c071d34a708a19ba3e02106ad82ef7bbd69f5e48266b613b" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ "atoi", "bigdecimal", @@ -8043,14 +8011,14 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "log", "memchr", "once_cell", "paste", "percent-encoding", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls 0.23.16", + "rustls-pemfile 2.2.0", "serde", "serde_json", "sha2 0.10.8", @@ -8061,28 +8029,28 @@ dependencies = [ "tokio-stream", "tracing", "url", - "uuid 1.10.0", - "webpki-roots 0.25.4", + "uuid 1.11.0", + "webpki-roots 0.26.6", ] [[package]] name = "sqlx-macros" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23217eb7d86c584b8cbe0337b9eacf12ab76fe7673c513141ec42565698bb88" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "sqlx-macros-core" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a099220ae541c5db479c6424bdf1b200987934033c2584f79a0e1693601e776" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", @@ -8098,7 +8066,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.74", + "syn 2.0.86", "tempfile", "tokio", "url", @@ -8106,9 +8074,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5afe4c38a9b417b6a9a5eeffe7235d0a106716495536e7727d1c7f4b1ff3eba6" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64 0.22.1", @@ -8145,15 +8113,15 @@ dependencies = [ "stringprep", "thiserror", "tracing", - "uuid 1.10.0", + "uuid 1.11.0", "whoami", ] [[package]] name = "sqlx-postgres" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1dbb157e65f10dbe01f729339c06d239120221c9ad9fa0ba8408c4cc18ecf21" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64 0.22.1", @@ -8187,15 +8155,15 @@ dependencies = [ "stringprep", "thiserror", "tracing", - "uuid 1.10.0", + "uuid 1.11.0", "whoami", ] [[package]] name = "sqlx-sqlite" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2cdd83c008a622d94499c0006d8ee5f821f36c89b7d625c900e5dc30b5c5ee" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "chrono", @@ -8213,7 +8181,7 @@ dependencies = [ "sqlx-core", "tracing", "url", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] @@ -8224,15 +8192,15 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stacker" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" dependencies = [ "cc", "cfg-if", "libc", "psm", - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -8250,7 +8218,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -8304,7 +8272,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -8317,7 +8285,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -8336,6 +8304,19 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "swc_allocator" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76aa0eb65c0f39f9b6d82a7e5192c30f7ac9a78f084a21f270de1d8c600ca388" +dependencies = [ + "bumpalo", + "hashbrown 0.14.5", + "ptr_meta", + "rustc-hash 1.1.0", + "triomphe", +] + [[package]] name = "swc_atoms" version = "0.6.7" @@ -8364,9 +8345,9 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.33.26" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f9706038906e66f3919028f9f7a37f3ed552f1b85578e93f4468742e2da438" +checksum = "12d0a8eaaf1606c9207077d75828008cb2dfb51b095a766bd2b72ef893576e31" dependencies = [ "ast_node", "better_scoped_tls", @@ -8379,32 +8360,8 @@ dependencies = [ "rustc-hash 1.1.0", "serde", "siphasher", - "swc_atoms", - "swc_eq_ignore_macros", - "swc_visit", - "tracing", - "unicode-width", - "url", -] - -[[package]] -name = "swc_common" -version = "0.34.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9087befec6b63911f9d2f239e4f91c9b21589c169b86ed2d616944d23cf4a243" -dependencies = [ - "ast_node", - "better_scoped_tls", - "cfg-if", - "either", - "from_variant", - "new_debug_unreachable", - "num-bigint", - "once_cell", - "rustc-hash 1.1.0", - "serde", - "siphasher", - "sourcemap", + "sourcemap 9.0.0", + "swc_allocator", "swc_atoms", "swc_eq_ignore_macros", "swc_visit", @@ -8415,12 +8372,12 @@ dependencies = [ [[package]] name = "swc_config" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b67e115ab136fe0eb03558bb0508ca7782eeb446a96d165508c48617e3fd94" +checksum = "4740e53eaf68b101203c1df0937d5161a29f3c13bceed0836ddfe245b72dd000" dependencies = [ "anyhow", - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_json", "swc_cached", @@ -8436,31 +8393,14 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "swc_ecma_ast" -version = "0.113.7" +version = "0.118.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a534a8360a076a030989f6d121ba6044345594bdf0457c4629f432742026b8" -dependencies = [ - "bitflags 2.6.0", - "is-macro", - "num-bigint", - "phf", - "scoped-tls", - "string_enum", - "swc_atoms", - "swc_common 0.33.26", - "unicode-id-start", -] - -[[package]] -name = "swc_ecma_ast" -version = "0.115.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be1306930c235435a892104c00c2b5e16231043c085d5a10bd3e7537b15659b" +checksum = "a6f866d12e4d519052b92a0a86d1ac7ff17570da1272ca0c89b3d6f802cd79df" dependencies = [ "bitflags 2.6.0", "is-macro", @@ -8470,60 +8410,60 @@ dependencies = [ "serde", "string_enum", "swc_atoms", - "swc_common 0.34.4", + "swc_common", "unicode-id-start", ] [[package]] name = "swc_ecma_codegen" -version = "0.151.1" +version = "0.155.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5141a8cb4eb69e090e6aea5d49061b46919be5210f3d084f9d9ad63d30f5cff" +checksum = "cc7641608ef117cfbef9581a99d02059b522fcca75e5244fa0cbbd8606689c6f" dependencies = [ "memchr", "num-bigint", "once_cell", - "rustc-hash 1.1.0", "serde", - "sourcemap", + "sourcemap 9.0.0", + "swc_allocator", "swc_atoms", - "swc_common 0.34.4", - "swc_ecma_ast 0.115.1", + "swc_common", + "swc_ecma_ast", "swc_ecma_codegen_macros", "tracing", ] [[package]] name = "swc_ecma_codegen_macros" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090e409af49c8d1a3c13b3aab1ed09dd4eda982207eb3e63c2ad342f072b49c8" +checksum = "859fabde36db38634f3fad548dd5e3410c1aebba1b67a3c63e67018fa57a0bca" dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "swc_ecma_loader" -version = "0.46.1" +version = "0.49.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9febebf047d1286e7b723fa2758f3229da2c103834f3eaee69833f46692612" +checksum = "55fa3d55045b97894bfb04d38aff6d6302ac8a6a38e3bb3dfb0d20475c4974a9" dependencies = [ "anyhow", "pathdiff", "serde", "swc_atoms", - "swc_common 0.34.4", + "swc_common", "tracing", ] [[package]] name = "swc_ecma_parser" -version = "0.144.3" +version = "0.149.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0b4193b9c127db1990a5a08111aafe0122bc8b138646807c63f2a6521b7da4" +checksum = "683dada14722714588b56481399c699378b35b2ba4deb5c4db2fb627a97fb54b" dependencies = [ "either", "new_debug_unreachable", @@ -8535,69 +8475,47 @@ dependencies = [ "smartstring", "stacker", "swc_atoms", - "swc_common 0.33.26", - "swc_ecma_ast 0.113.7", - "tracing", - "typed-arena", -] - -[[package]] -name = "swc_ecma_parser" -version = "0.146.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e0c2e85f12c63b85c805e923079b04d1fb3e25edd069d638eed5f2098de74" -dependencies = [ - "either", - "new_debug_unreachable", - "num-bigint", - "num-traits", - "phf", - "serde", - "smallvec", - "smartstring", - "stacker", - "swc_atoms", - "swc_common 0.34.4", - "swc_ecma_ast 0.115.1", + "swc_common", + "swc_ecma_ast", "tracing", "typed-arena", ] [[package]] name = "swc_ecma_transforms_base" -version = "0.140.3" +version = "0.145.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37dc505c92af56d0f77cf6f31a6ccd37ac40cad1e01ff77277e0b1c70e8f8ff" +checksum = "65f21494e75d0bd8ef42010b47cabab9caaed8f2207570e809f6f4eb51a710d1" dependencies = [ "better_scoped_tls", "bitflags 2.6.0", - "indexmap 2.4.0", + "indexmap 2.6.0", "once_cell", "phf", "rustc-hash 1.1.0", "serde", "smallvec", "swc_atoms", - "swc_common 0.34.4", - "swc_ecma_ast 0.115.1", - "swc_ecma_parser 0.146.12", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", "swc_ecma_utils", - "swc_ecma_visit 0.101.0", + "swc_ecma_visit", "tracing", ] [[package]] name = "swc_ecma_transforms_classes" -version = "0.129.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3eab5f8179e5b0aedf385eacc2c033691c6d211a7babd1bbbff12cf794a824e" +checksum = "3c3d884594385bea9405a2e1721151470d9a14d3ceec5dd773c0ca6894791601" dependencies = [ "swc_atoms", - "swc_common 0.34.4", - "swc_ecma_ast 0.115.1", + "swc_common", + "swc_ecma_ast", "swc_ecma_transforms_base", "swc_ecma_utils", - "swc_ecma_visit 0.101.0", + "swc_ecma_visit", ] [[package]] @@ -8609,160 +8527,148 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "swc_ecma_transforms_proposal" -version = "0.174.3" +version = "0.179.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df8aa6752cc2fcf3d78ac67827542fb666e52283f2b26802aa058906bb750d3" +checksum = "79938ff510fc647febd8c6c3ef4143d099fdad87a223680e632623d056dae2dd" dependencies = [ "either", "rustc-hash 1.1.0", "serde", "smallvec", "swc_atoms", - "swc_common 0.34.4", - "swc_ecma_ast 0.115.1", + "swc_common", + "swc_ecma_ast", "swc_ecma_transforms_base", "swc_ecma_transforms_classes", "swc_ecma_transforms_macros", "swc_ecma_utils", - "swc_ecma_visit 0.101.0", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_transforms_react" -version = "0.186.2" +version = "0.191.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446da32cac8299973aaf1d37496562bfd0c1e4f3c3ab5d0af6f07f42e8184102" +checksum = "76c76d8b9792ce51401d38da0fa62158d61f6d80d16d68fe5b03ce4bf5fba383" dependencies = [ "base64 0.21.7", "dashmap", - "indexmap 2.4.0", + "indexmap 2.6.0", "once_cell", "serde", "sha1", "string_enum", + "swc_allocator", "swc_atoms", - "swc_common 0.34.4", + "swc_common", "swc_config", - "swc_ecma_ast 0.115.1", - "swc_ecma_parser 0.146.12", + "swc_ecma_ast", + "swc_ecma_parser", "swc_ecma_transforms_base", "swc_ecma_transforms_macros", "swc_ecma_utils", - "swc_ecma_visit 0.101.0", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_transforms_typescript" -version = "0.191.2" +version = "0.198.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1ce8af2865449e714ae56dacb6b54b3f6dc4cc25074da4e39b878bd93c5e39c" +checksum = "15455da4768f97186c40523e83600495210c11825d3a44db43383fd81eace88d" dependencies = [ "ryu-js", "serde", "swc_atoms", - "swc_common 0.34.4", - "swc_ecma_ast 0.115.1", + "swc_common", + "swc_ecma_ast", "swc_ecma_transforms_base", "swc_ecma_transforms_react", "swc_ecma_utils", - "swc_ecma_visit 0.101.0", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_utils" -version = "0.130.3" +version = "0.134.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e62b199454a576c5fdbd7e1bef8ab88a395427456d8a713d994b7d469833aa" +checksum = "029eec7dd485923a75b5a45befd04510288870250270292fc2c1b3a9e7547408" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "num_cpus", "once_cell", "rustc-hash 1.1.0", "ryu-js", "swc_atoms", - "swc_common 0.34.4", - "swc_ecma_ast 0.115.1", - "swc_ecma_visit 0.101.0", + "swc_common", + "swc_ecma_ast", + "swc_ecma_visit", "tracing", "unicode-id", ] [[package]] name = "swc_ecma_visit" -version = "0.99.1" +version = "0.104.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6ce28ad8e591f8d627f1f9cb26b25e5d83052a9bc1b674d95fc28040cfa98" +checksum = "5b1c6802e68e51f336e8bc9644e9ff9da75d7da9c1a6247d532f2e908aa33e81" dependencies = [ + "new_debug_unreachable", "num-bigint", "swc_atoms", - "swc_common 0.33.26", - "swc_ecma_ast 0.113.7", - "swc_visit", - "tracing", -] - -[[package]] -name = "swc_ecma_visit" -version = "0.101.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce0d997f0c9b4e181225f603d161f6757c2a97022258170982cfe005ec69ec92" -dependencies = [ - "num-bigint", - "swc_atoms", - "swc_common 0.34.4", - "swc_ecma_ast 0.115.1", + "swc_common", + "swc_ecma_ast", "swc_visit", "tracing", ] [[package]] name = "swc_eq_ignore_macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695a1d8b461033d32429b5befbf0ad4d7a2c4d6ba9cd5ba4e0645c615839e8e4" +checksum = "63db0adcff29d220c3d151c5b25c0eabe7e32dd936212b84cdaa1392e3130497" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "swc_macros_common" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91745f3561057493d2da768437c427c0e979dff7396507ae02f16c981c4a8466" +checksum = "f486687bfb7b5c560868f69ed2d458b880cebc9babebcb67e49f31b55c5bf847" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "swc_visit" -version = "0.5.14" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043d11fe683dcb934583ead49405c0896a5af5face522e4682c16971ef7871b9" +checksum = "1ceb044142ba2719ef9eb3b6b454fce61ab849eb696c34d190f04651955c613d" dependencies = [ "either", - "swc_visit_macros", + "new_debug_unreachable", ] [[package]] name = "swc_visit_macros" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae9ef18ff8daffa999f729db056d2821cd2f790f3a11e46422d19f46bb193e7" +checksum = "92807d840959f39c60ce8a774a3f83e8193c658068e6d270dbe0a05e40e90b41" dependencies = [ "Inflector", "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -8778,9 +8684,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.74" +version = "2.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c" dependencies = [ "proc-macro2", "quote", @@ -8796,7 +8702,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -8810,6 +8716,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -8819,7 +8728,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -8844,7 +8753,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys 0.6.0", ] [[package]] @@ -8857,6 +8777,16 @@ dependencies = [ "libc", ] +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tantivy" version = "0.22.0" @@ -8904,7 +8834,7 @@ dependencies = [ "tempfile", "thiserror", "time", - "uuid 1.10.0", + "uuid 1.11.0", "winapi", ] @@ -8953,7 +8883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d60769b80ad7953d8a7b2c70cdfe722bbcdcac6bccc8ac934c40c034d866fc18" dependencies = [ "byteorder", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "utf8-ranges", ] @@ -9006,9 +8936,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.41" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" dependencies = [ "filetime", "libc", @@ -9017,14 +8947,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", - "fastrand 2.1.0", + "fastrand 2.1.1", "once_cell", - "rustix 0.38.34", + "rustix", "windows-sys 0.59.0", ] @@ -9048,22 +8978,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -9112,7 +9042,7 @@ dependencies = [ "tokio-rustls 0.24.1", "tokio-util", "tracing", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] @@ -9262,32 +9192,33 @@ dependencies = [ [[package]] name = "tokio" -version = "1.39.2" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", "libc", "mio", + "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", "tokio-macros", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -9302,9 +9233,9 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03adcf0147e203b6032c0b2d30be1415ba03bc348901f3ff1cc0df6a733e60c3" +checksum = "3b5d3742945bc7d7f210693b0c58ae542c6fd47b17adbbda0885f3dcb34a6bdb" dependencies = [ "async-trait", "byteorder", @@ -9342,7 +9273,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "tokio", ] @@ -9361,9 +9292,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -9386,10 +9317,24 @@ dependencies = [ ] [[package]] -name = "tokio-util" -version = "0.7.11" +name = "tokio-tungstenite" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "native-tls", + "tokio", + "tokio-native-tls", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -9420,7 +9365,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.20", + "toml_edit 0.22.22", ] [[package]] @@ -9438,7 +9383,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", @@ -9447,26 +9392,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.4.0", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" -dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.20", ] [[package]] @@ -9495,17 +9429,22 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] name = "tower" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36b837f86b25d7c0d7988f00a54e74739be6477f2aac6201b8f429a7569991b7" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -9531,7 +9470,24 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "async-compression 0.4.12", + "bitflags 2.6.0", + "bytes", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" +dependencies = [ + "async-compression 0.4.17", "bitflags 2.6.0", "bytes", "futures-core", @@ -9543,7 +9499,6 @@ dependencies = [ "tokio-util", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -9570,6 +9525,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.27" @@ -9578,7 +9545,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -9641,7 +9608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea6023f9fe4b69267ccd3ed7d203d931c43c5f82dbaa0f07202bc17193a5f43" dependencies = [ "loki-api", - "reqwest 0.12.5", + "reqwest 0.12.9", "serde", "serde_json", "snap", @@ -9688,9 +9655,9 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" +checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" dependencies = [ "serde", "stable_deref_trait", @@ -9750,6 +9717,25 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "native-tls", + "rand 0.8.5", + "sha1", + "thiserror", + "utf-8", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -9796,7 +9782,7 @@ dependencies = [ "regress", "schemars", "serde_json", - "syn 2.0.74", + "syn 2.0.86", "thiserror", "unicode-ident", ] @@ -9813,7 +9799,7 @@ dependencies = [ "serde", "serde_json", "serde_tokenstream", - "syn 2.0.74", + "syn 2.0.86", "typify-impl", ] @@ -9825,7 +9811,7 @@ checksum = "04f903f293d11f31c0c29e4148f6dc0d033a7f80cebc0282bea147611667d289" dependencies = [ "getrandom 0.2.15", "rand 0.8.5", - "uuid 1.10.0", + "uuid 1.11.0", "web-time", ] @@ -9895,42 +9881,39 @@ dependencies = [ [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-id" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f" +checksum = "10103c57044730945224467c09f71a4db0071c123a0648cc3e818913bde6b561" [[package]] name = "unicode-id-start" -version = "1.0.4" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02aebfa694eccbbbffdd92922c7de136b9fe764396d2f10e21bce1681477cfc1" +checksum = "2f322b60f6b9736017344fa0635d64be2f458fbc04eef65f6be22976dd1ffd5b" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -9946,27 +9929,27 @@ dependencies = [ [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -9976,9 +9959,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "unicode_names2" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addeebf294df7922a1164f729fb27ebbbcea99cc32b3bf08afab62757f707677" +checksum = "d1673eca9782c84de5f81b82e4109dcfb3611c8ba0d52930ec4a9478f547b2dd" dependencies = [ "phf", "unicode_names2_generator", @@ -9986,9 +9969,9 @@ dependencies = [ [[package]] name = "unicode_names2_generator" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f444b8bba042fe3c1251ffaca35c603f2dc2ccc08d595c65a8c4f76f3e8426c0" +checksum = "b91e5b84611016120197efd7dc93ef76774f4e084cd73c9fb3ea4a86c570c56e" dependencies = [ "getopts", "log", @@ -10025,12 +10008,12 @@ dependencies = [ "log", "native-tls", "once_cell", - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "serde", "serde_json", "url", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] @@ -10053,17 +10036,22 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "urlpattern" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9bd5ff03aea02fa45b13a7980151fe45009af1980ba69f651ec367121a31609" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" dependencies = [ - "derive_more", "regex", "serde", "unic-ucd-ident", "url", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8-ranges" version = "1.0.5" @@ -10087,9 +10075,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom 0.2.15", "serde", @@ -10097,19 +10085,19 @@ dependencies = [ [[package]] name = "v8" -version = "0.99.0" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa3fc0608a78f0c7d4ec88025759cb78c90a29984b48540060355a626ae329c1" +checksum = "a381badc47c6f15acb5fe0b5b40234162349ed9d4e4fd7c83a7f5547c0fc69c5" dependencies = [ - "bindgen", + "bindgen 0.69.5", "bitflags 2.6.0", "fslock", "gzip-header", "home", - "miniz_oxide", + "miniz_oxide 0.7.4", "once_cell", "paste", - "which 6.0.2", + "which 6.0.3", ] [[package]] @@ -10120,9 +10108,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" [[package]] name = "vcpkg" @@ -10187,35 +10175,34 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", - "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -10225,9 +10212,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10235,32 +10222,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-bindgen-test" -version = "0.3.43" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" +checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" dependencies = [ "console_error_panic_hook", "js-sys", - "minicov", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -10269,20 +10255,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.43" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" +checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" dependencies = [ "futures-util", "js-sys", @@ -10302,9 +10288,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -10328,9 +10314,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -10344,28 +10330,28 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.34", + "rustix", ] [[package]] name = "which" -version = "6.0.2" +version = "6.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d9c5ed668ee1f17edb3b627225343d210006a90bb1e3745ce1f30b1fb115075" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", - "rustix 0.38.34", + "rustix", "winsafe", ] [[package]] name = "whoami" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall 0.5.7", "wasite", "web-sys", ] @@ -10409,7 +10395,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "axum", @@ -10421,11 +10407,12 @@ dependencies = [ "gethostname", "git-version", "lazy_static", + "object_store", "once_cell", - "pg-embed", "prometheus", + "quote", "rand 0.8.5", - "reqwest 0.12.5", + "reqwest 0.12.9", "rsmq_async", "serde", "serde_json", @@ -10437,9 +10424,10 @@ dependencies = [ "tokio", "tracing", "url", - "uuid 1.10.0", + "uuid 1.11.0", "windmill-api", "windmill-api-client", + "windmill-autoscaling", "windmill-common", "windmill-git-sync", "windmill-indexer", @@ -10449,7 +10437,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "argon2", @@ -10466,9 +10454,8 @@ dependencies = [ "candle-nn", "candle-transformers", "chrono", - "chrono-tz", + "chrono-tz 0.10.0", "cookie 0.17.0", - "crc", "cron", "datafusion", "futures", @@ -10477,12 +10464,13 @@ dependencies = [ "hf-hub", "hmac", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.0", "itertools 0.13.0", "jsonwebtoken", "lazy_static", "magic-crypt", "mail-parser", + "matchit", "mime_guess", "native-tls", "object_store", @@ -10493,7 +10481,7 @@ dependencies = [ "quick_cache", "rand 0.8.5", "regex", - "reqwest 0.12.5", + "reqwest 0.12.9", "rsa 0.7.2", "rsmq_async", "rust-embed", @@ -10511,16 +10499,17 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-tar", + "tokio-tungstenite", "tokio-util", - "tower 0.5.0", + "tower 0.5.1", "tower-cookies", - "tower-http", + "tower-http 0.5.2", "tracing", "tracing-subscriber", "ulid", "url", "urlencoding", - "uuid 1.10.0", + "uuid 1.11.0", "windmill-audit", "windmill-common", "windmill-git-sync", @@ -10533,7 +10522,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.381.0" +version = "1.416.2" dependencies = [ "base64 0.21.7", "chrono", @@ -10546,12 +10535,12 @@ dependencies = [ "serde", "serde_json", "syn 1.0.109", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] name = "windmill-audit" -version = "1.381.0" +version = "1.416.2" dependencies = [ "chrono", "serde", @@ -10562,9 +10551,24 @@ dependencies = [ "windmill-common", ] +[[package]] +name = "windmill-autoscaling" +version = "1.416.2" +dependencies = [ + "anyhow", + "rsmq_async", + "serde", + "serde_json", + "sqlx", + "tracing", + "uuid 1.11.0", + "windmill-common", + "windmill-queue", +] + [[package]] name = "windmill-common" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "async-stream", @@ -10573,13 +10577,16 @@ dependencies = [ "axum", "bytes", "chrono", + "const_format", + "crc", "cron", "futures-core", + "gethostname", "git-version", "hex", "hmac", - "hyper 1.4.1", - "indexmap 2.4.0", + "hyper 1.5.0", + "indexmap 2.6.0", "itertools 0.13.0", "lazy_static", "magic-crypt", @@ -10588,7 +10595,7 @@ dependencies = [ "prometheus", "rand 0.8.5", "regex", - "reqwest 0.12.5", + "reqwest 0.12.9", "serde", "serde_json", "sha2 0.10.8", @@ -10597,15 +10604,17 @@ dependencies = [ "tikv-jemalloc-ctl", "tokio", "tracing", + "tracing-appender", "tracing-flame", "tracing-loki", "tracing-subscriber", - "uuid 1.10.0", + "uuid 1.11.0", + "windmill-macros", ] [[package]] name = "windmill-git-sync" -version = "1.381.0" +version = "1.416.2" dependencies = [ "regex", "rsmq_async", @@ -10613,19 +10622,20 @@ dependencies = [ "serde_json", "sqlx", "tracing", - "uuid 1.10.0", + "uuid 1.11.0", "windmill-common", "windmill-queue", ] [[package]] name = "windmill-indexer" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "bytes", "chrono", "futures", + "lazy_static", "object_store", "serde", "serde_json", @@ -10635,32 +10645,46 @@ dependencies = [ "tokio", "tokio-tar", "tracing", - "uuid 1.10.0", + "uuid 1.11.0", "windmill-common", ] [[package]] -name = "windmill-parser" -version = "1.381.0" +name = "windmill-macros" +version = "1.416.2" dependencies = [ + "itertools 0.13.0", + "lazy_static", + "proc-macro2", + "quote", + "regex", + "syn 2.0.86", +] + +[[package]] +name = "windmill-parser" +version = "1.416.2" +dependencies = [ + "convert_case 0.6.0", "serde", "serde_json", ] [[package]] name = "windmill-parser-bash" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "lazy_static", "regex", + "regex-lite", "serde_json", "windmill-parser", ] [[package]] name = "windmill-parser-go" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "gosyn", @@ -10672,32 +10696,30 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "lazy_static", "regex", + "regex-lite", "serde_json", "windmill-parser", ] [[package]] name = "windmill-parser-php" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", - "convert_case 0.6.0", "itertools 0.13.0", - "lazy_static", "php-parser-rs", - "regex", "serde_json", "windmill-parser", ] [[package]] name = "windmill-parser-py" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "itertools 0.13.0", @@ -10708,7 +10730,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "async-recursion", @@ -10716,6 +10738,7 @@ dependencies = [ "lazy_static", "phf", "regex", + "regex-lite", "rustpython-parser", "serde_json", "sqlx", @@ -10723,31 +10746,48 @@ dependencies = [ "windmill-parser", ] +[[package]] +name = "windmill-parser-rust" +version = "1.416.2" +dependencies = [ + "anyhow", + "convert_case 0.6.0", + "itertools 0.13.0", + "lazy_static", + "pulldown-cmark", + "quote", + "regex", + "serde_json", + "syn 2.0.86", + "toml 0.7.8", + "windmill-parser", +] + [[package]] name = "windmill-parser-sql" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "lazy_static", "regex", + "regex-lite", "serde_json", "windmill-parser", ] [[package]] name = "windmill-parser-ts" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", - "convert_case 0.6.0", "lazy_static", "regex", "serde-wasm-bindgen", "serde_json", - "swc_common 0.33.26", - "swc_ecma_ast 0.113.7", - "swc_ecma_parser 0.144.3", - "swc_ecma_visit 0.99.1", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_visit", "triomphe", "wasm-bindgen", "windmill-parser", @@ -10755,7 +10795,7 @@ dependencies = [ [[package]] name = "windmill-parser-wasm" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "getrandom 0.2.15", @@ -10768,20 +10808,32 @@ dependencies = [ "windmill-parser-graphql", "windmill-parser-php", "windmill-parser-py", + "windmill-parser-rust", "windmill-parser-sql", "windmill-parser-ts", + "windmill-parser-yaml", +] + +[[package]] +name = "windmill-parser-yaml" +version = "1.416.2" +dependencies = [ + "anyhow", + "serde_json", + "windmill-parser", + "yaml-rust", ] [[package]] name = "windmill-queue" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "async-recursion", "axum", "bigdecimal", "chrono", - "chrono-tz", + "chrono-tz 0.10.0", "cron", "futures-core", "hex", @@ -10790,7 +10842,7 @@ dependencies = [ "lazy_static", "prometheus", "regex", - "reqwest 0.12.5", + "reqwest 0.12.9", "rsmq_async", "serde", "serde_json", @@ -10800,14 +10852,14 @@ dependencies = [ "tokio", "tracing", "ulid", - "uuid 1.10.0", + "uuid 1.11.0", "windmill-audit", "windmill-common", ] [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.381.0" +version = "1.416.2" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -10817,7 +10869,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.381.0" +version = "1.416.2" dependencies = [ "anyhow", "async-recursion", @@ -10857,13 +10909,14 @@ dependencies = [ "prometheus", "rand 0.8.5", "regex", - "reqwest 0.12.5", + "reqwest 0.12.9", "rsmq_async", "rust_decimal", "serde", "serde_json", "sha2 0.10.8", "sqlx", + "swc_ecma_parser", "tar", "tiberius", "tokio", @@ -10871,7 +10924,7 @@ dependencies = [ "tokio-util", "tracing", "urlencoding", - "uuid 1.10.0", + "uuid 1.11.0", "windmill-audit", "windmill-common", "windmill-git-sync", @@ -10882,9 +10935,12 @@ dependencies = [ "windmill-parser-php", "windmill-parser-py", "windmill-parser-py-imports", + "windmill-parser-rust", "windmill-parser-sql", "windmill-parser-ts", + "windmill-parser-yaml", "windmill-queue", + "yaml-rust", "zstd 0.12.4", ] @@ -10897,6 +10953,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -11056,9 +11142,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -11073,16 +11159,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "winsafe" version = "0.0.19" @@ -11105,8 +11181,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", - "linux-raw-sys 0.4.14", - "rustix 0.38.34", + "linux-raw-sys", + "rustix", ] [[package]] @@ -11124,6 +11200,15 @@ dependencies = [ "lzma-sys", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yansi" version = "0.5.1" @@ -11150,7 +11235,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", "synstructure", ] @@ -11172,7 +11257,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", ] [[package]] @@ -11192,7 +11277,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.86", "synstructure", ] @@ -11208,18 +11293,9 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" dependencies = [ - "aes 0.8.4", "byteorder", - "bzip2", - "constant_time_eq 0.1.5", "crc32fast", "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2", - "sha1", - "time", - "zstd 0.11.2+zstd.1.5.2", ] [[package]] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 906d9f08b9..1c0abc299c 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.381.0" +version = "1.416.2" authors.workspace = true edition.workspace = true @@ -13,19 +13,23 @@ members = [ "./windmill-common", "./windmill-audit", "./windmill-git-sync", + "./windmill-autoscaling", "./windmill-indexer", + "./windmill-macros", "./parsers/windmill-parser", "./parsers/windmill-parser-ts", "./parsers/windmill-parser-wasm", "./parsers/windmill-parser-go", + "./parsers/windmill-parser-rust", "./parsers/windmill-parser-bash", "./parsers/windmill-parser-py", "./parsers/windmill-parser-py-imports", "./parsers/windmill-sql-datatype-parser-wasm", + "./parsers/windmill-parser-yaml", "windmill-macros", ] [workspace.package] -version = "1.381.0" +version = "1.416.2" authors = ["Ruben Fiszel "] edition = "2021" @@ -37,17 +41,19 @@ path = "./src/main.rs" opt-level = 0 incremental = true +[profile.release] +lto = "thin" + [features] default = [] -enterprise = ["windmill-worker/enterprise", "windmill-queue/enterprise", "windmill-api/enterprise", "windmill-git-sync/enterprise", "windmill-common/prometheus", "windmill-common/enterprise", "windmill-indexer/enterprise"] +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", "windmill-indexer/enterprise"] enterprise_saml = ["windmill-api/enterprise_saml"] stripe = ["windmill-api/stripe"] -benchmark = ["windmill-api/benchmark", "windmill-worker/benchmark", "windmill-queue/benchmark"] +benchmark = ["windmill-api/benchmark", "windmill-worker/benchmark", "windmill-queue/benchmark", "windmill-common/benchmark"] flamegraph = ["windmill-common/flamegraph", "windmill-worker/flamegraph"] loki = ["windmill-common/loki"] -pg_embed = ["dep:pg-embed"] embedding = ["windmill-api/embedding"] -parquet = ["windmill-api/parquet", "windmill-common/parquet", "windmill-worker/parquet", "windmill-indexer/parquet"] +parquet = ["windmill-api/parquet", "windmill-common/parquet", "windmill-worker/parquet", "windmill-indexer/parquet", "dep:object_store"] prometheus = ["windmill-common/prometheus", "windmill-api/prometheus", "windmill-worker/prometheus", "windmill-queue/prometheus"] flow_testing = ["windmill-worker/flow_testing"] openidconnect = ["windmill-api/openidconnect"] @@ -55,6 +61,7 @@ cloud = ["windmill-queue/cloud", "windmill-worker/cloud"] jemalloc = ["windmill-common/jemalloc", "dep:tikv-jemallocator", "dep:tikv-jemalloc-sys", "dep:tikv-jemalloc-ctl"] tantivy = ["dep:windmill-indexer", "windmill-api/tantivy"] sqlx = ["windmill-worker/sqlx"] +deno_core = ["windmill-worker/deno_core", "dep:deno_core"] [dependencies] anyhow.workspace = true @@ -66,6 +73,7 @@ windmill-git-sync.workspace = true windmill-api = { workspace = true, default-features = false } windmill-worker.workspace = true windmill-indexer = { workspace = true, optional = true } +windmill-autoscaling = { workspace = true, optional = true } futures.workspace = true tracing.workspace = true sqlx.workspace = true @@ -83,8 +91,9 @@ uuid.workspace = true gethostname.workspace = true serde_json.workspace = true serde.workspace = true -deno_core.workspace = true -pg-embed = {git = "https://github.com/faokunega/pg-embed", optional = true, default-features = false, features = ['rt_tokio']} +deno_core = { workspace = true, optional = true } +object_store = { workspace = true, optional = true } +quote.workspace = true [target.'cfg(not(target_env = "msvc"))'.dependencies] @@ -101,6 +110,7 @@ serde.workspace = true windmill-api-client.workspace = true deno_core = { workspace = true, features = ["include_js_files_for_snapshotting", "unsafe_use_unprotected_platform"] } + [workspace.dependencies] windmill-api = { path = "./windmill-api", default-features = false } windmill-queue = { path = "./windmill-queue" } @@ -108,12 +118,16 @@ windmill-worker = { path = "./windmill-worker" } windmill-common = { path = "./windmill-common", default-features = false } windmill-audit = { path = "./windmill-audit" } windmill-git-sync = { path = "./windmill-git-sync" } +windmill-autoscaling = { path = "./windmill-autoscaling" } windmill-indexer = {path = "./windmill-indexer"} +windmill-macros = {path = "./windmill-macros"} windmill-parser = { path = "./parsers/windmill-parser" } windmill-parser-ts = { path = "./parsers/windmill-parser-ts" } windmill-parser-py = { path = "./parsers/windmill-parser-py" } windmill-parser-py-imports = { path = "./parsers/windmill-parser-py-imports" } 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-bash = { path = "./parsers/windmill-parser-bash" } windmill-parser-sql = { path = "./parsers/windmill-parser-sql" } windmill-parser-graphql = { path = "./parsers/windmill-parser-graphql" } @@ -136,6 +150,7 @@ chrono = { version = "0.4.35", features = ["serde"] } chrono-tz = "^0" tracing = "^0" tracing-subscriber = { version = "^0", features = ["env-filter", "json"] } +tracing-appender = "^0" prometheus = { version = "^0", default-features = false } cookie = { version = "0.17.0" } phf = { version = "0.11", features = ["macros"] } @@ -145,7 +160,7 @@ hex = "^0" sql-builder = "^3" argon2 = "^0" quick_cache = "^0" -rand = "0.8.5" +rand = "^0" rand_core = { version = "^0", features = ["std"] } magic-crypt = "^3" git-version = "^0" @@ -157,7 +172,7 @@ urlencoding = "^2" url = "^2" async-oauth2 = "^0" reqwest = { version = "^0.12", features = ["json", "stream", "gzip"] } -time = "0.3.16" +time = "^0" serde_urlencoded = "^0" tokio-tar = "^0" tempfile = "^3" @@ -165,21 +180,25 @@ tokio-util = { version = "^0", features = ["io"] } json-pointer = "^0" itertools = "^0" regex = "^1" -deno_fetch = "0.187.0" -deno_tls = "0.150.0" -deno_console = "0.163.0" -deno_url = "0.163.0" -deno_webidl = "0.163.0" -deno_web = "0.194.0" -deno_net = "0.155.0" -deno_core = "0.299.0" -deno_ast = { version = "=0.40.0", features = ["transpiling"] } + +deno_fetch = "0.195.0" +deno_tls = "0.158.0" +deno_console = "0.171.0" +deno_url = "0.171.0" +deno_webidl = "0.171.0" +deno_web = "0.202.0" +deno_net = "0.163.0" +deno_core = "0.311.0" +deno_ast = { version = "=0.42.2", features = ["transpiling"] } + +swc_common = "=0.37.5" +swc_ecma_parser = "=0.149.1" +swc_ecma_ast = "=0.118.2" +swc_ecma_visit = "=0.104.8" + async-recursion = "^1" -swc_common = "=0.33.26" -swc_ecma_parser = "=0.144.3" -swc_ecma_ast = "=0.113.7" -swc_ecma_visit = "=0.99.1" -base64 = "0.21.0" + +base64 = "^0" base32 = "^0" hmac = "0.12.1" sha2 = "0.10.6" @@ -203,7 +222,7 @@ serde_derive = "1.0.147" const_format = { version = "0.2", features = ["rust_1_64", "rust_1_51"] } dyn-iter = "0.2.0" rsa = "0.7.2" -async-stripe = { version = "0.34.1", features = [ +async-stripe = { version = "0.39.1", features = [ "runtime-tokio-hyper", "checkout", "billing", @@ -214,7 +233,7 @@ rsmq_async = { version = "5.1.5" } gosyn = "0.2.6" bytes = "1.4.0" gethostname = "0.4.3" -wasm-bindgen = "0.2.92" +wasm-bindgen = "=0.2.92" serde-wasm-bindgen = "0.6.5" wasm-bindgen-test = "0.3.42" convert_case = "0.6.0" @@ -245,6 +264,7 @@ indexmap = { version = "2.2.5", features = ["serde"]} tokio-native-tls = "^0" openssl = "=0.10" mail-parser = "^0" +matchit = "=0.7.3" datafusion = "39.0.0" object_store = { version = "0.10.0", features = ["aws", "azure"] } @@ -262,7 +282,16 @@ tikv-jemallocator = { version = "0.5" } tikv-jemalloc-sys = { version = "^0.5" } tikv-jemalloc-ctl = { version = "^0.5" } -# 0.1.12 broken (nested dependency of swc_common) -triomphe = "<0.1.12" +triomphe = "^0" tantivy = "0.22.0" + +# Macro-related +proc-macro2 = "1.0" +pulldown-cmark = "0.9" +toml = "0.7" +syn = { version = "2.0.74", features = ["full"] } +quote = "1.0.36" +regex-lite = "0.1.6" +yaml-rust = "0.4.5" +tokio-tungstenite = { version = "0.24.0", features = ["native-tls"] } \ No newline at end of file diff --git a/backend/custom_migrations/bypassrls_1.sql b/backend/custom_migrations/bypassrls_1.sql deleted file mode 100644 index 1918b26b0b..0000000000 --- a/backend/custom_migrations/bypassrls_1.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE POLICY admin_policy ON account TO windmill_admin USING (true); -CREATE POLICY admin_policy ON app TO windmill_admin USING (true); -CREATE POLICY admin_policy ON audit TO windmill_admin USING (true); -CREATE POLICY admin_policy ON capture TO windmill_admin USING (true); -CREATE POLICY admin_policy ON completed_job TO windmill_admin USING (true); -CREATE POLICY admin_policy ON flow TO windmill_admin USING (true); -CREATE POLICY admin_policy ON folder TO windmill_admin USING (true); -CREATE POLICY admin_policy ON queue TO windmill_admin USING (true); -CREATE POLICY admin_policy ON raw_app TO windmill_admin USING (true); -CREATE POLICY admin_policy ON resource TO windmill_admin USING (true); -CREATE POLICY admin_policy ON schedule TO windmill_admin USING (true); -CREATE POLICY admin_policy ON script TO windmill_admin USING (true); -CREATE POLICY admin_policy ON usr_to_group TO windmill_admin USING (true); -CREATE POLICY admin_policy ON variable TO windmill_admin USING (true); \ No newline at end of file diff --git a/backend/custom_migrations/create_workspace_without_md5.sql b/backend/custom_migrations/create_workspace_without_md5.sql new file mode 100644 index 0000000000..fc140d9e57 --- /dev/null +++ b/backend/custom_migrations/create_workspace_without_md5.sql @@ -0,0 +1,16 @@ +INSERT INTO workspace(id, name, owner) VALUES + ('admins', 'Admins', 'admin@windmill.dev') ON CONFLICT DO NOTHING; + +INSERT INTO workspace_settings (workspace_id) VALUES + ('admins') ON CONFLICT DO NOTHING; + +INSERT INTO workspace_key + (workspace_id, kind, key) + VALUES ('admins', 'cloud', array_to_string( + array( + SELECT chr( (trunc(65 + random() * 25)::int) + + CASE WHEN random() > 0.5 THEN 32 ELSE 0 END ) -- generates random uppercase/lowercase letters + FROM generate_series(1, 32) -- generates 32 characters + ), + '' +)) ON CONFLICT DO NOTHING; \ No newline at end of file diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 8260652cea..e7dd9365ec 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -7cf76a8c6694b59f4615b0c8fa61fb02411326a7 \ No newline at end of file +f136a2f499e0fe7c10c54c79488851980d796eb2 \ No newline at end of file diff --git a/backend/migrations/20240613150524_add_job_perms.down.sql b/backend/migrations/20240613150524_add_job_perms.down.sql index d2f607c5b8..f489666b92 100644 --- a/backend/migrations/20240613150524_add_job_perms.down.sql +++ b/backend/migrations/20240613150524_add_job_perms.down.sql @@ -1 +1,2 @@ -- Add down migration script here +DROP TABLE public.job_perms; \ No newline at end of file diff --git a/backend/migrations/20240807114128_add_rust_lang.down.sql b/backend/migrations/20240807114128_add_rust_lang.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240807114128_add_rust_lang.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240807114128_add_rust_lang.up.sql b/backend/migrations/20240807114128_add_rust_lang.up.sql new file mode 100644 index 0000000000..2a3cc1bae1 --- /dev/null +++ b/backend/migrations/20240807114128_add_rust_lang.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'rust'; +UPDATE config set config = jsonb_set(config, '{worker_tags}', config->'worker_tags' || '["rust"]'::jsonb) where name = 'worker__default' and config @> '{"worker_tags": ["deno", "python3", "go", "bash", "powershell", "dependency", "flow", "hub", "other", "bun", "php"]}'::jsonb AND NOT config->'worker_tags' @> '"rust"'::jsonb; diff --git a/backend/migrations/20240815085729_add_logfile.down.sql b/backend/migrations/20240815085729_add_logfile.down.sql new file mode 100644 index 0000000000..c2a9f2d62d --- /dev/null +++ b/backend/migrations/20240815085729_add_logfile.down.sql @@ -0,0 +1,4 @@ +-- Add down migration script here +DROP TABLE log_file; +DROP TYPE LOG_MODE; + diff --git a/backend/migrations/20240815085729_add_logfile.up.sql b/backend/migrations/20240815085729_add_logfile.up.sql new file mode 100644 index 0000000000..1a79a9e7b1 --- /dev/null +++ b/backend/migrations/20240815085729_add_logfile.up.sql @@ -0,0 +1,16 @@ +-- Add up migration script here +-- Add up migration script here +CREATE TYPE LOG_MODE AS ENUM ('standalone', 'server', 'worker', 'agent', 'indexer'); +CREATE TABLE log_file ( + hostname VARCHAR(255) NOT NULL, + log_ts TIMESTAMP, + ok_lines BIGINT, + err_lines BIGINT, + mode LOG_MODE NOT NULL, + worker_group VARCHAR(255), + file_path VARCHAR(510) NOT NULL, + PRIMARY KEY (hostname, log_ts) +); + +CREATE INDEX log_file_log_ts_idx ON log_file (log_ts); +CREATE INDEX log_file_hostname_log_ts_idx ON log_file (hostname, log_ts); \ No newline at end of file diff --git a/backend/migrations/20240829143329_alert_center.down.sql b/backend/migrations/20240829143329_alert_center.down.sql new file mode 100644 index 0000000000..fe1cb273be --- /dev/null +++ b/backend/migrations/20240829143329_alert_center.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +drop table alerts; +drop table healthchecks; \ No newline at end of file diff --git a/backend/migrations/20240829143329_alert_center.up.sql b/backend/migrations/20240829143329_alert_center.up.sql new file mode 100644 index 0000000000..7cf4f65ba7 --- /dev/null +++ b/backend/migrations/20240829143329_alert_center.up.sql @@ -0,0 +1,16 @@ +-- Add up migration script here +create table alerts ( + id serial PRIMARY KEY, + alert_type varchar(50) NOT NULL, + message text NOT NULL, + created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +create table healthchecks ( + id bigserial PRIMARY KEY, + check_type varchar(50) NOT NULL, + healthy boolean NOT NULL, + created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +create index healthchecks_check_type_created_at on healthchecks(check_type, created_at); diff --git a/backend/migrations/20240831202016_add_json_fmt_to_log_file.down.sql b/backend/migrations/20240831202016_add_json_fmt_to_log_file.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240831202016_add_json_fmt_to_log_file.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240831202016_add_json_fmt_to_log_file.up.sql b/backend/migrations/20240831202016_add_json_fmt_to_log_file.up.sql new file mode 100644 index 0000000000..df50f2bc9a --- /dev/null +++ b/backend/migrations/20240831202016_add_json_fmt_to_log_file.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +ALTER TABLE log_file ADD COLUMN IF NOT EXISTS json_fmt boolean DEFAULT false; \ No newline at end of file diff --git a/backend/migrations/20240906082526_add_ansible_lang.down.sql b/backend/migrations/20240906082526_add_ansible_lang.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240906082526_add_ansible_lang.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240906082526_add_ansible_lang.up.sql b/backend/migrations/20240906082526_add_ansible_lang.up.sql new file mode 100644 index 0000000000..6f9df11f42 --- /dev/null +++ b/backend/migrations/20240906082526_add_ansible_lang.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'ansible'; +UPDATE config set config = jsonb_set(config, '{worker_tags}', config->'worker_tags' || '["ansible"]'::jsonb) where name = 'worker__default' and config @> '{"worker_tags": ["deno", "python3", "go", "bash", "powershell", "dependency", "flow", "hub", "other", "bun", "php", "rust"]}'::jsonb AND NOT config->'worker_tags' @> '"ansible"'::jsonb; diff --git a/backend/migrations/20240906151147_add_success_handler.down.sql b/backend/migrations/20240906151147_add_success_handler.down.sql new file mode 100644 index 0000000000..33b6e62539 --- /dev/null +++ b/backend/migrations/20240906151147_add_success_handler.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +ALTER TABLE schedule DROP COLUMN on_success, DROP COLUMN on_success_extra_args; \ No newline at end of file diff --git a/backend/migrations/20240906151147_add_success_handler.up.sql b/backend/migrations/20240906151147_add_success_handler.up.sql new file mode 100644 index 0000000000..3465ed5ea5 --- /dev/null +++ b/backend/migrations/20240906151147_add_success_handler.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +ALTER TABLE schedule ADD COLUMN on_success VARCHAR(1000), ADD COLUMN on_success_extra_args json; \ No newline at end of file diff --git a/backend/migrations/20240907150910_migrate_to_new_cli.down.sql b/backend/migrations/20240907150910_migrate_to_new_cli.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240907150910_migrate_to_new_cli.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240907150910_migrate_to_new_cli.up.sql b/backend/migrations/20240907150910_migrate_to_new_cli.up.sql new file mode 100644 index 0000000000..aa88241d14 --- /dev/null +++ b/backend/migrations/20240907150910_migrate_to_new_cli.up.sql @@ -0,0 +1,11 @@ + +-- Add up migration script here +UPDATE script SET content = 'import * as wmill from "windmill-cli@1.393.2" + +export async function main(x: string) { + await wmill.hubPull({ workspace: "admins", token: process.env["WM_TOKEN"], baseUrl: process.env["BASE_URL"] }) + return x +} +', language = 'bun', +lock = '{\n "dependencies": {\n "windmill-cli": "latest"\n }\n}\n//bun.lockb\n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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACmAgAANAAAgAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA2gIAAE4AAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADEDAAA6AACAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABrAwAASAAAgAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAswMAAEYAAIAFAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABYEAABMAACABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABiBAAAPgAAgAQAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAArwQAAEYAAIAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPUEAAA7AACACgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA/BQAARgAAgAIAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAkwUAAEQAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANcFAAAyAACAAwAAAAcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAqBgAATAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdgYAAEYAAIACAAAAAwAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMHAABEAACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABHBwAARAAAgAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAiwcAAD4AAIAFAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkHAABQAACAAgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAZCAAANgAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAATwgAADgAAIACAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAIcIAABAAACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADHCAAAMQAAgAEAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA+AgAAC4AAIADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAC8JAAA6AACAAwAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABpCQAASAAAgAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAsQkAADcAAIAEAAAAEwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8KAABOAACAAAAAAAUAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAANCwAAPgAAgAUAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAASwsAAEoAAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJULAABIAACAAQAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADdCwAARAAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAIQwAAEQAAIAAAAAAAQAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGUMAABCAACAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACnDAAAQQAAgAEAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA6AwAAD4AAIABAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACYNAAA6AACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABgDQAAOAAAgAEAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAmA0AADEAAIAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkNAABAAACAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAJDgAAPgAAgAIAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAARw4AADgAAIABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAH8OAAA+AACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADJDgAAQAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACQ8AADgAAIACAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEEPAAAwAACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABxDwAANgAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAApw8AADIAAIAAAAAABQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANkPAAAyAACAAgAAAAYAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAALEAAALAAAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxAAADAAAIABAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGcQAAAwAACAAQAAAAgAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACXEAAALAAAgAIAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAwxAAAEAAAIABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMRAAA0AACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA3EQAAQAAAgAEAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdxEAAD4AAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAALURAAA/AACAAQAAABQAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD+EQAAPQAAgAAAAAAEAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAUxIAAEAAAIACAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJMSAAA4AACAAgAAAAUAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADLEgAAMgAAgAMAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA/RIAADcAAIABAAAABgAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEkTAAA+AACAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACHEwAAPQAAgAIAAAABAAAAIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxBMAADcAAIABAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPsTAAAtAACABgAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA0FAAAQAAAgAEAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAoRQAAEUAAIABAAAADQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOYUAABCAACAAQAAAAIAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABJFQAANAAAgAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAfRUAAEIAAIABAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8VAAA+AACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD9FQAAOgAAgAEAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxYAADoAAIABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHEWAAA6AACAAQAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADQFgAATgAAgAEAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAShcAAFgAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKIXAABMAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADuFwAAMAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAHhgAAFAAAIABAAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAG4YAAA8AACAAgAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC8GAAAOgAAgAEAAAAJAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA9hgAADoAAIAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADAZAAA2AACAAQAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABmGQAANgAAgAEAAAADAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAphkAADwAAIAAAAAABgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOIZAAA0AACAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAWGgAAMAAAgAEAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAURoAADcAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGgcAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACsHAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA8hwAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADodAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAB+HQAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxh0AAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABIeAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABYHgAARAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAnB4AAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOQeAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAwHwAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAeB8AAE4AAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMYfAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAASIAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAWCAAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKAgAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADkIAAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAALCEAAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHghAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC+IQAASgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACCIAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAFAiAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACcIgAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA5CIAAEQAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACgjAAA2AACAAQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABeIwAAMAAAgAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAjiMAADsAAIAAAAAACQAAAD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANQjAAA+AACACQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAASJAAAPAAAgAAAAAAGAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAwAAAANAAAAAgAAAA8AAAAAAAAADwAAAAEAAAAQAAAAAAAAABAAAAACAAAAEgAAAAAAAAASAAAABAAAABYAAAABAAAAFwAAAAEAAAAYAAAAAAAAABgAAAAAAAAAGAAAAAIAAAAaAAAAAAAAABoAAAABAAAAGwAAAAAAAAAbAAAAAQAAABwAAAABAAAAHQAAAAAAAAAdAAAABAAAACEAAAAAAAAAIQAAAAcAAAAoAAAAAAAAACgAAAABAAAAKQAAAAAAAAApAAAAAAAAACkAAAAAAAAAKQAAAAAAAAApAAAAAAAAACkAAAAAAAAAKQAAAAEAAAAqAAAAAAAAACoAAAAAAAAAKgAAAB8AAABJAAAAAQAAAEoAAAAAAAAASgAAAAAAAABKAAAAAAAAAEoAAAAAAAAASgAAAAAAAABKAAAAAAAAAEoAAAAEAAAATgAAAAAAAABOAAAAAAAAAE4AAAAAAAAATgAAAA0AAABbAAAAAAAAAFsAAAABAAAAXAAAAAAAAABcAAAABQAAAGEAAAAAAAAAYQAAAAAAAABhAAAAAAAAAGEAAAAAAAAAYQAAAAAAAABhAAAAAQAAAGIAAAAAAAAAYgAAAAAAAABiAAAAAAAAAGIAAAAAAAAAYgAAAAcAAABpAAAAAAAAAGkAAAAAAAAAaQAAAAAAAABpAAAADAAAAHUAAAABAAAAdgAAAAAAAAB2AAAABAAAAHoAAAAAAAAAegAAAAIAAAB8AAAAAAAAAHwAAAABAAAAfQAAAAAAAAB9AAAAAQAAAH4AAAAEAAAAggAAAAAAAACCAAAABQAAAIcAAAABAAAAiAAAAAAAAACIAAAAAAAAAIgAAAAAAAAAiAAAAAAAAACIAAAABQAAAI0AAAAGAAAAkwAAAAEAAACUAAAAAQAAAJUAAAABAAAAlgAAAAMAAACZAAAAAgAAAJsAAAAAAAAAmwAAAAAAAACbAAAAAAAAAJsAAAACAAAAnQAAAAAAAACdAAAAAAAAAJ0AAAAAAAAAnQAAABgAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAMAAAC4AAAAAAAAALgAAAABAAAAAAAAAAEAAAABAAAADAAAAA0AAAACAAAADwAAAAAAAAAPAAAAAQAAABAAAAAAAAAAEAAAAAIAAAASAAAAAAAAABIAAAAEAAAAFgAAAAEAAAAXAAAAAQAAABgAAAAAAAAAGAAAAAAAAAAYAAAAAgAAABoAAAAAAAAAGgAAAAEAAAAbAAAAAAAAABsAAAABAAAAHAAAAAEAAAAdAAAAAAAAAB0AAAAEAAAAIQAAAAAAAAAhAAAABwAAACgAAAAAAAAAKAAAAAEAAAApAAAAAAAAACkAAAAAAAAAKQAAAAAAAAApAAAAAAAAACkAAAAAAAAAKQAAAAAAAAApAAAAAQAAACoAAAAAAAAAKgAAAAAAAAAqAAAAHwAAAEkAAAABAAAASgAAAAAAAABKAAAAAAAAAEoAAAAAAAAASgAAAAAAAABKAAAAAAAAAEoAAAAAAAAASgAAAAQAAABOAAAAAAAAAE4AAAAAAAAATgAAAAAAAABOAAAADQAAAFsAAAAAAAAAWwAAAAEAAABcAAAAAAAAAFwAAAAFAAAAYQAAAAAAAABhAAAAAAAAAGEAAAAAAAAAYQAAAAAAAABhAAAAAAAAAGEAAAABAAAAYgAAAAAAAABiAAAAAAAAAGIAAAAAAAAAYgAAAAAAAABiAAAABwAAAGkAAAAAAAAAaQAAAAAAAABpAAAAAAAAAGkAAAAMAAAAdQAAAAEAAAB2AAAAAAAAAHYAAAAEAAAAegAAAAAAAAB6AAAAAgAAAHwAAAAAAAAAfAAAAAEAAAB9AAAAAAAAAH0AAAABAAAAfgAAAAQAAACCAAAAAAAAAIIAAAAFAAAAhwAAAAEAAACIAAAAAAAAAIgAAAAAAAAAiAAAAAAAAACIAAAAAAAAAIgAAAAFAAAAjQAAAAYAAACTAAAAAQAAAJQAAAABAAAAlQAAAAEAAACWAAAAAwAAAJkAAAACAAAAmwAAAAAAAACbAAAAAAAAAJsAAAAAAAAAmwAAAAIAAACdAAAAAAAAAJ0AAAAAAAAAnQAAAAAAAACdAAAAGAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAwAAALgAAAAAAAAAuAAAAAEAAAAAAP4P/gEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAQD+D/4BAAABAAAAAAAAAAAAAAAEnFcorsSkCz8vYXAoZrKLi9czdIvLIYptbISOLuy4R+UtJGOUkjeYcwquPiSjBCSKdzYL5hFPVeFeiuj7326sDgEAAAEA/g/+AQAAAgAAAAAAAAAAAAAABKENAlZjoqOt8JYcEBe+cwOIqKJT7zsAKCtMrs3EuWwwtSVLx98tRkvMT4fBDqXKA0EVOBUxvDkH8YaUfnOg68wBAAABAP4P/gEAAAMAAAAAAAAAAAAAAATicyF5ykaU+LRxLNPrsv5Ob4Y4mq+6TyCocHOKpxRA5que4hrHXP3r+AkcJIjPZnTOHETpHPBvchlc+0WHnWP7AQAAAQD+D/4BAAAEAAAAAAAAAAAAAAAEGlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscgEAAAEA/g/+AQAABQAAAAAAAAAAAAAABC6Qf+eAfv9ieYakO4pmR33VN9TpYEKse2YnFZZJvZM4Pf8PBiixHBXyZf7ewwhA7njsgQA+swgsEzuhc7NDaBEBAAABAP4P/gEAAAYAAAAAAAAAAAAAAATxVt9Z8cttvC7f43o4qw4ykF1PiRc8MMH1wmTZsnqaH25zF2Wc28fV76uhiQqY303HDbKPPtXN472g7PbMnTg/AQAAAQD+D/4BAAAHAAAAAAAAAAAAAAAEUjCbBB2IeyMVoDyO16boHEsTus2npVtXyER2pfP0zm7rmp6ko65HA3OXvMzhMVq3hW9RQ5esc3mrkTnb19PIawEAAAEA/g/+AQAACAAAAAAAAAAAAAAABJp5HkNaj+VHtsHfmor0w9zR3f5Wfei7tI4H9KcJLSz7cenE2Yh+7cnhkUR7NM19K262oVz515VJ23l8mgQbiGsBAAABAP4P/gEAAAkAAAAAAAAAAAAAAARRxV9V9orhJzibtfd1RKgeijNAYEQV4ML7NWjTq33zF7wLMdJlkF6Q1cf627Q1qUeiVwn9AAapLjod5/tBcEgzAQAAAQD+D/4BAAAKAAAAAAAAAAAAAAAEKIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRAEAAAEA/g/+AQAACwAAAAAAAAAAAAAABHpY3IBA5RJ7P+wFxaLAeSv9pwjOD+xUD5BnPw1i8ua5hRFr2Wshq4pNXff0CGOZyeH/WLFbwZAOpCaR5/ayEnUBAAABAP4P/gEAAAwAAAAAAAAAAAAAAAQ34x5diiqvek6CfzF/JE9EQ3uAdqQtiOGweFYZPd9YCIvgiQC3SIPDXhCKISbZsTfRzldfmrQW0ADcIrl/38FSAQAAAQD+D/4BAAANAAAAAAAAAAAAAAAEWY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8XgEAAAEA/g/+AQAADgAAAAAAAAAAAAAABAOqf6bv+n8gXANU0c/xqlmD1YqZa37XFtoGQvau/Z4DQigHkf194HBHV0B5eCjV1ft8ICCdQj5CUNyBzOpXLMgBAAABAP4P/gEAAA8AAAAAAAAAAAAAAAS2PAzl7EyDoEZEj6Q2ZOe02y91lLVfwEVhLq2cnaF0fSRXEzr95VnbHL4WpK1Ja9ia18UwMsjG6uisfAMp8PPlAQAAAQD+D/4BAAAQAAAAAAAAAAAAAAAE9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1AEAAAEA/g/+AQAAEQAAAAAAAAAAAAAABHrYV07d0hhkfveYLnZqidXjYUTu3hhBiIGAPb5z2rSuP3rc9jBFQ56ORjAom3TE7gTMhJcyJYMTJ2tyveFwyA0BAAABAP4P/gEAABIAAAAAAAAAAAAAAARecAi9Dx4z6QLppQvHrC5CLBWyfOyL13dbHNXcWlZMYDX0XrbWTB1uwBwUpeApQdlazL6ZjqIvWwdPFYQULK0MAQAAAQD+D/4BAAATAAAAAAAAAAAAAAAE3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5PwEAAAEA/g/+AQAAFAAAAAAAAAAAAAAABIIS9Lc9VxvWRJkTHBDdr7e8Wm6w3ahx3spIAEaZmdAYiHLVsTOO1bet2TtnZ6eEGLf8SVSy8uWb9Zf8UXYdm8oBAAABAP4P/gEAABUAAAAAAAAAAAAAAAQuLkA6qtlYJUDafmSvLMSapqLpspIi+nPmhQkc9WPr52xsPdfWLG2xjm0Sexo2kfekUAeYbx4gdSu0S2iGuD5RAQAAAQD+D/4BAAAWAAAAAAAAAAAAAAAE8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdAEAAAEA/g/+AQAAFwAAAAAAAAAAAAAABBDw+atbl8hcSaQqy5wnNZx56t4Dmug2QaHACIiNk2kggO1QidVCQzGoAsyJFzbFGHw9XWiv/y0xEPMYiG6x7XMBAAABAP4P/gEAABgAAAAAAAAAAAAAAASf9KGe8OLoUdttV++Kuj5aiOIXO/6zww8wcFzNV499SkMkvCgtPSG3WXhjAEJuLykkC94QR2eQfI/JM/+bNF/CAQAAAQD+D/4BAAAZAAAAAAAAAAAAAAAEGd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+gEAAAEA/g/+AQAAGgAAAAAAAAAAAAAABN6LlDqUIbYK2zmteye/rsTk6SE2Fmhj+/wIaEd/gPv9XvbJK83pRov3V8xGMr28bmxBelp9sqbHEyoiiRRZ9WoBAAABAP4P/gEAABsAAAAAAAAAAAAAAARUuCEhY0zoQtDOjvPCZyDQ2ZNXJYpiO8h4zzfKOnTBENOZSeszrvx9BtwoGjqfYIkQXSzOgb//K2D5MqVrz0AtAQAAAQD+D/4BAAAcAAAAAAAAAAAAAAAEk/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQEAAAEA/g/+AQAAHQAAAAAAAAAAAAAABGUAb4tQ3KSeBg6mp47nGdh498BDuaWQ0vPQVm5HK73cZLCaK8FAw2Wpl/ZXRZKfWsNpZgQy4JDmxAOA1jSfRWEBAAABAP4P/gEAAB4AAAAAAAAAAAAAAATiEsHw/LjNlx7mzjJ31fOimrBW//IY2FXUGXw1OYKrXvrcd4rb4TBVO/6V4Z4vXcOeHbB9uqjBU9cIg7TPi1pjAQAAAQD+D/4BAAAfAAAAAAAAAAAAAAAEUaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQEAAAEA/g/+AQAAIAAAAAAAAAAAAAAABF1zhbcqg4zQwEMVX2Mbhe4PSJfyG1pppUINjGCjh/BMSE9aoOsXOM8ktx2hBAE4LNW7X88ateXIlImO4I0l0RkBAAABAP4P/gEAACEAAAAAAAAAAAAAAARfqampS/n25YsYPifeFnwK7wpsXY8xY9IVibFmN2SmbfI5TuFJRifNORkjWZxapyGmG+rK7Pf8GGAFHgT8m2QKAQAAAQD+D/4BAAAiAAAAAAAAAAAAAAAE5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9QEAAAEA/g/+AQAAIwAAAAAAAAAAAAAABBb3mUzbhsNOHMZQIlm84us0wC/5YXoWlm07YJbiYePxPeQ6jME5oWtymTdWgFgPHBSIR8zGVLy3r5MOUapPrUkBAAABAP4P/gEAACQAAAAAAAAAAAAAAASundKjTspx2aYpsa+Bo3FBImvtsZVJWTlL0SrUX6mltGjvT5h5oPGTDkN3w0834YPpuOdibZW4+4Jeam5i+YJdAQAAAQD+D/4BAAAlAAAAAAAAAAAAAAAEcCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1wEAAAEA/g/+AQAAJgAAAAAAAAAAAAAABEAA85Wh3PInFfCO722iVycKHfR1mKfLgqn9cWuDnzbtU+yVcUCK1IDlrR3TQ7T4ssJhW4ktdlY6LSFy6yjN6K0BAAABAP4P/gEAACcAAAAAAAAAAAAAAAQTksNftaunzkqKXluFm/jqPyM55ugqrkkyZgzeBUZ0YfzEWk9ZdQyw2uU4MKuSjEwR42L9dkjC5G9jhc3BgwmnAQAAAQD+D/4BAAAoAAAAAAAAAAAAAAAE5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQEAAAEA/g/+AQAAKQAAAAAAAAAAAAAABDwlQELMFnprulHcbAxRV//oFXmKigKHdw91FZvdYx8Mp4LjsAL2D4cfJzZTPvjakXCugscaVGn45oSHSoh4m6oBAAABAP4P/gEAACoAAAAAAAAAAAAAAARca5EM2NdSKOxQvS+XqdIPtzBRG7MSCCVs5oW5kz2DeTANc5ZVNyTSMvOM/MYP5NrNZtuhli7nb/39c91SCd72AQAAAQD+D/4BAAArAAAAAAAAAAAAAAAENiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9owEAAAEA/g/+AQAALAAAAAAAAAAAAAAABEzyV6vCahWlWJtglpj75z9iMqOGUjO/0CnEprjCwzm36R+X4u0VBpnf60w3/q7rf7Gog4kBHlUzYAJiRHQDsdMBAAABAP4P/gEAAC0AAAAAAAAAAAAAAAQKLJ47EVP8lnI3mbTP099fDhIIEnpLKDPUOmXTCqOWEMQYYE/UaexRUQvSnreGgbV9yPd8fKdeL01g7idY4v6pAQAAAQD+D/4BAAAuAAAAAAAAAAAAAAAEqqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXgEAAAEA/g/+AQAALwAAAAAAAAAAAAAABB64LMfqK6qMoJ5oRWymhxOnNveifh0wEF6MRBeoDbqUTpphiUaMs3xt3HAL3qgga8K/9ssUOQVXfxk5eWoDsEoBAAABAP4P/gEAADAAAAAAAAAAAAAAAAShWXOSDcQ0CEKTbN2/sgnB39BQPjPZHFHCmRwZjymwJVwJhk2rjBidVYAscz5uu24mN49aJgX8KWa4OvwKHn6SAQAAAQD+D/4BAAAxAAAAAAAAAAAAAAAEWMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlowEAAAEA/g/+AQAAMgAAAAAAAAAAAAAABBbcKxv3rgc2hI2HkajoJcuxtKr4ol6CVp7xB9mdaZQXV4G8o79+KR00m/c6HhzMg8t9/g1suVrfVqPk1EbTmEkBAAABAP4P/gEAADMAAAAAAAAAAAAAAASjmxI8oSSD8MhA2YfjdXT+56suunNV52RSHy0Y29p5el+m7CMp6eVKjH/Y78FOVlS0R74kbuzliETPrTw+UAdEAQAAAQD+D/4BAAA0AAAAAAAAAAAAAAAERwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQEAAAEA/g/+AQAANQAAAAAAAAAAAAAABIO5x+j+ncg4qCaIAABqaxqQrVSJiYaT5P66As3W93yIetf7P5z7H0eqJ8jMJAgEfzpQt8gQtJREr1KEBALLCK8BAAABAP4P/gEAADYAAAAAAAAAAAAAAATawkYlNpcghpHXDiIlI2g3SGcxjsalz+fwPipIInDxCoVZd/ty4CCcQfEGnB5pVw968LaXcqmNgLHc3KlBCBomAQAAAQD+D/4BAAA3AAAAAAAAAAAAAAAEzJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8QEAAAEA/g/+AQAAOAAAAAAAAAAAAAAABGwuxJa3SWiZz2wD/tRKLWL6mbG93nJecIugX4ugSU1HDaMKenL7KYNI1850Uyg45vxOwHYBQVXgD1TDXChrBzABAAABAP4P/gEAADkAAAAAAAAAAAAAAAROmnrQ/ohQkNO46r/lnxx2yTMm6N/Cp85OSvAjCPshEhKmeQmdPpLIng8I+cYygWML112FqXkpUhi0C33uLHTkAQAAAQD+D/4BAAA6AAAAAAAAAAAAAAAEx0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQegEAAAEA/g/+AQAAOwAAAAAAAAAAAAAABGiC+Rce5msFWt9NGpdgZxBOIjb6NahE8S6zyP6NOS+8+oKO3wsNSehEJmyuBZidgEu5IFRfyhGVrnwX3QpTHD4BAAABAP4P/gEAADwAAAAAAAAAAAAAAAToWXO5tMtkbcnZr81UICV4SGPOrmjGAfJoJT3Jhe9wuy+hVocmr+znFcjr9dc/q3PtH3EA60edI7+1e0XdZFOUAQAAAQD+D/4BAAA9AAAAAAAAAAAAAAAE5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISgEAAAEA/g/+AQAAPgAAAAAAAAAAAAAABKY8tm2IUrLn8FpSsD3Ppd3De/sLiZSurs9GHSRDpUA25eo6P2JT4uJm/GoFJFQvARe1fDbs3sjzakZLAN4c7SkBAAABAP4P/gEAAD8AAAAAAAAAAAAAAASdOOp9wEUSKkp1cK/hgNBYJ+ZwtkqbzWV0XSkCilO/KsUZVtxHo/9UAB3kbs37S1OvxCqJTS0Vp0PoUrg20nA4AQAAAQD+D/4BAABAAAAAAAAAAAAAAAAEpMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hAEAAAEA/g/+AQAAQQAAAAAAAAAAAAAABJpfaUXgrtzOtZBpaqE5trpkl05UU7hk8dG32I/riFCimMnBuTbUm3nrVd32klOke2ozj8NIPydT7yuKjcu7OWwBAAABAP4P/gEAAEIAAAAAAAAAAAAAAAS/cxedkBy+fLCRNQRmiYgBy2V7tFdd5505HfXDCXtWXKhc7hCL1qu9J6c1Bad7VNxHCEIvUfAsjbVsSp2mPz+sAQAAAQD+D/4BAABDAAAAAAAAAAAAAAAEYZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtgEAAAEA/g/+AQAARAAAAAAAAAAAAAAABPMxqsqXxDYwiKhoYF06AvGgdq+2KwV/gEAHyD7PzJZPgbT087Tr00tNTUVv9xIetCfmuPJbfKrAs4q0OpaAlXwBAAABAP4P/gEAAEUAAAAAAAAAAAAAAAT81/tPLNPHpLfJEk5s4BXv3nqvxyvb46PwALl23zBI/cFACh5fnw2gfIJTw/zMaQ1dK2NNKLp/M7oXSkF1xhsSAQAAAQD+D/4BAABGAAAAAAAAAAAAAAAETkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8gEAAAEA/g/+AQAARwAAAAAAAAAAAAAABHavqnpUPWpB6XDpf4FFUU8VSDpACdcEd0AL2+EbFY0vKFaBYwxk3Ou/cCWJlJpJ1BeR8DCzoG+TvmtysX1mqT0BAAABAP4P/gEAAEgAAAAAAAAAAAAAAARkNj5s+bnNNMX5ikKsBT2crRSAgJg9PRC1PU1lYW/iz75M2RyBVpPSDr7hHa4jgyNCPPKwcHXPG5YvnSHNp5eLAQAAAQD+D/4BAABJAAAAAAAAAAAAAAAEsPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvgEAAAEA/g/+AQAASgAAAAAAAAAAAAAABDL46DAicBGq0m1GJOTvp5qEs0rrUrE8BfOc3Bz0PTq5RaGTmCI2qgQCSKiF46bcg+b04cRqudl7vzGic0ZCJOEBAAABAP4P/gEAAEsAAAAAAAAAAAAAAAR8Nb8RnpD1GI7x4UbweP7u7+hb5es9MgKHAI4zb62HYDo5uUO1hgim972b4q8j1ngL2pIReVoZHptMRgdF66CUAQAAAQD+D/4BAABMAAAAAAAAAAAAAAAEIRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3gEAAAEA/g/+AQAATQAAAAAAAAAAAAAABObmIbCR/FSQU7+6LJYOAc5yWIQ6ESOsGmAsTJgnZ063AqxwP3whSqExc9iSihNB3QxVBe/6ELoc7plySu6WgUUBAAABAP4P/gEAAE4AAAAAAAAAAAAAAATSElT1II++YzMgF1kWo09dZrp2qHtZ0fRwgj3L4LJLysbecvjwFyWtr0eYqFVVQfI9Y0fljvEPAAHtt+BKORQxAQAAAQD+D/4BAABPAAAAAAAAAAAAAAAE7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SAEAAAEA/g/+AQAAUAAAAAAAAAAAAAAABJdywrhejIAzcEwypHWBhIoWI7eaUT2xIOOq7ZZp0j5VG4JgfCziKyiW2GBQUm5z2iXsTCrYjzvIZnkY0c9k3fgBAAABAP4P/gEAAFEAAAAAAAAAAAAAAARInVqZkAlSJlL4+GxUt/m0bJ2VpUHwR0WlpI7iCaJQpQ7GTyrOfkAjLhl4lSaHbbOch2T+4wBRPamXcXHNVQf5AQAAAQD+D/4BAABSAAAAAAAAAAAAAAAEZf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6cswEAAAEA/g/+AQAAUwAAAAAAAAAAAAAABBh00jUmCAkO7HB+7GfjNqxaKUaC4fLdmy0lugW4K7S7GoTiAeYsgFSX/Ro1it3GEw2jI+F3QaTNXAOqSEtCr9sBAAABAP4P/gEAAFQAAAAAAAAAAAAAAASmBFziEnj+w2NYJJL0CadLjTHds0wNOSceAvlRowFMzImdT3QSBaHVHP4wL14W7gG439TBmMpC5j/W/eszscx+AQAAAQD+D/4BAABVAAAAAAAAAAAAAAAE55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrgEAAAEA/g/+AQAAVgAAAAAAAAAAAAAABI8WsiykoaxKqsydHrpkG1YU2EDNuwn09U9+foAoAxaC/NiS7F6kye+s7+gNGCzoBJy1DLy87A7BiK5fDRaU9oEBAAABAP4P/gEAAFcAAAAAAAAAAAAAAAR3rls2Uhp3G+lv8DZptV2WoqpXnreO5GdnVa2TqzWwhHy42xdHvTGojNWrFV/V5OoO6fBPYyRzMR5p7MIpNmHAAQAAAQD+D/4BAABYAAAAAAAAAAAAAAAErBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+AEAAAEA/g/+AQAAWQAAAAAAAAAAAAAABJZULDC0lA1D0+OI3a1Pzt+6pZ4n4rQz/mcK5pmXKEisiyr7WcacldJ9v2w/zeLQQAGf4CRHWVOyjK2qCtfl2AIBAAABAP4P/gEAAFoAAAAAAAAAAAAAAATQoj/rTvGjFJOgfsaM3UV9JsuhTT5u1OJyOxBJZCWH+FnKQ3wqmYx/u5jA9bdH5qRnpH/DXxmVdIcFheJhQ87eAQAAAQD+D/4BAABbAAAAAAAAAAAAAAAEbuRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYowEAAAEA/g/+AQAAXAAAAAAAAAAAAAAABInJQB3jajZuvMxbZ2dHvtS9slCHb8zaGrilOFgQN1bx/7zxYnhe6n0ZcFGVPgwPT/Wz1yEvdLpcaFKAh9t7FdsBAAABAP4P/gEAAF0AAAAAAAAAAAAAAAQ9gC2FNrabZUrG69IPcM8L8bL5T6w4DUsC5PyaSZG6/D40AJJp5cRD40dxUXus42XqpxrFXdS56bBrCT7v5IkvAQAAAQD+D/4BAABeAAAAAAAAAAAAAAAE+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBgEAAAEA/g/+AQAAXwAAAAAAAAAAAAAABFO9XMk2prodQkTQn6RmOraNvJcbzcDxuBrs/xFY4H9yZs79L5Q6dWrU/XkuXQ4zGB7nKR21p7Oi8H9wSs+rL3cBAAABAP4P/gEAAGAAAAAAAAAAAAAAAAQE0ZtYt93R5Q9puGRdRWbSPy669ETJOHmi9Fr93KjD8GoBtknIL7l9T4jNA7OYArNiphEAhKhGF1Cvd4hn89eqAQAAAQD+D/4BAABhAAAAAAAAAAAAAAAEVVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEgIAAAEAAAiAAAAAYgAAAAAAAAAAAAAABAR6RRXrJZFq11slD52ypvsWGFWK7gopxnH7UgWmvM6BfYWTuAXEghVLx1U7c6SGOmM1J2LbhIWfgvYhF48Z2rIBAAABAAgAgAAAAGMAAAAAAAAAAAAAAAQFxovRWfpDALCt7djvXudUdlsBrhQESKDMWbpV2xV1P8xtnfzGiPVf0c+RmFuZoEZQPVby/EB999sN7xsDoAqdAQAAAQAEAIAAAABkAAAAAAAAAAAAAAAE4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6AEAAAEAAAhAAAAAZQAAAAAAAAAAAAAABEQUU9oKhJdCCkAAU+F04+/LaZPb+3oafpms59h21HmZdWDHWhgEKoWqYxkwnu7sO8tH6w4uIEtLh84b6RbiNbABAAABAAAIIAAAAGYAAAAAAAAAAAAAAARpjaAyYqY+HF9T7QR2c35c20ZuN9CDBmPjeTwbd/KsMz9R1nDDrGtbGYOS7PZ4JlyGpV4AGNXkGmKV06tRsFOoAQAAAQAEACAAAABnAAAAAAAAAAAAAAAE3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+QEAAAEAAAgAAAAAaAAAAAAAAAAAAAAABGnrxJAjbuypT0aWC48JnXLjc+mwxYhO2fFwuAj6hMY076x7oIdvEM1F1TmbYmIIXIilGnDZLasXacpqZYpdW3gBAAABAAAIEAAAAGkAAAAAAAAAAAAAAAQRXr6i9OwRcI8CnnyDZ0PrwvGg//ArmlG+DLQn8fE8YHTT2iYU+/dh63QeJqq+siuA9MG4LrAIfUtM5j3UQ7mFAQAAAQAAAhAAAABqAAAAAAAAAAAAAAAE9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDwEAAAEAAAAQAAAAawAAAAAAAAAAAAAABOQFeD86fNH4Ry/NyTOi6AOqU0FVoAdR6LzAbC0PTmViw6lWPDFaGwVzUpgCYv/wrIerXGO3uy58th4NbRJTIyABAAABAIAAEAAAAGwAAAAAAAAAAAAAAAR0o3x+BWp3S9QiPG4kjo//1JJJ7+YH2u8D3wJIfawmeVn84JlY7UMm/GPyO8pN9hR0Z9yrZ0PGgpoLpse5OWBzAQAAAQAAABAAAABtAAAAAAAAAAAAAAAEnrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3QEAAAEAAAAQAAAAbgAAAAAAAAAAAAAABFcdPS8xKAWucw54nh/C0jEU6I+4q/yXqtBruqif9RnAavRpH6BAKF7y4ltVPSdahP2Pzsmqt98OadmVqzTRzRMBAAABAAgAEAAAAG8AAAAAAAAAAAAAAARVM3gS44fBcSRfNfmdO9VjizsT8qvPsI4LzGR+1tspFgCX3q8+JSywaR4wQtAw6cs4nyTcFjX5ljna221mcdxdAQAAAQAEABAAAABwAAAAAAAAAAAAAAAE/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754gEAAAEAAgAQAAAAcQAAAAAAAAAAAAAABAl15M4J/nVwD7N1gcBPir563+FhAsAXX433mB6THlcVhNBHHger4VhkobOsItCGBKjEiM3ThdV40PzJJuXe2XUBAAABAAAICAAAAHIAAAAAAAAAAAAAAASUrV4l7KTVlfxSSWoV3/cDrRS5n/pRV8ZPYu4ajdanj/Pt5FNFhj7TE67aSkKU/68xOL3Ao59eLa+NSk7VGjvqAQAAAQAEAAgAAABzAAAAAAAAAAAAAAAEh1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhAEAAAEAAAgEAAAAdAAAAAAAAAAAAAAABGgpanYEw1T0hBoKAkvEAxt+xrvMnPZUxzQEJbM7UOhDXrShDv/2/Mt9TDLtmWj25+JFbCAAc1S12C4QhnpBg6sBAAABAAQABAAAAHUAAAAAAAAAAAAAAARixLZ7da2CfDtarnddcEtxXomFGwSryGR+D3URJVp0ivOv3A7qMkMxmcJBsebUa5zm38J0OIVJJ9Y/nwU269PdAQAAAQAACAABAAB2AAAAAAAAAAAAAAAEnlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlRegEAAAEABAAAAQAAdwAAAAAAAAAAAAAABMcOdIqcpF3C7LS3lh+1kXULsrCano7gBj3d9L3dYuc0siit1hPoo8x5iysXYgjLR9aR8+/KzoNASkmDkgf9iocBAAABAAIAAAEAAHgAAAAAAAAAAAAAAAS7Pr+0TLYgWb1Fg7K8qXzzN3Nl/AR8pmadf0KPUEeN5IY24Yu4wPWRHzLlu15ibCoqbW2Pybhxv9ooSiuvp8dZAQAAAQCAAAIAAAB5AAAAAAAAAAAAAAAE6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQEAAAEA/g/+AQAAegAAAAAAAAAAAAAABAMzkSnc9Wbfe0822EJyKyN2Yom1qUV1H6aP8NMTidtBqTWHdm3dzFPZt9c0v2idUyZeiXy06JPN2PB4zbp2E9ABAAABAP4P/gEAAHsAAAAAAAAAAAAAAAQ8lYdRvVEV68oLBoUD1GUbm0J34U7mJGH0DwcS2SYEfYuLTeImuIHqbokg3isbPcrcktrAjv+94DXHNEo/ohIHAQAAAQD+D/4BAAB8AAAAAAAAAAAAAAAEWjvinW/rM9KEauFCgiRU1VM6Vn4zvv0bPy6DcvjHLNKl1F9cLMW0axsqGqcpQdEr9X9A5V4lWV2cNiXTDUZXhQEAAAEA/g/+AQAAfQAAAAAAAAAAAAAABDLu0dIOIoPU1LhksSWr58uUb9HoAhLaWUTTK2WmEtb8ZIiMRohlMKHs1Ny2syEPihNOIU603zT4MVOYM4uxeT8BAAABAP4P/gEAAH4AAAAAAAAAAAAAAATh8KTv3CyEx3MynasfTqpaskTiKiWouEJQf46K4iBT75EHT73g2UMvzVq07sZfnm5Qq56jS3Ec228TIjoPtZ0zAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAd21pbGwAAAAMAAAACwAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAPAEAAAoAAIBGAQAADAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAkwIAABMAAIBjbGkuanMAAAIAAAAoAwAACQAAgGNsaS5qcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAbWltZQAAAABjbGkuanMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAZXNidWlsZABGGgAACwAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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bmFsU3RyaW5nPiAxNiBzaXplb2YsIDggYWxpZ25vZgp4lwAAAAAAANa7AAAAAAAACjx1OD4gMSBzaXplb2YsIDEgYWxpZ25vZgoAAHdpbmRtaWxsLWNsaWVzbS9tYWluLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2luZG1pbGwtY2xpLy0vd2luZG1pbGwtY2xpLTEuMzkzLjIudGd6QGF5b25saS9qc2V4dGdpdGlnbm9yZS1wYXJzZXJtaW5pbWF0Y2h3aW5kbWlsbC1jbGllbnRAZGVuby9zaGltLWRlbm9odHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZGVuby9zaGltLWRlbm8vLS9zaGltLWRlbm8tMC4xOC4yLnRnekBkZW5vL3NoaW0tZGVuby10ZXN0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGRlbm8vc2hpbS1kZW5vLXRlc3QvLS9zaGltLWRlbm8tdGVzdC0wLjUuMC50Z3pub2RlLXdoaWNoYmluL3doaWNoLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hpY2gvLS93aGljaC00LjAuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pc2V4ZS8tL2lzZXhlLTMuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dzLy0vd3MtOC4xOC4wLnRnemJ1ZmZlcnV0aWx1dGYtOC12YWxpZGF0ZWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dpbmRtaWxsLWNsaWVudC8tL3dpbmRtaWxsLWNsaWVudC0xLjM2NC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL29wZW4vLS9vcGVuLTEwLjEuMC50Z3pkZWZhdWx0LWJyb3dzZXJkZWZpbmUtbGF6eS1wcm9waXMtaW5zaWRlLWNvbnRhaW5lcmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzLXdzbC8tL2lzLXdzbC0zLjEuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1pbnNpZGUtY29udGFpbmVyLy0vaXMtaW5zaWRlLWNvbnRhaW5lci0xLjAuMC50Z3ppcy1kb2NrZXJodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1kb2NrZXIvLS9pcy1kb2NrZXItMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmaW5lLWxhenktcHJvcC8tL2RlZmluZS1sYXp5LXByb3AtMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLy0vZGVmYXVsdC1icm93c2VyLTUuMi4xLnRnemJ1bmRsZS1uYW1lZGVmYXVsdC1icm93c2VyLWlkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLWlkLy0vZGVmYXVsdC1icm93c2VyLWlkLTUuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2J1bmRsZS1uYW1lLy0vYnVuZGxlLW5hbWUtNC4xLjAudGd6cnVuLWFwcGxlc2NyaXB0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcnVuLWFwcGxlc2NyaXB0Ly0vcnVuLWFwcGxlc2NyaXB0LTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21pbmltYXRjaC8tL21pbmltYXRjaC0xMC4wLjEudGd6YnJhY2UtZXhwYW5zaW9uaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnJhY2UtZXhwYW5zaW9uLy0vYnJhY2UtZXhwYW5zaW9uLTIuMC4xLnRnemJhbGFuY2VkLW1hdGNoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYmFsYW5jZWQtbWF0Y2gvLS9iYWxhbmNlZC1tYXRjaC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9qc3ppcC8tL2pzemlwLTMuNy4xLnRnenJlYWRhYmxlLXN0cmVhbXNldC1pbW1lZGlhdGUtc2hpbWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NldC1pbW1lZGlhdGUtc2hpbS8tL3NldC1pbW1lZGlhdGUtc2hpbS0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yZWFkYWJsZS1zdHJlYW0vLS9yZWFkYWJsZS1zdHJlYW0tMi4zLjgudGd6Y29yZS11dGlsLWlzcHJvY2Vzcy1uZXh0aWNrLWFyZ3NzYWZlLWJ1ZmZlcnN0cmluZ19kZWNvZGVydXRpbC1kZXByZWNhdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlsLWRlcHJlY2F0ZS8tL3V0aWwtZGVwcmVjYXRlLTEuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0cmluZ19kZWNvZGVyLy0vc3RyaW5nX2RlY29kZXItMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZS1idWZmZXIvLS9zYWZlLWJ1ZmZlci01LjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wcm9jZXNzLW5leHRpY2stYXJncy8tL3Byb2Nlc3MtbmV4dGljay1hcmdzLTIuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzYXJyYXkvLS9pc2FycmF5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2luaGVyaXRzLy0vaW5oZXJpdHMtMi4wLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29yZS11dGlsLWlzLy0vY29yZS11dGlsLWlzLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Bha28vLS9wYWtvLTEuMC4xMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9saWUvLS9saWUtMy4zLjAudGd6aW1tZWRpYXRlaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaW1tZWRpYXRlLy0vaW1tZWRpYXRlLTMuMC42LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dpdGlnbm9yZS1wYXJzZXIvLS9naXRpZ25vcmUtcGFyc2VyLTAuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2V4cHJlc3MvLS9leHByZXNzLTQuMTkuMi50Z3plbmNvZGV1cmxwcm94eS1hZGRyYm9keS1wYXJzZXJlc2NhcGUtaHRtbGh0dHAtZXJyb3Jzb24tZmluaXNoZWR1dGlscy1tZXJnZWNvbnRlbnQtdHlwZWZpbmFsaGFuZGxlcnJhbmdlLXBhcnNlcnNlcnZlLXN0YXRpY2FycmF5LWZsYXR0ZW5wYXRoLXRvLXJlZ2V4cHNldHByb3RvdHlwZW9mY29va2llLXNpZ25hdHVyZW1lcmdlLWRlc2NyaXB0b3JzY29udGVudC1kaXNwb3NpdGlvbmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtZGlzcG9zaXRpb24vLS9jb250ZW50LWRpc3Bvc2l0aW9uLTAuNS40LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NhZmUtYnVmZmVyLy0vc2FmZS1idWZmZXItNS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVyZ2UtZGVzY3JpcHRvcnMvLS9tZXJnZS1kZXNjcmlwdG9ycy0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9jb29raWUtc2lnbmF0dXJlLy0vY29va2llLXNpZ25hdHVyZS0xLjAuNi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zZXRwcm90b3R5cGVvZi8tL3NldHByb3RvdHlwZW9mLTEuMi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3BhdGgtdG8tcmVnZXhwLy0vcGF0aC10by1yZWdleHAtMC4xLjcudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYXJyYXktZmxhdHRlbi8tL2FycmF5LWZsYXR0ZW4tMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2VydmUtc3RhdGljLy0vc2VydmUtc3RhdGljLTEuMTUuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lc2NhcGUtaHRtbC8tL2VzY2FwZS1odG1sLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VuY29kZXVybC8tL2VuY29kZXVybC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wYXJzZXVybC8tL3BhcnNldXJsLTEuMy4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NlbmQvLS9zZW5kLTAuMTguMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yYW5nZS1wYXJzZXIvLS9yYW5nZS1wYXJzZXItMS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvb24tZmluaXNoZWQvLS9vbi1maW5pc2hlZC0yLjQuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lZS1maXJzdC8tL2VlLWZpcnN0LTEuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2h0dHAtZXJyb3JzLy0vaHR0cC1lcnJvcnMtMi4wLjAudGd6dG9pZGVudGlmaWVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdG9pZGVudGlmaWVyLy0vdG9pZGVudGlmaWVyLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0YXR1c2VzLy0vc3RhdHVzZXMtMi4wLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVwZC8tL2RlcGQtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVzdHJveS8tL2Rlc3Ryb3ktMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnJlc2gvLS9mcmVzaC0wLjUuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9kZWJ1Zy8tL2RlYnVnLTIuNi45LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21zLy0vbXMtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS8tL21pbWUtMS42LjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXRhZy8tL2V0YWctMS44LjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbXMvLS9tcy0yLjEuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9maW5hbGhhbmRsZXIvLS9maW5hbGhhbmRsZXItMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdW5waXBlLy0vdW5waXBlLTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtdHlwZS8tL2NvbnRlbnQtdHlwZS0xLjAuNS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlscy1tZXJnZS8tL3V0aWxzLW1lcmdlLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2JvZHktcGFyc2VyLy0vYm9keS1wYXJzZXItMS4yMC4yLnRnemljb252LWxpdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pY29udi1saXRlLy0vaWNvbnYtbGl0ZS0wLjQuMjQudGd6Pj0gMi4xLjIgPCAzc2FmZXItYnVmZmVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZXItYnVmZmVyLy0vc2FmZXItYnVmZmVyLTIuMS4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Jhdy1ib2R5Ly0vcmF3LWJvZHktMi41LjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnl0ZXMvLS9ieXRlcy0zLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy90eXBlLWlzLy0vdHlwZS1pcy0xLjYuMTgudGd6bWltZS10eXBlc21lZGlhLXR5cGVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVkaWEtdHlwZXIvLS9tZWRpYS10eXBlci0wLjMuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9taW1lLXR5cGVzLy0vbWltZS10eXBlcy0yLjEuMzUudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS1kYi8tL21pbWUtZGItMS41Mi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3FzLy0vcXMtNi4xMS4wLnRnenNpZGUtY2hhbm5lbGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NpZGUtY2hhbm5lbC8tL3NpZGUtY2hhbm5lbC0xLjAuNi50Z3pjYWxsLWJpbmRlcy1lcnJvcnNnZXQtaW50cmluc2ljb2JqZWN0LWluc3BlY3RodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9vYmplY3QtaW5zcGVjdC8tL29iamVjdC1pbnNwZWN0LTEuMTMuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9nZXQtaW50cmluc2ljLy0vZ2V0LWludHJpbnNpYy0xLjIuNC50Z3pmdW5jdGlvbi1iaW5kaGFzLXByb3RvaGFzLXN5bWJvbHNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXNvd24vLS9oYXNvd24tMi4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnVuY3Rpb24tYmluZC8tL2Z1bmN0aW9uLWJpbmQtMS4xLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaGFzLXN5bWJvbHMvLS9oYXMtc3ltYm9scy0xLjAuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvdG8vLS9oYXMtcHJvdG8tMS4wLjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZXJyb3JzLy0vZXMtZXJyb3JzLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NhbGwtYmluZC8tL2NhbGwtYmluZC0xLjAuNy50Z3plcy1kZWZpbmUtcHJvcGVydHlzZXQtZnVuY3Rpb24tbGVuZ3RoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2V0LWZ1bmN0aW9uLWxlbmd0aC8tL3NldC1mdW5jdGlvbi1sZW5ndGgtMS4yLjIudGd6ZGVmaW5lLWRhdGEtcHJvcGVydHloYXMtcHJvcGVydHktZGVzY3JpcHRvcnNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMvLS9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMtMS4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZGVmaW5lLXByb3BlcnR5Ly0vZXMtZGVmaW5lLXByb3BlcnR5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dvcGQvLS9nb3BkLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RlZmluZS1kYXRhLXByb3BlcnR5Ly0vZGVmaW5lLWRhdGEtcHJvcGVydHktMS4xLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcHJveHktYWRkci8tL3Byb3h5LWFkZHItMi4wLjcudGd6Zm9yd2FyZGVkaXBhZGRyLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaXBhZGRyLmpzLy0vaXBhZGRyLmpzLTEuOS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ZvcndhcmRlZC8tL2ZvcndhcmRlZC0wLjIuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9tZXRob2RzLy0vbWV0aG9kcy0xLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9hY2NlcHRzLy0vYWNjZXB0cy0xLjMuOC50Z3puZWdvdGlhdG9yaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbmVnb3RpYXRvci8tL25lZ290aWF0b3ItMC42LjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29va2llLy0vY29va2llLTAuNi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3ZhcnkvLS92YXJ5LTEuMS4yLnRnemJpbi9lc2J1aWxkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXNidWlsZC8tL2VzYnVpbGQtMC4yMy4xLnRnekBlc2J1aWxkL2FpeC1wcGM2NEBlc2J1aWxkL2FuZHJvaWQtYXJtQGVzYnVpbGQvYW5kcm9pZC1hcm02NEBlc2J1aWxkL2FuZHJvaWQteDY0QGVzYnVpbGQvZGFyd2luLWFybTY0QGVzYnVpbGQvZGFyd2luLXg2NEBlc2J1aWxkL2ZyZWVic2QtYXJtNjRAZXNidWlsZC9mcmVlYnNkLXg2NEBlc2J1aWxkL2xpbnV4LWFybUBlc2J1aWxkL2xpbnV4LWFybTY0QGVzYnVpbGQvbGludXgtaWEzMkBlc2J1aWxkL2xpbnV4LWxvb25nNjRAZXNidWlsZC9saW51eC1taXBzNjRlbEBlc2J1aWxkL2xpbnV4LXBwYzY0QGVzYnVpbGQvbGludXgtcmlzY3Y2NEBlc2J1aWxkL2xpbnV4LXMzOTB4QGVzYnVpbGQvbGludXgteDY0QGVzYnVpbGQvbmV0YnNkLXg2NEBlc2J1aWxkL29wZW5ic2QtYXJtNjRAZXNidWlsZC9vcGVuYnNkLXg2NEBlc2J1aWxkL3N1bm9zLXg2NEBlc2J1aWxkL3dpbjMyLWFybTY0QGVzYnVpbGQvd2luMzItaWEzMkBlc2J1aWxkL3dpbjMyLXg2NGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLXg2NC8tL3dpbjMyLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvd2luMzItaWEzMi8tL3dpbjMyLWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLWFybTY0Ly0vd2luMzItYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3N1bm9zLXg2NC8tL3N1bm9zLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC14NjQvLS9vcGVuYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC1hcm02NC8tL29wZW5ic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL25ldGJzZC14NjQvLS9uZXRic2QteDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC14NjQvLS9saW51eC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXMzOTB4Ly0vbGludXgtczM5MHgtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXJpc2N2NjQvLS9saW51eC1yaXNjdjY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1wcGM2NC8tL2xpbnV4LXBwYzY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1taXBzNjRlbC8tL2xpbnV4LW1pcHM2NGVsLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1sb29uZzY0Ly0vbGludXgtbG9vbmc2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvbGludXgtaWEzMi8tL2xpbnV4LWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybTY0Ly0vbGludXgtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybS8tL2xpbnV4LWFybS0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC14NjQvLS9mcmVlYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC1hcm02NC8tL2ZyZWVic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2Rhcndpbi14NjQvLS9kYXJ3aW4teDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9kYXJ3aW4tYXJtNjQvLS9kYXJ3aW4tYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQteDY0Ly0vYW5kcm9pZC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQtYXJtNjQvLS9hbmRyb2lkLWFybTY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9hbmRyb2lkLWFybS8tL2FuZHJvaWQtYXJtLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9haXgtcHBjNjQvLS9haXgtcHBjNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VzLW1haW4vLS9lcy1tYWluLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RpZmYvLS9kaWZmLTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0BheW9ubGkvanNleHQvLS9qc2V4dC0wLjkuNjMudGd6c3Vkby1wcm9tcHRodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zdWRvLXByb21wdC8tL3N1ZG8tcHJvbXB0LTkuMi4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ljb252LWxpdGUvLS9pY29udi1saXRlLTAuNi4zLnRnej49IDIuMS4yIDwgMy4wLjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==' +WHERE hash = -28028598712388162 AND workspace_id = 'admins'; \ No newline at end of file diff --git a/backend/migrations/20240908214334_migrate_to_new_cli_2.down.sql b/backend/migrations/20240908214334_migrate_to_new_cli_2.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240908214334_migrate_to_new_cli_2.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240908214334_migrate_to_new_cli_2.up.sql b/backend/migrations/20240908214334_migrate_to_new_cli_2.up.sql new file mode 100644 index 0000000000..445ecee8f5 --- /dev/null +++ b/backend/migrations/20240908214334_migrate_to_new_cli_2.up.sql @@ -0,0 +1,17 @@ +-- Add up migration script here + +-- Add up migration script here +UPDATE script SET content = 'import * as wmill from "windmill-cli@1.393.2" + +export async function main() { + await wmill.hubPull({ workspace: "admins", token: process.env["WM_TOKEN"], baseUrl: process.env["BASE_URL"] }); +} +', language = 'bun', +lock = '{ + "dependencies": { + "windmill-cli": "latest" + } +} +//bun.lockb +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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACmAgAANAAAgAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA2gIAAE4AAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADEDAAA6AACAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABrAwAASAAAgAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAswMAAEYAAIAFAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABYEAABMAACABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABiBAAAPgAAgAQAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAArwQAAEYAAIAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPUEAAA7AACACgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA/BQAARgAAgAIAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAkwUAAEQAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANcFAAAyAACAAwAAAAcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAqBgAATAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdgYAAEYAAIACAAAAAwAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMHAABEAACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABHBwAARAAAgAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAiwcAAD4AAIAFAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkHAABQAACAAgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAZCAAANgAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAATwgAADgAAIACAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAIcIAABAAACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADHCAAAMQAAgAEAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA+AgAAC4AAIADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAC8JAAA6AACAAwAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABpCQAASAAAgAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAsQkAADcAAIAEAAAAEwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8KAABOAACAAAAAAAUAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAANCwAAPgAAgAUAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAASwsAAEoAAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJULAABIAACAAQAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADdCwAARAAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAIQwAAEQAAIAAAAAAAQAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGUMAABCAACAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACnDAAAQQAAgAEAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA6AwAAD4AAIABAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACYNAAA6AACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABgDQAAOAAAgAEAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAmA0AADEAAIAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkNAABAAACAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAJDgAAPgAAgAIAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAARw4AADgAAIABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAH8OAAA+AACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADJDgAAQAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACQ8AADgAAIACAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEEPAAAwAACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABxDwAANgAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAApw8AADIAAIAAAAAABQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANkPAAAyAACAAgAAAAYAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAALEAAALAAAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxAAADAAAIABAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGcQAAAwAACAAQAAAAgAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACXEAAALAAAgAIAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAwxAAAEAAAIABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMRAAA0AACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA3EQAAQAAAgAEAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdxEAAD4AAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAALURAAA/AACAAQAAABQAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD+EQAAPQAAgAAAAAAEAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAUxIAAEAAAIACAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJMSAAA4AACAAgAAAAUAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADLEgAAMgAAgAMAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA/RIAADcAAIABAAAABgAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEkTAAA+AACAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACHEwAAPQAAgAIAAAABAAAAIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxBMAADcAAIABAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPsTAAAtAACABgAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA0FAAAQAAAgAEAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAoRQAAEUAAIABAAAADQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOYUAABCAACAAQAAAAIAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABJFQAANAAAgAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAfRUAAEIAAIABAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8VAAA+AACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD9FQAAOgAAgAEAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxYAADoAAIABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHEWAAA6AACAAQAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADQFgAATgAAgAEAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAShcAAFgAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKIXAABMAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADuFwAAMAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAHhgAAFAAAIABAAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAG4YAAA8AACAAgAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC8GAAAOgAAgAEAAAAJAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA9hgAADoAAIAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADAZAAA2AACAAQAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABmGQAANgAAgAEAAAADAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAphkAADwAAIAAAAAABgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOIZAAA0AACAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAWGgAAMAAAgAEAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAURoAADcAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGgcAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACsHAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA8hwAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADodAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAB+HQAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxh0AAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABIeAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABYHgAARAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAnB4AAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOQeAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAwHwAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAeB8AAE4AAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMYfAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAASIAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAWCAAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKAgAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADkIAAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAALCEAAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHghAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC+IQAASgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACCIAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAFAiAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACcIgAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA5CIAAEQAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACgjAAA2AACAAQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABeIwAAMAAAgAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAjiMAADsAAIAAAAAACQAAAD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANQjAAA+AACACQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAASJAAAPAAAgAAAAAAGAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAwAAAANAAAAAgAAAA8AAAAAAAAADwAAAAEAAAAQAAAAAAAAABAAAAACAAAAEgAAAAAAAAASAAAABAAAABYAAAABAAAAFwAAAAEAAAAYAAAAAAAAABgAAAAAAAAAGAAAAAIAAAAaAAAAAAAAABoAAAABAAAAGwAAAAAAAAAbAAAAAQAAABwAAAABAAAAHQAAAAAAAAAdAAAABAAAACEAAAAAAAAAIQAAAAcAAAAoAAAAAAAAACgAAAABAAAAKQAAAAAAAAApAAAAAAAAACkAAAAAAAAAKQAAAAAAAAApAAAAAAAAACkAAAAAAAAAKQAAAAEAAAAqAAAAAAAAACoAAAAAAAAAKgAAAB8AAABJAAAAAQAAAEoAAAAAAAAASgAAAAAAAABKAAAAAAAAAEoAAAAAAAAASgAAAAAAAABKAAAAAAAAAEoAAAAEAAAATgAAAAAAAABOAAAAAAAAAE4AAAAAAAAATgAAAA0AAABbAAAAAAAAAFsAAAABAAAAXAAAAAAAAABcAAAABQAAAGEAAAAAAAAAYQAAAAAAAABhAAAAAAAAAGEAAAAAAAAAYQAAAAAAAABhAAAAAQAAAGIAAAAAAAAAYgAAAAAAAABiAAAAAAAAAGIAAAAAAAAAYgAAAAcAAABpAAAAAAAAAGkAAAAAAAAAaQAAAAAAAABpAAAADAAAAHUAAAABAAAAdgAAAAAAAAB2AAAABAAAAHoAAAAAAAAAegAAAAIAAAB8AAAAAAAAAHwAAAABAAAAfQAAAAAAAAB9AAAAAQAAAH4AAAAEAAAAggAAAAAAAACCAAAABQAAAIcAAAABAAAAiAAAAAAAAACIAAAAAAAAAIgAAAAAAAAAiAAAAAAAAACIAAAABQAAAI0AAAAGAAAAkwAAAAEAAACUAAAAAQAAAJUAAAABAAAAlgAAAAMAAACZAAAAAgAAAJsAAAAAAAAAmwAAAAAAAACbAAAAAAAAAJsAAAACAAAAnQAAAAAAAACdAAAAAAAAAJ0AAAAAAAAAnQAAABgAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAMAAAC4AAAAAAAAALgAAAABAAAAAAAAAAEAAAABAAAADAAAAA0AAAACAAAADwAAAAAAAAAPAAAAAQAAABAAAAAAAAAAEAAAAAIAAAASAAAAAAAAABIAAAAEAAAAFgAAAAEAAAAXAAAAAQAAABgAAAAAAAAAGAAAAAAAAAAYAAAAAgAAABoAAAAAAAAAGgAAAAEAAAAbAAAAAAAAABsAAAABAAAAHAAAAAEAAAAdAAAAAAAAAB0AAAAEAAAAIQAAAAAAAAAhAAAABwAAACgAAAAAAAAAKAAAAAEAAAApAAAAAAAAACkAAAAAAAAAKQAAAAAAAAApAAAAAAAAACkAAAAAAAAAKQAAAAAAAAApAAAAAQAAACoAAAAAAAAAKgAAAAAAAAAqAAAAHwAAAEkAAAABAAAASgAAAAAAAABKAAAAAAAAAEoAAAAAAAAASgAAAAAAAABKAAAAAAAAAEoAAAAAAAAASgAAAAQAAABOAAAAAAAAAE4AAAAAAAAATgAAAAAAAABOAAAADQAAAFsAAAAAAAAAWwAAAAEAAABcAAAAAAAAAFwAAAAFAAAAYQAAAAAAAABhAAAAAAAAAGEAAAAAAAAAYQAAAAAAAABhAAAAAAAAAGEAAAABAAAAYgAAAAAAAABiAAAAAAAAAGIAAAAAAAAAYgAAAAAAAABiAAAABwAAAGkAAAAAAAAAaQAAAAAAAABpAAAAAAAAAGkAAAAMAAAAdQAAAAEAAAB2AAAAAAAAAHYAAAAEAAAAegAAAAAAAAB6AAAAAgAAAHwAAAAAAAAAfAAAAAEAAAB9AAAAAAAAAH0AAAABAAAAfgAAAAQAAACCAAAAAAAAAIIAAAAFAAAAhwAAAAEAAACIAAAAAAAAAIgAAAAAAAAAiAAAAAAAAACIAAAAAAAAAIgAAAAFAAAAjQAAAAYAAACTAAAAAQAAAJQAAAABAAAAlQAAAAEAAACWAAAAAwAAAJkAAAACAAAAmwAAAAAAAACbAAAAAAAAAJsAAAAAAAAAmwAAAAIAAACdAAAAAAAAAJ0AAAAAAAAAnQAAAAAAAACdAAAAGAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAAAAALUAAAAAAAAAtQAAAAAAAAC1AAAAAwAAALgAAAAAAAAAuAAAAAEAAAAAAP4P/gEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAQD+D/4BAAABAAAAAAAAAAAAAAAEnFcorsSkCz8vYXAoZrKLi9czdIvLIYptbISOLuy4R+UtJGOUkjeYcwquPiSjBCSKdzYL5hFPVeFeiuj7326sDgEAAAEA/g/+AQAAAgAAAAAAAAAAAAAABKENAlZjoqOt8JYcEBe+cwOIqKJT7zsAKCtMrs3EuWwwtSVLx98tRkvMT4fBDqXKA0EVOBUxvDkH8YaUfnOg68wBAAABAP4P/gEAAAMAAAAAAAAAAAAAAATicyF5ykaU+LRxLNPrsv5Ob4Y4mq+6TyCocHOKpxRA5que4hrHXP3r+AkcJIjPZnTOHETpHPBvchlc+0WHnWP7AQAAAQD+D/4BAAAEAAAAAAAAAAAAAAAEGlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscgEAAAEA/g/+AQAABQAAAAAAAAAAAAAABC6Qf+eAfv9ieYakO4pmR33VN9TpYEKse2YnFZZJvZM4Pf8PBiixHBXyZf7ewwhA7njsgQA+swgsEzuhc7NDaBEBAAABAP4P/gEAAAYAAAAAAAAAAAAAAATxVt9Z8cttvC7f43o4qw4ykF1PiRc8MMH1wmTZsnqaH25zF2Wc28fV76uhiQqY303HDbKPPtXN472g7PbMnTg/AQAAAQD+D/4BAAAHAAAAAAAAAAAAAAAEUjCbBB2IeyMVoDyO16boHEsTus2npVtXyER2pfP0zm7rmp6ko65HA3OXvMzhMVq3hW9RQ5esc3mrkTnb19PIawEAAAEA/g/+AQAACAAAAAAAAAAAAAAABJp5HkNaj+VHtsHfmor0w9zR3f5Wfei7tI4H9KcJLSz7cenE2Yh+7cnhkUR7NM19K262oVz515VJ23l8mgQbiGsBAAABAP4P/gEAAAkAAAAAAAAAAAAAAARRxV9V9orhJzibtfd1RKgeijNAYEQV4ML7NWjTq33zF7wLMdJlkF6Q1cf627Q1qUeiVwn9AAapLjod5/tBcEgzAQAAAQD+D/4BAAAKAAAAAAAAAAAAAAAEKIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRAEAAAEA/g/+AQAACwAAAAAAAAAAAAAABHpY3IBA5RJ7P+wFxaLAeSv9pwjOD+xUD5BnPw1i8ua5hRFr2Wshq4pNXff0CGOZyeH/WLFbwZAOpCaR5/ayEnUBAAABAP4P/gEAAAwAAAAAAAAAAAAAAAQ34x5diiqvek6CfzF/JE9EQ3uAdqQtiOGweFYZPd9YCIvgiQC3SIPDXhCKISbZsTfRzldfmrQW0ADcIrl/38FSAQAAAQD+D/4BAAANAAAAAAAAAAAAAAAEWY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8XgEAAAEA/g/+AQAADgAAAAAAAAAAAAAABAOqf6bv+n8gXANU0c/xqlmD1YqZa37XFtoGQvau/Z4DQigHkf194HBHV0B5eCjV1ft8ICCdQj5CUNyBzOpXLMgBAAABAP4P/gEAAA8AAAAAAAAAAAAAAAS2PAzl7EyDoEZEj6Q2ZOe02y91lLVfwEVhLq2cnaF0fSRXEzr95VnbHL4WpK1Ja9ia18UwMsjG6uisfAMp8PPlAQAAAQD+D/4BAAAQAAAAAAAAAAAAAAAE9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1AEAAAEA/g/+AQAAEQAAAAAAAAAAAAAABHrYV07d0hhkfveYLnZqidXjYUTu3hhBiIGAPb5z2rSuP3rc9jBFQ56ORjAom3TE7gTMhJcyJYMTJ2tyveFwyA0BAAABAP4P/gEAABIAAAAAAAAAAAAAAARecAi9Dx4z6QLppQvHrC5CLBWyfOyL13dbHNXcWlZMYDX0XrbWTB1uwBwUpeApQdlazL6ZjqIvWwdPFYQULK0MAQAAAQD+D/4BAAATAAAAAAAAAAAAAAAE3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5PwEAAAEA/g/+AQAAFAAAAAAAAAAAAAAABIIS9Lc9VxvWRJkTHBDdr7e8Wm6w3ahx3spIAEaZmdAYiHLVsTOO1bet2TtnZ6eEGLf8SVSy8uWb9Zf8UXYdm8oBAAABAP4P/gEAABUAAAAAAAAAAAAAAAQuLkA6qtlYJUDafmSvLMSapqLpspIi+nPmhQkc9WPr52xsPdfWLG2xjm0Sexo2kfekUAeYbx4gdSu0S2iGuD5RAQAAAQD+D/4BAAAWAAAAAAAAAAAAAAAE8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdAEAAAEA/g/+AQAAFwAAAAAAAAAAAAAABBDw+atbl8hcSaQqy5wnNZx56t4Dmug2QaHACIiNk2kggO1QidVCQzGoAsyJFzbFGHw9XWiv/y0xEPMYiG6x7XMBAAABAP4P/gEAABgAAAAAAAAAAAAAAASf9KGe8OLoUdttV++Kuj5aiOIXO/6zww8wcFzNV499SkMkvCgtPSG3WXhjAEJuLykkC94QR2eQfI/JM/+bNF/CAQAAAQD+D/4BAAAZAAAAAAAAAAAAAAAEGd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+gEAAAEA/g/+AQAAGgAAAAAAAAAAAAAABN6LlDqUIbYK2zmteye/rsTk6SE2Fmhj+/wIaEd/gPv9XvbJK83pRov3V8xGMr28bmxBelp9sqbHEyoiiRRZ9WoBAAABAP4P/gEAABsAAAAAAAAAAAAAAARUuCEhY0zoQtDOjvPCZyDQ2ZNXJYpiO8h4zzfKOnTBENOZSeszrvx9BtwoGjqfYIkQXSzOgb//K2D5MqVrz0AtAQAAAQD+D/4BAAAcAAAAAAAAAAAAAAAEk/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQEAAAEA/g/+AQAAHQAAAAAAAAAAAAAABGUAb4tQ3KSeBg6mp47nGdh498BDuaWQ0vPQVm5HK73cZLCaK8FAw2Wpl/ZXRZKfWsNpZgQy4JDmxAOA1jSfRWEBAAABAP4P/gEAAB4AAAAAAAAAAAAAAATiEsHw/LjNlx7mzjJ31fOimrBW//IY2FXUGXw1OYKrXvrcd4rb4TBVO/6V4Z4vXcOeHbB9uqjBU9cIg7TPi1pjAQAAAQD+D/4BAAAfAAAAAAAAAAAAAAAEUaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQEAAAEA/g/+AQAAIAAAAAAAAAAAAAAABF1zhbcqg4zQwEMVX2Mbhe4PSJfyG1pppUINjGCjh/BMSE9aoOsXOM8ktx2hBAE4LNW7X88ateXIlImO4I0l0RkBAAABAP4P/gEAACEAAAAAAAAAAAAAAARfqampS/n25YsYPifeFnwK7wpsXY8xY9IVibFmN2SmbfI5TuFJRifNORkjWZxapyGmG+rK7Pf8GGAFHgT8m2QKAQAAAQD+D/4BAAAiAAAAAAAAAAAAAAAE5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9QEAAAEA/g/+AQAAIwAAAAAAAAAAAAAABBb3mUzbhsNOHMZQIlm84us0wC/5YXoWlm07YJbiYePxPeQ6jME5oWtymTdWgFgPHBSIR8zGVLy3r5MOUapPrUkBAAABAP4P/gEAACQAAAAAAAAAAAAAAASundKjTspx2aYpsa+Bo3FBImvtsZVJWTlL0SrUX6mltGjvT5h5oPGTDkN3w0834YPpuOdibZW4+4Jeam5i+YJdAQAAAQD+D/4BAAAlAAAAAAAAAAAAAAAEcCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1wEAAAEA/g/+AQAAJgAAAAAAAAAAAAAABEAA85Wh3PInFfCO722iVycKHfR1mKfLgqn9cWuDnzbtU+yVcUCK1IDlrR3TQ7T4ssJhW4ktdlY6LSFy6yjN6K0BAAABAP4P/gEAACcAAAAAAAAAAAAAAAQTksNftaunzkqKXluFm/jqPyM55ugqrkkyZgzeBUZ0YfzEWk9ZdQyw2uU4MKuSjEwR42L9dkjC5G9jhc3BgwmnAQAAAQD+D/4BAAAoAAAAAAAAAAAAAAAE5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQEAAAEA/g/+AQAAKQAAAAAAAAAAAAAABDwlQELMFnprulHcbAxRV//oFXmKigKHdw91FZvdYx8Mp4LjsAL2D4cfJzZTPvjakXCugscaVGn45oSHSoh4m6oBAAABAP4P/gEAACoAAAAAAAAAAAAAAARca5EM2NdSKOxQvS+XqdIPtzBRG7MSCCVs5oW5kz2DeTANc5ZVNyTSMvOM/MYP5NrNZtuhli7nb/39c91SCd72AQAAAQD+D/4BAAArAAAAAAAAAAAAAAAENiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9owEAAAEA/g/+AQAALAAAAAAAAAAAAAAABEzyV6vCahWlWJtglpj75z9iMqOGUjO/0CnEprjCwzm36R+X4u0VBpnf60w3/q7rf7Gog4kBHlUzYAJiRHQDsdMBAAABAP4P/gEAAC0AAAAAAAAAAAAAAAQKLJ47EVP8lnI3mbTP099fDhIIEnpLKDPUOmXTCqOWEMQYYE/UaexRUQvSnreGgbV9yPd8fKdeL01g7idY4v6pAQAAAQD+D/4BAAAuAAAAAAAAAAAAAAAEqqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXgEAAAEA/g/+AQAALwAAAAAAAAAAAAAABB64LMfqK6qMoJ5oRWymhxOnNveifh0wEF6MRBeoDbqUTpphiUaMs3xt3HAL3qgga8K/9ssUOQVXfxk5eWoDsEoBAAABAP4P/gEAADAAAAAAAAAAAAAAAAShWXOSDcQ0CEKTbN2/sgnB39BQPjPZHFHCmRwZjymwJVwJhk2rjBidVYAscz5uu24mN49aJgX8KWa4OvwKHn6SAQAAAQD+D/4BAAAxAAAAAAAAAAAAAAAEWMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlowEAAAEA/g/+AQAAMgAAAAAAAAAAAAAABBbcKxv3rgc2hI2HkajoJcuxtKr4ol6CVp7xB9mdaZQXV4G8o79+KR00m/c6HhzMg8t9/g1suVrfVqPk1EbTmEkBAAABAP4P/gEAADMAAAAAAAAAAAAAAASjmxI8oSSD8MhA2YfjdXT+56suunNV52RSHy0Y29p5el+m7CMp6eVKjH/Y78FOVlS0R74kbuzliETPrTw+UAdEAQAAAQD+D/4BAAA0AAAAAAAAAAAAAAAERwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQEAAAEA/g/+AQAANQAAAAAAAAAAAAAABIO5x+j+ncg4qCaIAABqaxqQrVSJiYaT5P66As3W93yIetf7P5z7H0eqJ8jMJAgEfzpQt8gQtJREr1KEBALLCK8BAAABAP4P/gEAADYAAAAAAAAAAAAAAATawkYlNpcghpHXDiIlI2g3SGcxjsalz+fwPipIInDxCoVZd/ty4CCcQfEGnB5pVw968LaXcqmNgLHc3KlBCBomAQAAAQD+D/4BAAA3AAAAAAAAAAAAAAAEzJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8QEAAAEA/g/+AQAAOAAAAAAAAAAAAAAABGwuxJa3SWiZz2wD/tRKLWL6mbG93nJecIugX4ugSU1HDaMKenL7KYNI1850Uyg45vxOwHYBQVXgD1TDXChrBzABAAABAP4P/gEAADkAAAAAAAAAAAAAAAROmnrQ/ohQkNO46r/lnxx2yTMm6N/Cp85OSvAjCPshEhKmeQmdPpLIng8I+cYygWML112FqXkpUhi0C33uLHTkAQAAAQD+D/4BAAA6AAAAAAAAAAAAAAAEx0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQegEAAAEA/g/+AQAAOwAAAAAAAAAAAAAABGiC+Rce5msFWt9NGpdgZxBOIjb6NahE8S6zyP6NOS+8+oKO3wsNSehEJmyuBZidgEu5IFRfyhGVrnwX3QpTHD4BAAABAP4P/gEAADwAAAAAAAAAAAAAAAToWXO5tMtkbcnZr81UICV4SGPOrmjGAfJoJT3Jhe9wuy+hVocmr+znFcjr9dc/q3PtH3EA60edI7+1e0XdZFOUAQAAAQD+D/4BAAA9AAAAAAAAAAAAAAAE5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISgEAAAEA/g/+AQAAPgAAAAAAAAAAAAAABKY8tm2IUrLn8FpSsD3Ppd3De/sLiZSurs9GHSRDpUA25eo6P2JT4uJm/GoFJFQvARe1fDbs3sjzakZLAN4c7SkBAAABAP4P/gEAAD8AAAAAAAAAAAAAAASdOOp9wEUSKkp1cK/hgNBYJ+ZwtkqbzWV0XSkCilO/KsUZVtxHo/9UAB3kbs37S1OvxCqJTS0Vp0PoUrg20nA4AQAAAQD+D/4BAABAAAAAAAAAAAAAAAAEpMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hAEAAAEA/g/+AQAAQQAAAAAAAAAAAAAABJpfaUXgrtzOtZBpaqE5trpkl05UU7hk8dG32I/riFCimMnBuTbUm3nrVd32klOke2ozj8NIPydT7yuKjcu7OWwBAAABAP4P/gEAAEIAAAAAAAAAAAAAAAS/cxedkBy+fLCRNQRmiYgBy2V7tFdd5505HfXDCXtWXKhc7hCL1qu9J6c1Bad7VNxHCEIvUfAsjbVsSp2mPz+sAQAAAQD+D/4BAABDAAAAAAAAAAAAAAAEYZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtgEAAAEA/g/+AQAARAAAAAAAAAAAAAAABPMxqsqXxDYwiKhoYF06AvGgdq+2KwV/gEAHyD7PzJZPgbT087Tr00tNTUVv9xIetCfmuPJbfKrAs4q0OpaAlXwBAAABAP4P/gEAAEUAAAAAAAAAAAAAAAT81/tPLNPHpLfJEk5s4BXv3nqvxyvb46PwALl23zBI/cFACh5fnw2gfIJTw/zMaQ1dK2NNKLp/M7oXSkF1xhsSAQAAAQD+D/4BAABGAAAAAAAAAAAAAAAETkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8gEAAAEA/g/+AQAARwAAAAAAAAAAAAAABHavqnpUPWpB6XDpf4FFUU8VSDpACdcEd0AL2+EbFY0vKFaBYwxk3Ou/cCWJlJpJ1BeR8DCzoG+TvmtysX1mqT0BAAABAP4P/gEAAEgAAAAAAAAAAAAAAARkNj5s+bnNNMX5ikKsBT2crRSAgJg9PRC1PU1lYW/iz75M2RyBVpPSDr7hHa4jgyNCPPKwcHXPG5YvnSHNp5eLAQAAAQD+D/4BAABJAAAAAAAAAAAAAAAEsPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvgEAAAEA/g/+AQAASgAAAAAAAAAAAAAABDL46DAicBGq0m1GJOTvp5qEs0rrUrE8BfOc3Bz0PTq5RaGTmCI2qgQCSKiF46bcg+b04cRqudl7vzGic0ZCJOEBAAABAP4P/gEAAEsAAAAAAAAAAAAAAAR8Nb8RnpD1GI7x4UbweP7u7+hb5es9MgKHAI4zb62HYDo5uUO1hgim972b4q8j1ngL2pIReVoZHptMRgdF66CUAQAAAQD+D/4BAABMAAAAAAAAAAAAAAAEIRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3gEAAAEA/g/+AQAATQAAAAAAAAAAAAAABObmIbCR/FSQU7+6LJYOAc5yWIQ6ESOsGmAsTJgnZ063AqxwP3whSqExc9iSihNB3QxVBe/6ELoc7plySu6WgUUBAAABAP4P/gEAAE4AAAAAAAAAAAAAAATSElT1II++YzMgF1kWo09dZrp2qHtZ0fRwgj3L4LJLysbecvjwFyWtr0eYqFVVQfI9Y0fljvEPAAHtt+BKORQxAQAAAQD+D/4BAABPAAAAAAAAAAAAAAAE7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SAEAAAEA/g/+AQAAUAAAAAAAAAAAAAAABJdywrhejIAzcEwypHWBhIoWI7eaUT2xIOOq7ZZp0j5VG4JgfCziKyiW2GBQUm5z2iXsTCrYjzvIZnkY0c9k3fgBAAABAP4P/gEAAFEAAAAAAAAAAAAAAARInVqZkAlSJlL4+GxUt/m0bJ2VpUHwR0WlpI7iCaJQpQ7GTyrOfkAjLhl4lSaHbbOch2T+4wBRPamXcXHNVQf5AQAAAQD+D/4BAABSAAAAAAAAAAAAAAAEZf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6cswEAAAEA/g/+AQAAUwAAAAAAAAAAAAAABBh00jUmCAkO7HB+7GfjNqxaKUaC4fLdmy0lugW4K7S7GoTiAeYsgFSX/Ro1it3GEw2jI+F3QaTNXAOqSEtCr9sBAAABAP4P/gEAAFQAAAAAAAAAAAAAAASmBFziEnj+w2NYJJL0CadLjTHds0wNOSceAvlRowFMzImdT3QSBaHVHP4wL14W7gG439TBmMpC5j/W/eszscx+AQAAAQD+D/4BAABVAAAAAAAAAAAAAAAE55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrgEAAAEA/g/+AQAAVgAAAAAAAAAAAAAABI8WsiykoaxKqsydHrpkG1YU2EDNuwn09U9+foAoAxaC/NiS7F6kye+s7+gNGCzoBJy1DLy87A7BiK5fDRaU9oEBAAABAP4P/gEAAFcAAAAAAAAAAAAAAAR3rls2Uhp3G+lv8DZptV2WoqpXnreO5GdnVa2TqzWwhHy42xdHvTGojNWrFV/V5OoO6fBPYyRzMR5p7MIpNmHAAQAAAQD+D/4BAABYAAAAAAAAAAAAAAAErBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+AEAAAEA/g/+AQAAWQAAAAAAAAAAAAAABJZULDC0lA1D0+OI3a1Pzt+6pZ4n4rQz/mcK5pmXKEisiyr7WcacldJ9v2w/zeLQQAGf4CRHWVOyjK2qCtfl2AIBAAABAP4P/gEAAFoAAAAAAAAAAAAAAATQoj/rTvGjFJOgfsaM3UV9JsuhTT5u1OJyOxBJZCWH+FnKQ3wqmYx/u5jA9bdH5qRnpH/DXxmVdIcFheJhQ87eAQAAAQD+D/4BAABbAAAAAAAAAAAAAAAEbuRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYowEAAAEA/g/+AQAAXAAAAAAAAAAAAAAABInJQB3jajZuvMxbZ2dHvtS9slCHb8zaGrilOFgQN1bx/7zxYnhe6n0ZcFGVPgwPT/Wz1yEvdLpcaFKAh9t7FdsBAAABAP4P/gEAAF0AAAAAAAAAAAAAAAQ9gC2FNrabZUrG69IPcM8L8bL5T6w4DUsC5PyaSZG6/D40AJJp5cRD40dxUXus42XqpxrFXdS56bBrCT7v5IkvAQAAAQD+D/4BAABeAAAAAAAAAAAAAAAE+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBgEAAAEA/g/+AQAAXwAAAAAAAAAAAAAABFO9XMk2prodQkTQn6RmOraNvJcbzcDxuBrs/xFY4H9yZs79L5Q6dWrU/XkuXQ4zGB7nKR21p7Oi8H9wSs+rL3cBAAABAP4P/gEAAGAAAAAAAAAAAAAAAAQE0ZtYt93R5Q9puGRdRWbSPy669ETJOHmi9Fr93KjD8GoBtknIL7l9T4jNA7OYArNiphEAhKhGF1Cvd4hn89eqAQAAAQD+D/4BAABhAAAAAAAAAAAAAAAEVVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEgIAAAEAAAiAAAAAYgAAAAAAAAAAAAAABAR6RRXrJZFq11slD52ypvsWGFWK7gopxnH7UgWmvM6BfYWTuAXEghVLx1U7c6SGOmM1J2LbhIWfgvYhF48Z2rIBAAABAAgAgAAAAGMAAAAAAAAAAAAAAAQFxovRWfpDALCt7djvXudUdlsBrhQESKDMWbpV2xV1P8xtnfzGiPVf0c+RmFuZoEZQPVby/EB999sN7xsDoAqdAQAAAQAEAIAAAABkAAAAAAAAAAAAAAAE4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6AEAAAEAAAhAAAAAZQAAAAAAAAAAAAAABEQUU9oKhJdCCkAAU+F04+/LaZPb+3oafpms59h21HmZdWDHWhgEKoWqYxkwnu7sO8tH6w4uIEtLh84b6RbiNbABAAABAAAIIAAAAGYAAAAAAAAAAAAAAARpjaAyYqY+HF9T7QR2c35c20ZuN9CDBmPjeTwbd/KsMz9R1nDDrGtbGYOS7PZ4JlyGpV4AGNXkGmKV06tRsFOoAQAAAQAEACAAAABnAAAAAAAAAAAAAAAE3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+QEAAAEAAAgAAAAAaAAAAAAAAAAAAAAABGnrxJAjbuypT0aWC48JnXLjc+mwxYhO2fFwuAj6hMY076x7oIdvEM1F1TmbYmIIXIilGnDZLasXacpqZYpdW3gBAAABAAAIEAAAAGkAAAAAAAAAAAAAAAQRXr6i9OwRcI8CnnyDZ0PrwvGg//ArmlG+DLQn8fE8YHTT2iYU+/dh63QeJqq+siuA9MG4LrAIfUtM5j3UQ7mFAQAAAQAAAhAAAABqAAAAAAAAAAAAAAAE9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDwEAAAEAAAAQAAAAawAAAAAAAAAAAAAABOQFeD86fNH4Ry/NyTOi6AOqU0FVoAdR6LzAbC0PTmViw6lWPDFaGwVzUpgCYv/wrIerXGO3uy58th4NbRJTIyABAAABAIAAEAAAAGwAAAAAAAAAAAAAAAR0o3x+BWp3S9QiPG4kjo//1JJJ7+YH2u8D3wJIfawmeVn84JlY7UMm/GPyO8pN9hR0Z9yrZ0PGgpoLpse5OWBzAQAAAQAAABAAAABtAAAAAAAAAAAAAAAEnrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3QEAAAEAAAAQAAAAbgAAAAAAAAAAAAAABFcdPS8xKAWucw54nh/C0jEU6I+4q/yXqtBruqif9RnAavRpH6BAKF7y4ltVPSdahP2Pzsmqt98OadmVqzTRzRMBAAABAAgAEAAAAG8AAAAAAAAAAAAAAARVM3gS44fBcSRfNfmdO9VjizsT8qvPsI4LzGR+1tspFgCX3q8+JSywaR4wQtAw6cs4nyTcFjX5ljna221mcdxdAQAAAQAEABAAAABwAAAAAAAAAAAAAAAE/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754gEAAAEAAgAQAAAAcQAAAAAAAAAAAAAABAl15M4J/nVwD7N1gcBPir563+FhAsAXX433mB6THlcVhNBHHger4VhkobOsItCGBKjEiM3ThdV40PzJJuXe2XUBAAABAAAICAAAAHIAAAAAAAAAAAAAAASUrV4l7KTVlfxSSWoV3/cDrRS5n/pRV8ZPYu4ajdanj/Pt5FNFhj7TE67aSkKU/68xOL3Ao59eLa+NSk7VGjvqAQAAAQAEAAgAAABzAAAAAAAAAAAAAAAEh1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhAEAAAEAAAgEAAAAdAAAAAAAAAAAAAAABGgpanYEw1T0hBoKAkvEAxt+xrvMnPZUxzQEJbM7UOhDXrShDv/2/Mt9TDLtmWj25+JFbCAAc1S12C4QhnpBg6sBAAABAAQABAAAAHUAAAAAAAAAAAAAAARixLZ7da2CfDtarnddcEtxXomFGwSryGR+D3URJVp0ivOv3A7qMkMxmcJBsebUa5zm38J0OIVJJ9Y/nwU269PdAQAAAQAACAABAAB2AAAAAAAAAAAAAAAEnlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlRegEAAAEABAAAAQAAdwAAAAAAAAAAAAAABMcOdIqcpF3C7LS3lh+1kXULsrCano7gBj3d9L3dYuc0siit1hPoo8x5iysXYgjLR9aR8+/KzoNASkmDkgf9iocBAAABAAIAAAEAAHgAAAAAAAAAAAAAAAS7Pr+0TLYgWb1Fg7K8qXzzN3Nl/AR8pmadf0KPUEeN5IY24Yu4wPWRHzLlu15ibCoqbW2Pybhxv9ooSiuvp8dZAQAAAQCAAAIAAAB5AAAAAAAAAAAAAAAE6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQEAAAEA/g/+AQAAegAAAAAAAAAAAAAABAMzkSnc9Wbfe0822EJyKyN2Yom1qUV1H6aP8NMTidtBqTWHdm3dzFPZt9c0v2idUyZeiXy06JPN2PB4zbp2E9ABAAABAP4P/gEAAHsAAAAAAAAAAAAAAAQ8lYdRvVEV68oLBoUD1GUbm0J34U7mJGH0DwcS2SYEfYuLTeImuIHqbokg3isbPcrcktrAjv+94DXHNEo/ohIHAQAAAQD+D/4BAAB8AAAAAAAAAAAAAAAEWjvinW/rM9KEauFCgiRU1VM6Vn4zvv0bPy6DcvjHLNKl1F9cLMW0axsqGqcpQdEr9X9A5V4lWV2cNiXTDUZXhQEAAAEA/g/+AQAAfQAAAAAAAAAAAAAABDLu0dIOIoPU1LhksSWr58uUb9HoAhLaWUTTK2WmEtb8ZIiMRohlMKHs1Ny2syEPihNOIU603zT4MVOYM4uxeT8BAAABAP4P/gEAAH4AAAAAAAAAAAAAAATh8KTv3CyEx3MynasfTqpaskTiKiWouEJQf46K4iBT75EHT73g2UMvzVq07sZfnm5Qq56jS3Ec228TIjoPtZ0zAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAd21pbGwAAAAMAAAACwAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAPAEAAAoAAIBGAQAADAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAkwIAABMAAIBjbGkuanMAAAIAAAAoAwAACQAAgGNsaS5qcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAbWltZQAAAABjbGkuanMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAZXNidWlsZABGGgAACwAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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ybmFsU3RyaW5nPiAxNiBzaXplb2YsIDggYWxpZ25vZgp4lwAAAAAAANa7AAAAAAAACjx1OD4gMSBzaXplb2YsIDEgYWxpZ25vZgoAAHdpbmRtaWxsLWNsaWVzbS9tYWluLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2luZG1pbGwtY2xpLy0vd2luZG1pbGwtY2xpLTEuMzkzLjIudGd6QGF5b25saS9qc2V4dGdpdGlnbm9yZS1wYXJzZXJtaW5pbWF0Y2h3aW5kbWlsbC1jbGllbnRAZGVuby9zaGltLWRlbm9odHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZGVuby9zaGltLWRlbm8vLS9zaGltLWRlbm8tMC4xOC4yLnRnekBkZW5vL3NoaW0tZGVuby10ZXN0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGRlbm8vc2hpbS1kZW5vLXRlc3QvLS9zaGltLWRlbm8tdGVzdC0wLjUuMC50Z3pub2RlLXdoaWNoYmluL3doaWNoLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hpY2gvLS93aGljaC00LjAuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pc2V4ZS8tL2lzZXhlLTMuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dzLy0vd3MtOC4xOC4wLnRnemJ1ZmZlcnV0aWx1dGYtOC12YWxpZGF0ZWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dpbmRtaWxsLWNsaWVudC8tL3dpbmRtaWxsLWNsaWVudC0xLjM2NC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL29wZW4vLS9vcGVuLTEwLjEuMC50Z3pkZWZhdWx0LWJyb3dzZXJkZWZpbmUtbGF6eS1wcm9waXMtaW5zaWRlLWNvbnRhaW5lcmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzLXdzbC8tL2lzLXdzbC0zLjEuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1pbnNpZGUtY29udGFpbmVyLy0vaXMtaW5zaWRlLWNvbnRhaW5lci0xLjAuMC50Z3ppcy1kb2NrZXJodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1kb2NrZXIvLS9pcy1kb2NrZXItMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmaW5lLWxhenktcHJvcC8tL2RlZmluZS1sYXp5LXByb3AtMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLy0vZGVmYXVsdC1icm93c2VyLTUuMi4xLnRnemJ1bmRsZS1uYW1lZGVmYXVsdC1icm93c2VyLWlkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLWlkLy0vZGVmYXVsdC1icm93c2VyLWlkLTUuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2J1bmRsZS1uYW1lLy0vYnVuZGxlLW5hbWUtNC4xLjAudGd6cnVuLWFwcGxlc2NyaXB0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcnVuLWFwcGxlc2NyaXB0Ly0vcnVuLWFwcGxlc2NyaXB0LTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21pbmltYXRjaC8tL21pbmltYXRjaC0xMC4wLjEudGd6YnJhY2UtZXhwYW5zaW9uaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnJhY2UtZXhwYW5zaW9uLy0vYnJhY2UtZXhwYW5zaW9uLTIuMC4xLnRnemJhbGFuY2VkLW1hdGNoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYmFsYW5jZWQtbWF0Y2gvLS9iYWxhbmNlZC1tYXRjaC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9qc3ppcC8tL2pzemlwLTMuNy4xLnRnenJlYWRhYmxlLXN0cmVhbXNldC1pbW1lZGlhdGUtc2hpbWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NldC1pbW1lZGlhdGUtc2hpbS8tL3NldC1pbW1lZGlhdGUtc2hpbS0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yZWFkYWJsZS1zdHJlYW0vLS9yZWFkYWJsZS1zdHJlYW0tMi4zLjgudGd6Y29yZS11dGlsLWlzcHJvY2Vzcy1uZXh0aWNrLWFyZ3NzYWZlLWJ1ZmZlcnN0cmluZ19kZWNvZGVydXRpbC1kZXByZWNhdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlsLWRlcHJlY2F0ZS8tL3V0aWwtZGVwcmVjYXRlLTEuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0cmluZ19kZWNvZGVyLy0vc3RyaW5nX2RlY29kZXItMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZS1idWZmZXIvLS9zYWZlLWJ1ZmZlci01LjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wcm9jZXNzLW5leHRpY2stYXJncy8tL3Byb2Nlc3MtbmV4dGljay1hcmdzLTIuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzYXJyYXkvLS9pc2FycmF5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2luaGVyaXRzLy0vaW5oZXJpdHMtMi4wLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29yZS11dGlsLWlzLy0vY29yZS11dGlsLWlzLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Bha28vLS9wYWtvLTEuMC4xMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9saWUvLS9saWUtMy4zLjAudGd6aW1tZWRpYXRlaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaW1tZWRpYXRlLy0vaW1tZWRpYXRlLTMuMC42LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dpdGlnbm9yZS1wYXJzZXIvLS9naXRpZ25vcmUtcGFyc2VyLTAuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2V4cHJlc3MvLS9leHByZXNzLTQuMTkuMi50Z3plbmNvZGV1cmxwcm94eS1hZGRyYm9keS1wYXJzZXJlc2NhcGUtaHRtbGh0dHAtZXJyb3Jzb24tZmluaXNoZWR1dGlscy1tZXJnZWNvbnRlbnQtdHlwZWZpbmFsaGFuZGxlcnJhbmdlLXBhcnNlcnNlcnZlLXN0YXRpY2FycmF5LWZsYXR0ZW5wYXRoLXRvLXJlZ2V4cHNldHByb3RvdHlwZW9mY29va2llLXNpZ25hdHVyZW1lcmdlLWRlc2NyaXB0b3JzY29udGVudC1kaXNwb3NpdGlvbmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtZGlzcG9zaXRpb24vLS9jb250ZW50LWRpc3Bvc2l0aW9uLTAuNS40LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NhZmUtYnVmZmVyLy0vc2FmZS1idWZmZXItNS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVyZ2UtZGVzY3JpcHRvcnMvLS9tZXJnZS1kZXNjcmlwdG9ycy0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9jb29raWUtc2lnbmF0dXJlLy0vY29va2llLXNpZ25hdHVyZS0xLjAuNi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zZXRwcm90b3R5cGVvZi8tL3NldHByb3RvdHlwZW9mLTEuMi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3BhdGgtdG8tcmVnZXhwLy0vcGF0aC10by1yZWdleHAtMC4xLjcudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYXJyYXktZmxhdHRlbi8tL2FycmF5LWZsYXR0ZW4tMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2VydmUtc3RhdGljLy0vc2VydmUtc3RhdGljLTEuMTUuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lc2NhcGUtaHRtbC8tL2VzY2FwZS1odG1sLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VuY29kZXVybC8tL2VuY29kZXVybC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wYXJzZXVybC8tL3BhcnNldXJsLTEuMy4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NlbmQvLS9zZW5kLTAuMTguMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yYW5nZS1wYXJzZXIvLS9yYW5nZS1wYXJzZXItMS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvb24tZmluaXNoZWQvLS9vbi1maW5pc2hlZC0yLjQuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lZS1maXJzdC8tL2VlLWZpcnN0LTEuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2h0dHAtZXJyb3JzLy0vaHR0cC1lcnJvcnMtMi4wLjAudGd6dG9pZGVudGlmaWVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdG9pZGVudGlmaWVyLy0vdG9pZGVudGlmaWVyLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0YXR1c2VzLy0vc3RhdHVzZXMtMi4wLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVwZC8tL2RlcGQtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVzdHJveS8tL2Rlc3Ryb3ktMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnJlc2gvLS9mcmVzaC0wLjUuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9kZWJ1Zy8tL2RlYnVnLTIuNi45LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21zLy0vbXMtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS8tL21pbWUtMS42LjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXRhZy8tL2V0YWctMS44LjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbXMvLS9tcy0yLjEuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9maW5hbGhhbmRsZXIvLS9maW5hbGhhbmRsZXItMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdW5waXBlLy0vdW5waXBlLTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtdHlwZS8tL2NvbnRlbnQtdHlwZS0xLjAuNS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlscy1tZXJnZS8tL3V0aWxzLW1lcmdlLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2JvZHktcGFyc2VyLy0vYm9keS1wYXJzZXItMS4yMC4yLnRnemljb252LWxpdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pY29udi1saXRlLy0vaWNvbnYtbGl0ZS0wLjQuMjQudGd6Pj0gMi4xLjIgPCAzc2FmZXItYnVmZmVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZXItYnVmZmVyLy0vc2FmZXItYnVmZmVyLTIuMS4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Jhdy1ib2R5Ly0vcmF3LWJvZHktMi41LjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnl0ZXMvLS9ieXRlcy0zLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy90eXBlLWlzLy0vdHlwZS1pcy0xLjYuMTgudGd6bWltZS10eXBlc21lZGlhLXR5cGVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVkaWEtdHlwZXIvLS9tZWRpYS10eXBlci0wLjMuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9taW1lLXR5cGVzLy0vbWltZS10eXBlcy0yLjEuMzUudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS1kYi8tL21pbWUtZGItMS41Mi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3FzLy0vcXMtNi4xMS4wLnRnenNpZGUtY2hhbm5lbGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NpZGUtY2hhbm5lbC8tL3NpZGUtY2hhbm5lbC0xLjAuNi50Z3pjYWxsLWJpbmRlcy1lcnJvcnNnZXQtaW50cmluc2ljb2JqZWN0LWluc3BlY3RodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9vYmplY3QtaW5zcGVjdC8tL29iamVjdC1pbnNwZWN0LTEuMTMuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9nZXQtaW50cmluc2ljLy0vZ2V0LWludHJpbnNpYy0xLjIuNC50Z3pmdW5jdGlvbi1iaW5kaGFzLXByb3RvaGFzLXN5bWJvbHNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXNvd24vLS9oYXNvd24tMi4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnVuY3Rpb24tYmluZC8tL2Z1bmN0aW9uLWJpbmQtMS4xLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaGFzLXN5bWJvbHMvLS9oYXMtc3ltYm9scy0xLjAuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvdG8vLS9oYXMtcHJvdG8tMS4wLjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZXJyb3JzLy0vZXMtZXJyb3JzLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NhbGwtYmluZC8tL2NhbGwtYmluZC0xLjAuNy50Z3plcy1kZWZpbmUtcHJvcGVydHlzZXQtZnVuY3Rpb24tbGVuZ3RoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2V0LWZ1bmN0aW9uLWxlbmd0aC8tL3NldC1mdW5jdGlvbi1sZW5ndGgtMS4yLjIudGd6ZGVmaW5lLWRhdGEtcHJvcGVydHloYXMtcHJvcGVydHktZGVzY3JpcHRvcnNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMvLS9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMtMS4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZGVmaW5lLXByb3BlcnR5Ly0vZXMtZGVmaW5lLXByb3BlcnR5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dvcGQvLS9nb3BkLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RlZmluZS1kYXRhLXByb3BlcnR5Ly0vZGVmaW5lLWRhdGEtcHJvcGVydHktMS4xLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcHJveHktYWRkci8tL3Byb3h5LWFkZHItMi4wLjcudGd6Zm9yd2FyZGVkaXBhZGRyLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaXBhZGRyLmpzLy0vaXBhZGRyLmpzLTEuOS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ZvcndhcmRlZC8tL2ZvcndhcmRlZC0wLjIuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9tZXRob2RzLy0vbWV0aG9kcy0xLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9hY2NlcHRzLy0vYWNjZXB0cy0xLjMuOC50Z3puZWdvdGlhdG9yaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbmVnb3RpYXRvci8tL25lZ290aWF0b3ItMC42LjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29va2llLy0vY29va2llLTAuNi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3ZhcnkvLS92YXJ5LTEuMS4yLnRnemJpbi9lc2J1aWxkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXNidWlsZC8tL2VzYnVpbGQtMC4yMy4xLnRnekBlc2J1aWxkL2FpeC1wcGM2NEBlc2J1aWxkL2FuZHJvaWQtYXJtQGVzYnVpbGQvYW5kcm9pZC1hcm02NEBlc2J1aWxkL2FuZHJvaWQteDY0QGVzYnVpbGQvZGFyd2luLWFybTY0QGVzYnVpbGQvZGFyd2luLXg2NEBlc2J1aWxkL2ZyZWVic2QtYXJtNjRAZXNidWlsZC9mcmVlYnNkLXg2NEBlc2J1aWxkL2xpbnV4LWFybUBlc2J1aWxkL2xpbnV4LWFybTY0QGVzYnVpbGQvbGludXgtaWEzMkBlc2J1aWxkL2xpbnV4LWxvb25nNjRAZXNidWlsZC9saW51eC1taXBzNjRlbEBlc2J1aWxkL2xpbnV4LXBwYzY0QGVzYnVpbGQvbGludXgtcmlzY3Y2NEBlc2J1aWxkL2xpbnV4LXMzOTB4QGVzYnVpbGQvbGludXgteDY0QGVzYnVpbGQvbmV0YnNkLXg2NEBlc2J1aWxkL29wZW5ic2QtYXJtNjRAZXNidWlsZC9vcGVuYnNkLXg2NEBlc2J1aWxkL3N1bm9zLXg2NEBlc2J1aWxkL3dpbjMyLWFybTY0QGVzYnVpbGQvd2luMzItaWEzMkBlc2J1aWxkL3dpbjMyLXg2NGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLXg2NC8tL3dpbjMyLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvd2luMzItaWEzMi8tL3dpbjMyLWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLWFybTY0Ly0vd2luMzItYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3N1bm9zLXg2NC8tL3N1bm9zLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC14NjQvLS9vcGVuYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC1hcm02NC8tL29wZW5ic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL25ldGJzZC14NjQvLS9uZXRic2QteDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC14NjQvLS9saW51eC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXMzOTB4Ly0vbGludXgtczM5MHgtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXJpc2N2NjQvLS9saW51eC1yaXNjdjY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1wcGM2NC8tL2xpbnV4LXBwYzY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1taXBzNjRlbC8tL2xpbnV4LW1pcHM2NGVsLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1sb29uZzY0Ly0vbGludXgtbG9vbmc2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvbGludXgtaWEzMi8tL2xpbnV4LWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybTY0Ly0vbGludXgtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybS8tL2xpbnV4LWFybS0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC14NjQvLS9mcmVlYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC1hcm02NC8tL2ZyZWVic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2Rhcndpbi14NjQvLS9kYXJ3aW4teDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9kYXJ3aW4tYXJtNjQvLS9kYXJ3aW4tYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQteDY0Ly0vYW5kcm9pZC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQtYXJtNjQvLS9hbmRyb2lkLWFybTY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9hbmRyb2lkLWFybS8tL2FuZHJvaWQtYXJtLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9haXgtcHBjNjQvLS9haXgtcHBjNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VzLW1haW4vLS9lcy1tYWluLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RpZmYvLS9kaWZmLTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0BheW9ubGkvanNleHQvLS9qc2V4dC0wLjkuNjMudGd6c3Vkby1wcm9tcHRodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zdWRvLXByb21wdC8tL3N1ZG8tcHJvbXB0LTkuMi4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ljb252LWxpdGUvLS9pY29udi1saXRlLTAuNi4zLnRnej49IDIuMS4yIDwgMy4wLjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==' +WHERE hash = -28028598712388162 AND workspace_id = 'admins'; \ No newline at end of file diff --git a/backend/migrations/20240908222917_migrate_to_new_cli_3.down.sql b/backend/migrations/20240908222917_migrate_to_new_cli_3.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240908222917_migrate_to_new_cli_3.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240908222917_migrate_to_new_cli_3.up.sql b/backend/migrations/20240908222917_migrate_to_new_cli_3.up.sql new file mode 100644 index 0000000000..678fbc81d7 --- /dev/null +++ b/backend/migrations/20240908222917_migrate_to_new_cli_3.up.sql @@ -0,0 +1,15 @@ +-- Add up migration script here +UPDATE script SET content = 'import * as wmill from "windmill-cli@1.393.2" + +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": "latest" + } +} +//bun.lockb +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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACmAgAANAAAgAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA2gIAAE4AAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADEDAAA6AACAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABrAwAASAAAgAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAswMAAEYAAIAFAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABYEAABMAACABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABiBAAAPgAAgAQAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAArwQAAEYAAIAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPUEAAA7AACACgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA/BQAARgAAgAIAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAkwUAAEQAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANcFAAAyAACAAwAAAAcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAqBgAATAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdgYAAEYAAIACAAAAAwAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMHAABEAACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABHBwAARAAAgAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAiwcAAD4AAIAFAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkHAABQAACAAgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAZCAAANgAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAATwgAADgAAIACAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAIcIAABAAACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADHCAAAMQAAgAEAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA+AgAAC4AAIADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAC8JAAA6AACAAwAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABpCQAASAAAgAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAsQkAADcAAIAEAAAAEwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8KAABOAACAAAAAAAUAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAANCwAAPgAAgAUAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAASwsAAEoAAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJULAABIAACAAQAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADdCwAARAAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAIQwAAEQAAIAAAAAAAQAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGUMAABCAACAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACnDAAAQQAAgAEAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA6AwAAD4AAIABAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACYNAAA6AACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABgDQAAOAAAgAEAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAmA0AADEAAIAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkNAABAAACAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAJDgAAPgAAgAIAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAARw4AADgAAIABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAH8OAAA+AACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADJDgAAQAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACQ8AADgAAIACAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEEPAAAwAACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABxDwAANgAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAApw8AADIAAIAAAAAABQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANkPAAAyAACAAgAAAAYAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAALEAAALAAAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxAAADAAAIABAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGcQAAAwAACAAQAAAAgAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACXEAAALAAAgAIAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAwxAAAEAAAIABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMRAAA0AACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA3EQAAQAAAgAEAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdxEAAD4AAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAALURAAA/AACAAQAAABQAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD+EQAAPQAAgAAAAAAEAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAUxIAAEAAAIACAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJMSAAA4AACAAgAAAAUAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADLEgAAMgAAgAMAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA/RIAADcAAIABAAAABgAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEkTAAA+AACAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACHEwAAPQAAgAIAAAABAAAAIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxBMAADcAAIABAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPsTAAAtAACABgAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA0FAAAQAAAgAEAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAoRQAAEUAAIABAAAADQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOYUAABCAACAAQAAAAIAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABJFQAANAAAgAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAfRUAAEIAAIABAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8VAAA+AACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD9FQAAOgAAgAEAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxYAADoAAIABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHEWAAA6AACAAQAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADQFgAATgAAgAEAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAShcAAFgAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKIXAABMAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADuFwAAMAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAHhgAAFAAAIABAAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAG4YAAA8AACAAgAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC8GAAAOgAAgAEAAAAJAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA9hgAADoAAIAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADAZAAA2AACAAQAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABmGQAANgAAgAEAAAADAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAphkAADwAAIAAAAAABgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOIZAAA0AACAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAWGgAAMAAAgAEAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAURoAADcAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGgcAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACsHAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA8hwAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADodAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAB+HQAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxh0AAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABIeAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABYHgAARAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAnB4AAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOQeAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAwHwAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAeB8AAE4AAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMYfAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAASIAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAWCAAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKAgAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADkIAAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAALCEAAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHghAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC+IQAASgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACCIAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAFAiAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACcIgAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAbWltZQAAAABjbGkuanMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAZXNidWlsZABGGgAACwAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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ybmFsU3RyaW5nPiAxNiBzaXplb2YsIDggYWxpZ25vZgp4lwAAAAAAANa7AAAAAAAACjx1OD4gMSBzaXplb2YsIDEgYWxpZ25vZgoAAHdpbmRtaWxsLWNsaWVzbS9tYWluLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2luZG1pbGwtY2xpLy0vd2luZG1pbGwtY2xpLTEuMzkzLjIudGd6QGF5b25saS9qc2V4dGdpdGlnbm9yZS1wYXJzZXJtaW5pbWF0Y2h3aW5kbWlsbC1jbGllbnRAZGVuby9zaGltLWRlbm9odHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZGVuby9zaGltLWRlbm8vLS9zaGltLWRlbm8tMC4xOC4yLnRnekBkZW5vL3NoaW0tZGVuby10ZXN0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGRlbm8vc2hpbS1kZW5vLXRlc3QvLS9zaGltLWRlbm8tdGVzdC0wLjUuMC50Z3pub2RlLXdoaWNoYmluL3doaWNoLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hpY2gvLS93aGljaC00LjAuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pc2V4ZS8tL2lzZXhlLTMuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dzLy0vd3MtOC4xOC4wLnRnemJ1ZmZlcnV0aWx1dGYtOC12YWxpZGF0ZWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dpbmRtaWxsLWNsaWVudC8tL3dpbmRtaWxsLWNsaWVudC0xLjM2NC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL29wZW4vLS9vcGVuLTEwLjEuMC50Z3pkZWZhdWx0LWJyb3dzZXJkZWZpbmUtbGF6eS1wcm9waXMtaW5zaWRlLWNvbnRhaW5lcmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzLXdzbC8tL2lzLXdzbC0zLjEuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1pbnNpZGUtY29udGFpbmVyLy0vaXMtaW5zaWRlLWNvbnRhaW5lci0xLjAuMC50Z3ppcy1kb2NrZXJodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1kb2NrZXIvLS9pcy1kb2NrZXItMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmaW5lLWxhenktcHJvcC8tL2RlZmluZS1sYXp5LXByb3AtMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLy0vZGVmYXVsdC1icm93c2VyLTUuMi4xLnRnemJ1bmRsZS1uYW1lZGVmYXVsdC1icm93c2VyLWlkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLWlkLy0vZGVmYXVsdC1icm93c2VyLWlkLTUuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2J1bmRsZS1uYW1lLy0vYnVuZGxlLW5hbWUtNC4xLjAudGd6cnVuLWFwcGxlc2NyaXB0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcnVuLWFwcGxlc2NyaXB0Ly0vcnVuLWFwcGxlc2NyaXB0LTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21pbmltYXRjaC8tL21pbmltYXRjaC0xMC4wLjEudGd6YnJhY2UtZXhwYW5zaW9uaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnJhY2UtZXhwYW5zaW9uLy0vYnJhY2UtZXhwYW5zaW9uLTIuMC4xLnRnemJhbGFuY2VkLW1hdGNoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYmFsYW5jZWQtbWF0Y2gvLS9iYWxhbmNlZC1tYXRjaC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9qc3ppcC8tL2pzemlwLTMuNy4xLnRnenJlYWRhYmxlLXN0cmVhbXNldC1pbW1lZGlhdGUtc2hpbWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NldC1pbW1lZGlhdGUtc2hpbS8tL3NldC1pbW1lZGlhdGUtc2hpbS0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yZWFkYWJsZS1zdHJlYW0vLS9yZWFkYWJsZS1zdHJlYW0tMi4zLjgudGd6Y29yZS11dGlsLWlzcHJvY2Vzcy1uZXh0aWNrLWFyZ3NzYWZlLWJ1ZmZlcnN0cmluZ19kZWNvZGVydXRpbC1kZXByZWNhdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlsLWRlcHJlY2F0ZS8tL3V0aWwtZGVwcmVjYXRlLTEuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0cmluZ19kZWNvZGVyLy0vc3RyaW5nX2RlY29kZXItMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZS1idWZmZXIvLS9zYWZlLWJ1ZmZlci01LjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wcm9jZXNzLW5leHRpY2stYXJncy8tL3Byb2Nlc3MtbmV4dGljay1hcmdzLTIuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzYXJyYXkvLS9pc2FycmF5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2luaGVyaXRzLy0vaW5oZXJpdHMtMi4wLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29yZS11dGlsLWlzLy0vY29yZS11dGlsLWlzLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Bha28vLS9wYWtvLTEuMC4xMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9saWUvLS9saWUtMy4zLjAudGd6aW1tZWRpYXRlaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaW1tZWRpYXRlLy0vaW1tZWRpYXRlLTMuMC42LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dpdGlnbm9yZS1wYXJzZXIvLS9naXRpZ25vcmUtcGFyc2VyLTAuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2V4cHJlc3MvLS9leHByZXNzLTQuMTkuMi50Z3plbmNvZGV1cmxwcm94eS1hZGRyYm9keS1wYXJzZXJlc2NhcGUtaHRtbGh0dHAtZXJyb3Jzb24tZmluaXNoZWR1dGlscy1tZXJnZWNvbnRlbnQtdHlwZWZpbmFsaGFuZGxlcnJhbmdlLXBhcnNlcnNlcnZlLXN0YXRpY2FycmF5LWZsYXR0ZW5wYXRoLXRvLXJlZ2V4cHNldHByb3RvdHlwZW9mY29va2llLXNpZ25hdHVyZW1lcmdlLWRlc2NyaXB0b3JzY29udGVudC1kaXNwb3NpdGlvbmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtZGlzcG9zaXRpb24vLS9jb250ZW50LWRpc3Bvc2l0aW9uLTAuNS40LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NhZmUtYnVmZmVyLy0vc2FmZS1idWZmZXItNS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVyZ2UtZGVzY3JpcHRvcnMvLS9tZXJnZS1kZXNjcmlwdG9ycy0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9jb29raWUtc2lnbmF0dXJlLy0vY29va2llLXNpZ25hdHVyZS0xLjAuNi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zZXRwcm90b3R5cGVvZi8tL3NldHByb3RvdHlwZW9mLTEuMi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3BhdGgtdG8tcmVnZXhwLy0vcGF0aC10by1yZWdleHAtMC4xLjcudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYXJyYXktZmxhdHRlbi8tL2FycmF5LWZsYXR0ZW4tMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2VydmUtc3RhdGljLy0vc2VydmUtc3RhdGljLTEuMTUuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lc2NhcGUtaHRtbC8tL2VzY2FwZS1odG1sLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VuY29kZXVybC8tL2VuY29kZXVybC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wYXJzZXVybC8tL3BhcnNldXJsLTEuMy4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NlbmQvLS9zZW5kLTAuMTguMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yYW5nZS1wYXJzZXIvLS9yYW5nZS1wYXJzZXItMS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvb24tZmluaXNoZWQvLS9vbi1maW5pc2hlZC0yLjQuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lZS1maXJzdC8tL2VlLWZpcnN0LTEuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2h0dHAtZXJyb3JzLy0vaHR0cC1lcnJvcnMtMi4wLjAudGd6dG9pZGVudGlmaWVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdG9pZGVudGlmaWVyLy0vdG9pZGVudGlmaWVyLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0YXR1c2VzLy0vc3RhdHVzZXMtMi4wLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVwZC8tL2RlcGQtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVzdHJveS8tL2Rlc3Ryb3ktMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnJlc2gvLS9mcmVzaC0wLjUuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9kZWJ1Zy8tL2RlYnVnLTIuNi45LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21zLy0vbXMtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS8tL21pbWUtMS42LjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXRhZy8tL2V0YWctMS44LjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbXMvLS9tcy0yLjEuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9maW5hbGhhbmRsZXIvLS9maW5hbGhhbmRsZXItMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdW5waXBlLy0vdW5waXBlLTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtdHlwZS8tL2NvbnRlbnQtdHlwZS0xLjAuNS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlscy1tZXJnZS8tL3V0aWxzLW1lcmdlLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2JvZHktcGFyc2VyLy0vYm9keS1wYXJzZXItMS4yMC4yLnRnemljb252LWxpdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pY29udi1saXRlLy0vaWNvbnYtbGl0ZS0wLjQuMjQudGd6Pj0gMi4xLjIgPCAzc2FmZXItYnVmZmVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZXItYnVmZmVyLy0vc2FmZXItYnVmZmVyLTIuMS4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Jhdy1ib2R5Ly0vcmF3LWJvZHktMi41LjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnl0ZXMvLS9ieXRlcy0zLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy90eXBlLWlzLy0vdHlwZS1pcy0xLjYuMTgudGd6bWltZS10eXBlc21lZGlhLXR5cGVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVkaWEtdHlwZXIvLS9tZWRpYS10eXBlci0wLjMuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9taW1lLXR5cGVzLy0vbWltZS10eXBlcy0yLjEuMzUudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS1kYi8tL21pbWUtZGItMS41Mi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3FzLy0vcXMtNi4xMS4wLnRnenNpZGUtY2hhbm5lbGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NpZGUtY2hhbm5lbC8tL3NpZGUtY2hhbm5lbC0xLjAuNi50Z3pjYWxsLWJpbmRlcy1lcnJvcnNnZXQtaW50cmluc2ljb2JqZWN0LWluc3BlY3RodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9vYmplY3QtaW5zcGVjdC8tL29iamVjdC1pbnNwZWN0LTEuMTMuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9nZXQtaW50cmluc2ljLy0vZ2V0LWludHJpbnNpYy0xLjIuNC50Z3pmdW5jdGlvbi1iaW5kaGFzLXByb3RvaGFzLXN5bWJvbHNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXNvd24vLS9oYXNvd24tMi4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnVuY3Rpb24tYmluZC8tL2Z1bmN0aW9uLWJpbmQtMS4xLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaGFzLXN5bWJvbHMvLS9oYXMtc3ltYm9scy0xLjAuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvdG8vLS9oYXMtcHJvdG8tMS4wLjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZXJyb3JzLy0vZXMtZXJyb3JzLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NhbGwtYmluZC8tL2NhbGwtYmluZC0xLjAuNy50Z3plcy1kZWZpbmUtcHJvcGVydHlzZXQtZnVuY3Rpb24tbGVuZ3RoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2V0LWZ1bmN0aW9uLWxlbmd0aC8tL3NldC1mdW5jdGlvbi1sZW5ndGgtMS4yLjIudGd6ZGVmaW5lLWRhdGEtcHJvcGVydHloYXMtcHJvcGVydHktZGVzY3JpcHRvcnNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMvLS9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMtMS4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZGVmaW5lLXByb3BlcnR5Ly0vZXMtZGVmaW5lLXByb3BlcnR5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dvcGQvLS9nb3BkLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RlZmluZS1kYXRhLXByb3BlcnR5Ly0vZGVmaW5lLWRhdGEtcHJvcGVydHktMS4xLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcHJveHktYWRkci8tL3Byb3h5LWFkZHItMi4wLjcudGd6Zm9yd2FyZGVkaXBhZGRyLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaXBhZGRyLmpzLy0vaXBhZGRyLmpzLTEuOS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ZvcndhcmRlZC8tL2ZvcndhcmRlZC0wLjIuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9tZXRob2RzLy0vbWV0aG9kcy0xLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9hY2NlcHRzLy0vYWNjZXB0cy0xLjMuOC50Z3puZWdvdGlhdG9yaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbmVnb3RpYXRvci8tL25lZ290aWF0b3ItMC42LjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29va2llLy0vY29va2llLTAuNi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3ZhcnkvLS92YXJ5LTEuMS4yLnRnemJpbi9lc2J1aWxkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXNidWlsZC8tL2VzYnVpbGQtMC4yMy4xLnRnekBlc2J1aWxkL2FpeC1wcGM2NEBlc2J1aWxkL2FuZHJvaWQtYXJtQGVzYnVpbGQvYW5kcm9pZC1hcm02NEBlc2J1aWxkL2FuZHJvaWQteDY0QGVzYnVpbGQvZGFyd2luLWFybTY0QGVzYnVpbGQvZGFyd2luLXg2NEBlc2J1aWxkL2ZyZWVic2QtYXJtNjRAZXNidWlsZC9mcmVlYnNkLXg2NEBlc2J1aWxkL2xpbnV4LWFybUBlc2J1aWxkL2xpbnV4LWFybTY0QGVzYnVpbGQvbGludXgtaWEzMkBlc2J1aWxkL2xpbnV4LWxvb25nNjRAZXNidWlsZC9saW51eC1taXBzNjRlbEBlc2J1aWxkL2xpbnV4LXBwYzY0QGVzYnVpbGQvbGludXgtcmlzY3Y2NEBlc2J1aWxkL2xpbnV4LXMzOTB4QGVzYnVpbGQvbGludXgteDY0QGVzYnVpbGQvbmV0YnNkLXg2NEBlc2J1aWxkL29wZW5ic2QtYXJtNjRAZXNidWlsZC9vcGVuYnNkLXg2NEBlc2J1aWxkL3N1bm9zLXg2NEBlc2J1aWxkL3dpbjMyLWFybTY0QGVzYnVpbGQvd2luMzItaWEzMkBlc2J1aWxkL3dpbjMyLXg2NGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLXg2NC8tL3dpbjMyLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvd2luMzItaWEzMi8tL3dpbjMyLWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLWFybTY0Ly0vd2luMzItYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3N1bm9zLXg2NC8tL3N1bm9zLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC14NjQvLS9vcGVuYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC1hcm02NC8tL29wZW5ic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL25ldGJzZC14NjQvLS9uZXRic2QteDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC14NjQvLS9saW51eC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXMzOTB4Ly0vbGludXgtczM5MHgtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXJpc2N2NjQvLS9saW51eC1yaXNjdjY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1wcGM2NC8tL2xpbnV4LXBwYzY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1taXBzNjRlbC8tL2xpbnV4LW1pcHM2NGVsLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1sb29uZzY0Ly0vbGludXgtbG9vbmc2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvbGludXgtaWEzMi8tL2xpbnV4LWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybTY0Ly0vbGludXgtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybS8tL2xpbnV4LWFybS0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC14NjQvLS9mcmVlYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC1hcm02NC8tL2ZyZWVic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2Rhcndpbi14NjQvLS9kYXJ3aW4teDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9kYXJ3aW4tYXJtNjQvLS9kYXJ3aW4tYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQteDY0Ly0vYW5kcm9pZC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQtYXJtNjQvLS9hbmRyb2lkLWFybTY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9hbmRyb2lkLWFybS8tL2FuZHJvaWQtYXJtLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9haXgtcHBjNjQvLS9haXgtcHBjNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VzLW1haW4vLS9lcy1tYWluLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RpZmYvLS9kaWZmLTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0BheW9ubGkvanNleHQvLS9qc2V4dC0wLjkuNjMudGd6c3Vkby1wcm9tcHRodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zdWRvLXByb21wdC8tL3N1ZG8tcHJvbXB0LTkuMi4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ljb252LWxpdGUvLS9pY29udi1saXRlLTAuNi4zLnRnej49IDIuMS4yIDwgMy4wLjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==' +WHERE hash = -28028598712388162 AND workspace_id = 'admins'; \ No newline at end of file diff --git a/backend/migrations/20240910151523_resource_type_file_format.down.sql b/backend/migrations/20240910151523_resource_type_file_format.down.sql new file mode 100644 index 0000000000..f891983f26 --- /dev/null +++ b/backend/migrations/20240910151523_resource_type_file_format.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +ALTER TABLE resource_type + DROP COLUMN format_extension; diff --git a/backend/migrations/20240910151523_resource_type_file_format.up.sql b/backend/migrations/20240910151523_resource_type_file_format.up.sql new file mode 100644 index 0000000000..7bc683ff14 --- /dev/null +++ b/backend/migrations/20240910151523_resource_type_file_format.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TABLE resource_type + ADD COLUMN format_extension VARCHAR(20); diff --git a/backend/migrations/20240917172503_job_routing.down.sql b/backend/migrations/20240917172503_job_routing.down.sql new file mode 100644 index 0000000000..569385aa5a --- /dev/null +++ b/backend/migrations/20240917172503_job_routing.down.sql @@ -0,0 +1,7 @@ +-- Add down migration script here +DROP TABLE http_trigger; +DROP TYPE http_method; + +ALTER TABLE script DROP COLUMN has_preprocessor; + +DROP FUNCTION prevent_route_path_change(); \ No newline at end of file diff --git a/backend/migrations/20240917172503_job_routing.up.sql b/backend/migrations/20240917172503_job_routing.up.sql new file mode 100644 index 0000000000..42dd41e199 --- /dev/null +++ b/backend/migrations/20240917172503_job_routing.up.sql @@ -0,0 +1,61 @@ +-- Add up migration script here +CREATE TYPE http_method AS ENUM ('get', 'post', 'put', 'delete', 'patch'); + +CREATE TABLE http_trigger ( + path VARCHAR(255) NOT NULL, + route_path VARCHAR(255) NOT NULL, + route_path_key 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 '{}', + is_async BOOLEAN NOT NULL DEFAULT FALSE, + requires_auth BOOLEAN NOT NULL DEFAULT FALSE, + http_method http_method NOT NULL, + PRIMARY KEY (path, workspace_id) +); + + +GRANT SELECT, UPDATE ON http_trigger TO windmill_user; +GRANT ALL ON http_trigger TO windmill_admin; + +ALTER TABLE http_trigger ENABLE ROW LEVEL SECURITY; + +CREATE POLICY see_folder_extra_perms_user_select ON http_trigger FOR SELECT TO windmill_user +USING (SPLIT_PART(http_trigger.path, '/', 1) = 'f' AND SPLIT_PART(http_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_update ON http_trigger FOR UPDATE TO windmill_user +USING (SPLIT_PART(http_trigger.path, '/', 1) = 'f' AND SPLIT_PART(http_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); + + +CREATE POLICY see_extra_perms_user_select ON http_trigger FOR SELECT TO windmill_user +USING (extra_perms ? CONCAT('u/', current_setting('session.user'))); +CREATE POLICY see_extra_perms_user_update ON http_trigger FOR UPDATE TO windmill_user +USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean); + +CREATE POLICY see_extra_perms_groups_select ON http_trigger FOR SELECT TO windmill_user +USING (extra_perms ?| regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]); +CREATE POLICY see_extra_perms_groups_update ON http_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 OR REPLACE FUNCTION prevent_route_path_change() +RETURNS TRIGGER AS $$ +BEGIN + IF CURRENT_USER <> 'windmill_admin' AND NEW.route_path <> OLD.route_path THEN + RAISE EXCEPTION 'Modification of route_path is only allowed by admins'; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER check_route_path_change +BEFORE UPDATE ON http_trigger +FOR EACH ROW +EXECUTE FUNCTION prevent_route_path_change(); + +ALTER TABLE script ADD COLUMN has_preprocessor BOOLEAN; diff --git a/backend/migrations/20240919200009_migrate_smtp_settings.down.sql b/backend/migrations/20240919200009_migrate_smtp_settings.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240919200009_migrate_smtp_settings.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240919200009_migrate_smtp_settings.up.sql b/backend/migrations/20240919200009_migrate_smtp_settings.up.sql new file mode 100644 index 0000000000..54ac58675e --- /dev/null +++ b/backend/migrations/20240919200009_migrate_smtp_settings.up.sql @@ -0,0 +1,8 @@ +-- Add up migration script here +INSERT INTO global_settings (name, value) +SELECT 'smtp_settings', config +FROM config +WHERE name = 'server' +ON CONFLICT (name) DO UPDATE SET value = excluded.value; + +DELETE FROM config WHERE name = 'server'; diff --git a/backend/migrations/20240924213010_add_last_occupancy_rates.down.sql b/backend/migrations/20240924213010_add_last_occupancy_rates.down.sql new file mode 100644 index 0000000000..d2249d992d --- /dev/null +++ b/backend/migrations/20240924213010_add_last_occupancy_rates.down.sql @@ -0,0 +1,5 @@ +-- Add down migration script here +ALTER TABLE worker_ping +DROP COLUMN occupancy_rate_15s, +DROP COLUMN occupancy_rate_5m, +DROP COLUMN occupancy_rate_30m; diff --git a/backend/migrations/20240924213010_add_last_occupancy_rates.up.sql b/backend/migrations/20240924213010_add_last_occupancy_rates.up.sql new file mode 100644 index 0000000000..39033324c3 --- /dev/null +++ b/backend/migrations/20240924213010_add_last_occupancy_rates.up.sql @@ -0,0 +1,5 @@ +-- Add up migration script here +ALTER TABLE worker_ping +ADD COLUMN occupancy_rate_15s REAL, +ADD COLUMN occupancy_rate_5m REAL, +ADD COLUMN occupancy_rate_30m REAL; diff --git a/backend/migrations/20240930183601_add_preprocessor_kind.down.sql b/backend/migrations/20240930183601_add_preprocessor_kind.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240930183601_add_preprocessor_kind.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240930183601_add_preprocessor_kind.up.sql b/backend/migrations/20240930183601_add_preprocessor_kind.up.sql new file mode 100644 index 0000000000..d70dc181aa --- /dev/null +++ b/backend/migrations/20240930183601_add_preprocessor_kind.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +ALTER TYPE SCRIPT_KIND ADD VALUE IF NOT EXISTS 'preprocessor'; \ No newline at end of file diff --git a/backend/migrations/20241002163207_add_websocket_triggers.down.sql b/backend/migrations/20241002163207_add_websocket_triggers.down.sql new file mode 100644 index 0000000000..bb579574a8 --- /dev/null +++ b/backend/migrations/20241002163207_add_websocket_triggers.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +DROP TABLE websocket_trigger; \ No newline at end of file diff --git a/backend/migrations/20241002163207_add_websocket_triggers.up.sql b/backend/migrations/20241002163207_add_websocket_triggers.up.sql new file mode 100644 index 0000000000..4d6b44cb8f --- /dev/null +++ b/backend/migrations/20241002163207_add_websocket_triggers.up.sql @@ -0,0 +1,67 @@ +-- Add up migration script here + +CREATE TABLE websocket_trigger ( + path VARCHAR(255) NOT NULL, + url 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) NULL, + last_server_ping TIMESTAMPTZ NULL, + error TEXT NULL, + enabled BOOLEAN NOT NULL, + filters JSONB[] NOT NULL DEFAULT '{}', + PRIMARY KEY (path, workspace_id) +); + +GRANT ALL ON websocket_trigger TO windmill_user; +GRANT ALL ON websocket_trigger TO windmill_admin; + +ALTER TABLE websocket_trigger ENABLE ROW LEVEL SECURITY; + +CREATE POLICY admin_policy ON websocket_trigger FOR ALL TO windmill_admin USING (true); + +CREATE POLICY see_folder_extra_perms_user_select ON websocket_trigger FOR SELECT TO windmill_user +USING (SPLIT_PART(websocket_trigger.path, '/', 1) = 'f' AND SPLIT_PART(websocket_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_insert ON websocket_trigger FOR INSERT TO windmill_user +WITH CHECK (SPLIT_PART(websocket_trigger.path, '/', 1) = 'f' AND SPLIT_PART(websocket_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_update ON websocket_trigger FOR UPDATE TO windmill_user +USING (SPLIT_PART(websocket_trigger.path, '/', 1) = 'f' AND SPLIT_PART(websocket_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_delete ON websocket_trigger FOR DELETE TO windmill_user +USING (SPLIT_PART(websocket_trigger.path, '/', 1) = 'f' AND SPLIT_PART(websocket_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); + +CREATE POLICY see_own ON websocket_trigger FOR ALL TO windmill_user +USING (SPLIT_PART(websocket_trigger.path, '/', 1) = 'u' AND SPLIT_PART(websocket_trigger.path, '/', 2) = current_setting('session.user')); +CREATE POLICY see_member ON websocket_trigger FOR ALL TO windmill_user +USING (SPLIT_PART(websocket_trigger.path, '/', 1) = 'g' AND SPLIT_PART(websocket_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.groups'), ',')::text[])); + +CREATE POLICY see_extra_perms_user_select ON websocket_trigger FOR SELECT TO windmill_user +USING (extra_perms ? CONCAT('u/', current_setting('session.user'))); +CREATE POLICY see_extra_perms_user_insert ON websocket_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 websocket_trigger FOR UPDATE TO windmill_user +USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean); +CREATE POLICY see_extra_perms_user_delete ON websocket_trigger FOR DELETE TO windmill_user +USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean); + +CREATE POLICY see_extra_perms_groups_select ON websocket_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 websocket_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 websocket_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 websocket_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/20241006144414_admin_policy.down.sql b/backend/migrations/20241006144414_admin_policy.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20241006144414_admin_policy.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20241006144414_admin_policy.up.sql b/backend/migrations/20241006144414_admin_policy.up.sql new file mode 100644 index 0000000000..e6a3f3807e --- /dev/null +++ b/backend/migrations/20241006144414_admin_policy.up.sql @@ -0,0 +1,24 @@ +-- Add up migration script here +DO +$$ +DECLARE + tbl_name text; + policy_exists boolean; + tbl_names text[] := ARRAY['account', 'app', 'audit', 'capture', 'completed_job', 'flow', 'folder', 'http_trigger', 'queue', 'raw_app', 'resource', 'schedule', 'script', 'usr_to_group', 'variable']; +BEGIN + FOR tbl_name IN SELECT unnest(tbl_names) + LOOP + SELECT EXISTS ( + SELECT 1 + FROM pg_policies + WHERE schemaname = 'public' + AND tablename = tbl_name + AND policyname = 'admin_policy' + ) INTO policy_exists; + + IF NOT policy_exists THEN + EXECUTE format('CREATE POLICY admin_policy ON %I TO windmill_admin USING (true);', tbl_name); + END IF; + END LOOP; +END; +$$; \ No newline at end of file diff --git a/backend/migrations/20241008155800_concurrency_lock_table.down.sql b/backend/migrations/20241008155800_concurrency_lock_table.down.sql new file mode 100644 index 0000000000..2c7ec9a8f8 --- /dev/null +++ b/backend/migrations/20241008155800_concurrency_lock_table.down.sql @@ -0,0 +1,2 @@ +-- Drop the alert_locks table +DROP TABLE IF EXISTS concurrency_locks; diff --git a/backend/migrations/20241008155800_concurrency_lock_table.up.sql b/backend/migrations/20241008155800_concurrency_lock_table.up.sql new file mode 100644 index 0000000000..8449de152a --- /dev/null +++ b/backend/migrations/20241008155800_concurrency_lock_table.up.sql @@ -0,0 +1,6 @@ +-- Create the alert_locks table +CREATE TABLE concurrency_locks ( + id VARCHAR PRIMARY KEY, + last_locked_at TIMESTAMP NOT NULL, + owner VARCHAR NULL +); diff --git a/backend/migrations/20241024125924_autoscaling.down.sql b/backend/migrations/20241024125924_autoscaling.down.sql new file mode 100644 index 0000000000..8f536a7553 --- /dev/null +++ b/backend/migrations/20241024125924_autoscaling.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +DROP TABLE autoscaling_event; +DROP TYPE autoscaling_event_type; diff --git a/backend/migrations/20241024125924_autoscaling.up.sql b/backend/migrations/20241024125924_autoscaling.up.sql new file mode 100644 index 0000000000..fa3b161d56 --- /dev/null +++ b/backend/migrations/20241024125924_autoscaling.up.sql @@ -0,0 +1,13 @@ +-- Add up migration script here +CREATE TYPE AUTOSCALING_EVENT_TYPE AS ENUM ('full_scaleout', 'scalein', 'scaleout'); + +CREATE TABLE autoscaling_event ( + id SERIAL PRIMARY KEY, + worker_group TEXT NOT NULL, + event_type AUTOSCALING_EVENT_TYPE NOT NULL, + desired_workers INTEGER NOT NULL, + applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + reason TEXT +); + +CREATE INDEX autoscaling_event_worker_group_idx ON autoscaling_event (worker_group, applied_at); \ No newline at end of file diff --git a/backend/oauth_connect.json b/backend/oauth_connect.json index 034aece2f4..994d9999fd 100644 --- a/backend/oauth_connect.json +++ b/backend/oauth_connect.json @@ -152,5 +152,24 @@ "vismanet_erp_interactive_api:read", "vismanet_erp_interactive_api:update" ] + }, + "spotify": { + "auth_url": "https://accounts.spotify.com/authorize", + "token_url": "https://accounts.spotify.com/api/token", + "scopes": [ + "user-read-playback-state", + "user-modify-playback-state", + "user-read-currently-playing", + "playlist-read-private", + "playlist-read-collaborative", + "playlist-modify-private", + "playlist-modify-public", + "user-follow-read", + "user-read-playback-position", + "user-read-recently-played", + "user-top-read", + "user-library-modify", + "user-library-read" + ] } } \ No newline at end of file diff --git a/backend/parsers/windmill-parser-bash/Cargo.toml b/backend/parsers/windmill-parser-bash/Cargo.toml index 9d2070f6c8..4c7db23313 100644 --- a/backend/parsers/windmill-parser-bash/Cargo.toml +++ b/backend/parsers/windmill-parser-bash/Cargo.toml @@ -8,9 +8,14 @@ authors.workspace = true name = "windmill_parser_bash" path = "./src/lib.rs" +[target.'cfg(target_arch = "wasm32")'.dependencies] +regex-lite.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +regex.workspace = true + [dependencies] windmill-parser.workspace = true anyhow.workspace = true -regex.workspace = true lazy_static.workspace = true -serde_json.workspace = true \ No newline at end of file +serde_json.workspace = true diff --git a/backend/parsers/windmill-parser-bash/src/lib.rs b/backend/parsers/windmill-parser-bash/src/lib.rs index fa5eb3973d..9b62ad3b0c 100644 --- a/backend/parsers/windmill-parser-bash/src/lib.rs +++ b/backend/parsers/windmill-parser-bash/src/lib.rs @@ -1,7 +1,12 @@ #![allow(non_snake_case)] // TODO: switch to parse_* function naming use anyhow::anyhow; + +#[cfg(not(target_arch = "wasm32"))] use regex::Regex; +#[cfg(target_arch = "wasm32")] +use regex_lite::Regex; + use serde_json::json; use std::collections::HashMap; @@ -11,7 +16,13 @@ pub fn parse_bash_sig(code: &str) -> anyhow::Result { let parsed = parse_bash_file(&code)?; if let Some(x) = parsed { let args = x; - Ok(MainArgSignature { star_args: false, star_kwargs: false, args, no_main_func: None }) + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) } else { Err(anyhow!("Error parsing bash script".to_string())) } @@ -21,7 +32,13 @@ pub fn parse_powershell_sig(code: &str) -> anyhow::Result { let parsed = parse_powershell_file(&code)?; if let Some(x) = parsed { let args = x; - Ok(MainArgSignature { star_args: false, star_kwargs: false, args, no_main_func: None }) + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) } else { Err(anyhow!("Error parsing powershell script".to_string())) } @@ -168,7 +185,8 @@ non_required="${5:-}" oidx: None } ], - no_main_func: None + no_main_func: None, + has_preprocessor: None } ); diff --git a/backend/parsers/windmill-parser-go/src/lib.rs b/backend/parsers/windmill-parser-go/src/lib.rs index c2564dbbd2..218a6dc3ec 100644 --- a/backend/parsers/windmill-parser-go/src/lib.rs +++ b/backend/parsers/windmill-parser-go/src/lib.rs @@ -42,6 +42,7 @@ pub fn parse_go_sig(code: &str) -> anyhow::Result { star_kwargs: false, args, no_main_func: Some(false), + has_preprocessor: None, }) } else { Ok(MainArgSignature { @@ -49,6 +50,7 @@ pub fn parse_go_sig(code: &str) -> anyhow::Result { star_kwargs: false, args: vec![], no_main_func: Some(true), + has_preprocessor: None, }) } } @@ -241,7 +243,8 @@ func main(x int, y string, z bool, l []string, o struct { Name string `json:"nam oidx: None }, ], - no_main_func: Some(false) + no_main_func: Some(false), + has_preprocessor: None } ); diff --git a/backend/parsers/windmill-parser-graphql/Cargo.toml b/backend/parsers/windmill-parser-graphql/Cargo.toml index da1a8bf9c6..7f0a93b6f3 100644 --- a/backend/parsers/windmill-parser-graphql/Cargo.toml +++ b/backend/parsers/windmill-parser-graphql/Cargo.toml @@ -8,9 +8,14 @@ authors.workspace = true name = "windmill_parser_graphql" path = "./src/lib.rs" +[target.'cfg(target_arch = "wasm32")'.dependencies] +regex-lite.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +regex.workspace = true + [dependencies] windmill-parser.workspace = true anyhow.workspace = true -regex.workspace = true lazy_static.workspace = true -serde_json.workspace = true \ No newline at end of file +serde_json.workspace = true diff --git a/backend/parsers/windmill-parser-graphql/src/lib.rs b/backend/parsers/windmill-parser-graphql/src/lib.rs index 99eb8db261..a900c3244d 100644 --- a/backend/parsers/windmill-parser-graphql/src/lib.rs +++ b/backend/parsers/windmill-parser-graphql/src/lib.rs @@ -1,7 +1,12 @@ #![allow(non_snake_case)] // TODO: switch to parse_* function naming use anyhow::anyhow; + +#[cfg(not(target_arch = "wasm32"))] use regex::Regex; +#[cfg(target_arch = "wasm32")] +use regex_lite::Regex; + use serde_json::json; use windmill_parser::{Arg, MainArgSignature, Typ}; @@ -10,7 +15,13 @@ pub fn parse_graphql_sig(code: &str) -> anyhow::Result { let parsed = parse_graphql_file(&code)?; if let Some(x) = parsed { let args = x; - Ok(MainArgSignature { star_args: false, star_kwargs: false, args, no_main_func: None }) + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) } else { Err(anyhow!("Error parsing sql".to_string())) } @@ -114,7 +125,8 @@ query($i: Int, $arr: [String]!, $wahoo: String = "wahoo") { oidx: None } ], - no_main_func: None + no_main_func: None, + has_preprocessor: None } ); diff --git a/backend/parsers/windmill-parser-php/Cargo.toml b/backend/parsers/windmill-parser-php/Cargo.toml index 05d86a6c67..8bd3182f91 100644 --- a/backend/parsers/windmill-parser-php/Cargo.toml +++ b/backend/parsers/windmill-parser-php/Cargo.toml @@ -14,6 +14,3 @@ itertools.workspace = true serde_json.workspace = true anyhow.workspace = true php-parser-rs.workspace = true -convert_case.workspace = true -lazy_static.workspace = true -regex.workspace = true \ No newline at end of file diff --git a/backend/parsers/windmill-parser-php/src/lib.rs b/backend/parsers/windmill-parser-php/src/lib.rs index 27befc1ea7..4c239c21c9 100644 --- a/backend/parsers/windmill-parser-php/src/lib.rs +++ b/backend/parsers/windmill-parser-php/src/lib.rs @@ -1,7 +1,5 @@ -use convert_case::{Case, Casing}; -use regex::Regex; use serde_json::Value; -use windmill_parser::{Arg, MainArgSignature, Typ}; +use windmill_parser::{to_snake_case, Arg, MainArgSignature, Typ}; use php_parser_rs::parser::{ self, @@ -13,17 +11,6 @@ use php_parser_rs::parser::{ }, }; -lazy_static::lazy_static! { - static ref RE_SNK_CASE: Regex = Regex::new(r"_(\d)").unwrap(); -} - -fn to_snake_case(s: String) -> String { - let r = s.to_case(Case::Snake); - - // s_3 => s3 - RE_SNK_CASE.replace_all(&r, "$1").to_string() -} - fn parse_php_type(e: Type) -> Typ { match e { Type::Float(_) => Typ::Float, @@ -32,7 +19,7 @@ fn parse_php_type(e: Type) -> Typ { Type::String(_) => Typ::Str(None), Type::Array(_) => Typ::List(Box::new(Typ::Str(None))), Type::Object(_) => Typ::Object(vec![]), - Type::Named(_, name) => Typ::Resource(to_snake_case(name.to_string())), + Type::Named(_, name) => Typ::Resource(to_snake_case(name.to_string().as_ref())), _ => Typ::Unknown, } } @@ -95,6 +82,7 @@ pub fn parse_php_signature( star_kwargs: false, args, no_main_func: Some(false), + has_preprocessor: None, }) } else { Ok(MainArgSignature { @@ -102,6 +90,7 @@ pub fn parse_php_signature( star_kwargs: false, args: vec![], no_main_func: Some(true), + has_preprocessor: None, }) } } @@ -172,7 +161,8 @@ function main(string $input1 = \"hey\", bool $input2 = false, int $input3 = 3, f oidx: None } ], - no_main_func: Some(false) + no_main_func: Some(false), + has_preprocessor: None } ); diff --git a/backend/parsers/windmill-parser-py-imports/Cargo.toml b/backend/parsers/windmill-parser-py-imports/Cargo.toml index 665b6df211..078b15418b 100644 --- a/backend/parsers/windmill-parser-py-imports/Cargo.toml +++ b/backend/parsers/windmill-parser-py-imports/Cargo.toml @@ -8,13 +8,18 @@ authors.workspace = true name = "windmill_parser_py_imports" path = "./src/lib.rs" +[target.'cfg(target_arch = "wasm32")'.dependencies] +regex-lite.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +regex.workspace = true + [dependencies] windmill-parser.workspace = true windmill-common.workspace = true rustpython-parser.workspace = true phf.workspace = true itertools.workspace = true -regex.workspace = true serde_json.workspace = true anyhow.workspace = true lazy_static.workspace = true diff --git a/backend/parsers/windmill-parser-py-imports/src/lib.rs b/backend/parsers/windmill-parser-py-imports/src/lib.rs index 00810a7858..841a763ec2 100644 --- a/backend/parsers/windmill-parser-py-imports/src/lib.rs +++ b/backend/parsers/windmill-parser-py-imports/src/lib.rs @@ -10,7 +10,11 @@ use async_recursion::async_recursion; use itertools::Itertools; use lazy_static::lazy_static; use phf::phf_map; + +#[cfg(not(target_arch = "wasm32"))] use regex::Regex; +#[cfg(target_arch = "wasm32")] +use regex_lite::Regex; use rustpython_parser::{ ast::{Stmt, StmtImport, StmtImportFrom, Suite}, @@ -57,6 +61,7 @@ static PYTHON_IMPORTS_REPLACEMENT: phf::Map<&'static str, &'static str> = phf_ma "opensearchpy" => "opensearch-py", "lokalise" => "python-lokalise-api", "msgraph" => "msgraph-sdk", + "pythonjsonlogger" => "python-json-logger", }; fn replace_import(x: String) -> String { diff --git a/backend/parsers/windmill-parser-py/src/lib.rs b/backend/parsers/windmill-parser-py/src/lib.rs index 3adde32185..5b42171478 100644 --- a/backend/parsers/windmill-parser-py/src/lib.rs +++ b/backend/parsers/windmill-parser-py/src/lib.rs @@ -63,9 +63,17 @@ pub fn parse_python_signature( ) -> anyhow::Result { let main_name = override_main.unwrap_or("main".to_string()); + let has_preprocessor = !filter_non_main(code, "preprocessor").is_empty(); + let filtered_code = filter_non_main(code, &main_name); if filtered_code.is_empty() { - return Err(anyhow::anyhow!("No main function found".to_string(),)); + return Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args: vec![], + no_main_func: Some(true), + has_preprocessor: Some(has_preprocessor), + }); } let ast = Suite::parse(&filtered_code, "main.py") .map_err(|e| anyhow::anyhow!("Error parsing code: {}", e.to_string()))?; @@ -119,6 +127,7 @@ pub fn parse_python_signature( }) .collect(), no_main_func: Some(false), + has_preprocessor: Some(has_preprocessor), }) } else { Ok(MainArgSignature { @@ -126,6 +135,7 @@ pub fn parse_python_signature( star_kwargs: false, args: vec![], no_main_func: Some(true), + has_preprocessor: Some(has_preprocessor), }) } } @@ -325,6 +335,7 @@ def main(test1: str, name: datetime.datetime = datetime.now(), byte: bytes = byt }, ], no_main_func: Some(false), + has_preprocessor: Some(false) } ); @@ -389,6 +400,7 @@ def main(test1: str, } ], no_main_func: Some(false), + has_preprocessor: Some(false) } ); @@ -448,6 +460,7 @@ def main(test1: str, } ], no_main_func: Some(false), + has_preprocessor: Some(false) } ); @@ -491,6 +504,7 @@ def main(test1: Literal["foo", "bar"], test2: List[Literal["foo", "bar"]]): retu } ], no_main_func: Some(false), + has_preprocessor: Some(false) } ); @@ -521,6 +535,59 @@ def main(test1: DynSelect_foo): return oidx: None }], no_main_func: Some(false), + has_preprocessor: Some(false) + } + ); + + Ok(()) + } + + #[test] + fn test_parse_python_sig_6() -> anyhow::Result<()> { + let code = r#" + +import os + +def hello(): return + +"#; + //println!("{}", serde_json::to_string()?); + assert_eq!( + parse_python_signature(code, None)?, + MainArgSignature { + star_args: false, + star_kwargs: false, + args: vec![], + no_main_func: Some(true), + has_preprocessor: Some(false) + } + ); + + Ok(()) + } + + #[test] + fn test_parse_python_sig_7() -> anyhow::Result<()> { + let code = r#" + +import os + +def preprocessor(): return + +def main(): return + + + +"#; + //println!("{}", serde_json::to_string()?); + assert_eq!( + parse_python_signature(code, None)?, + MainArgSignature { + star_args: false, + star_kwargs: false, + args: vec![], + no_main_func: Some(false), + has_preprocessor: Some(true) } ); diff --git a/backend/parsers/windmill-parser-rust/Cargo.toml b/backend/parsers/windmill-parser-rust/Cargo.toml new file mode 100644 index 0000000000..e1dcf84449 --- /dev/null +++ b/backend/parsers/windmill-parser-rust/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "windmill-parser-rust" +version.workspace = true +edition.workspace = true +authors.workspace = true + +[lib] +name = "windmill_parser_rust" +path = "./src/lib.rs" + +[dependencies] +windmill-parser.workspace = true +itertools.workspace = true +serde_json.workspace = true +anyhow.workspace = true +convert_case.workspace = true +lazy_static.workspace = true +regex.workspace = true +pulldown-cmark.workspace = true +toml.workspace = true +syn.workspace = true +quote.workspace = true diff --git a/backend/parsers/windmill-parser-rust/manifest/Cargo.toml.default b/backend/parsers/windmill-parser-rust/manifest/Cargo.toml.default new file mode 100644 index 0000000000..6c9e93c8a1 --- /dev/null +++ b/backend/parsers/windmill-parser-rust/manifest/Cargo.toml.default @@ -0,0 +1,16 @@ +[[bin]] +name = "main" +path = "./main.rs" + +[package] +authors = ["Anonymous"] +edition = "2021" +name = "main" +version = "0.1.0" + +[profile.release] +strip = true + +[dependencies] +serde = { version = "1.0.207", features = ["derive"] } +serde_json = "1.0.124" diff --git a/backend/parsers/windmill-parser-rust/src/lib.rs b/backend/parsers/windmill-parser-rust/src/lib.rs new file mode 100644 index 0000000000..5d4d626f4c --- /dev/null +++ b/backend/parsers/windmill-parser-rust/src/lib.rs @@ -0,0 +1,500 @@ +use anyhow::anyhow; +use itertools::Itertools; +use quote::ToTokens; +use regex::Regex; +use windmill_parser::{Arg, MainArgSignature, Typ}; + +pub fn otyp_to_string(otyp: Option) -> String { + otyp.unwrap() +} + +pub fn parse_rust_signature(code: &str) -> anyhow::Result { + let ast: syn::File = syn::parse_file(code)?; + + if let Some(main_fn) = ast.items.iter().find_map(|item| match item { + syn::Item::Fn(f) if f.sig.ident == "main" => Some(f), + _ => None, + }) { + let args = main_fn + .sig + .inputs + .iter() + .map(|param| { + let (otyp, typ, name) = parse_rust_typ(param); + Arg { name, otyp, typ, default: None, has_default: false, oidx: None } + }) + .collect_vec(); + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: Some(false), + has_preprocessor: None, + }) + } else { + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args: vec![], + no_main_func: Some(true), + has_preprocessor: None, + }) + } +} + +pub fn parse_rust_deps_into_manifest(code: &str) -> anyhow::Result { + const MODIFIABLE_MANIFEST_TABLES: &[&str] = &["dependencies"]; + + let partial_manifest = find_embedded_manifest(code).unwrap_or(Manifest::Toml("".to_string())); + let partial_manifest = partial_manifest.into_toml()?; + let mut manif = default_manifest(); + for table_name in MODIFIABLE_MANIFEST_TABLES { + match partial_manifest.get(*table_name) { + Some(toml::Value::Table(tab)) => { + // Merge. + match manif.entry(*table_name) { + toml::map::Entry::Vacant(e) => { + e.insert(toml::Value::Table(tab.to_owned())); + } + toml::map::Entry::Occupied(e) => { + let into_t = match e.into_mut() { + toml::Value::Table(t) => Some(t), + _ => None, + }; + into_t.ok_or(anyhow!(""))?.extend(tab.to_owned()); + } + } + } + Some(v) => { + // Just replace. + manif.insert(table_name.to_string(), v.to_owned()); + } + None => (), + } + } + + Ok(manif.to_string()) +} + +fn parse_pat_type(p: Box) -> Typ { + match *p { + syn::Type::Array(a) => { + let inner_typ = parse_pat_type(a.elem); + Typ::List(Box::new(inner_typ)) + } + // syn::Type::BareFn(_) => todo!(), + // syn::Type::Group(_) => todo!(), + // syn::Type::ImplTrait(_) => todo!(), + // syn::Type::Infer(_) => todo!(), + // syn::Type::Macro(_) => todo!(), + // syn::Type::Never(_) => todo!(), + syn::Type::Paren(e) => parse_pat_type(e.elem), + syn::Type::Path(e) => { + if let Some(u) = e.path.segments.last() { + match u.ident.to_string().as_str() { + "usize" | "u8" | "u16" | "u32" | "u64" | "u128" | "isize" | "i8" | "i16" + | "i32" | "i64" | "i128" => Typ::Int, + "String" | "str" => Typ::Str(None), + "bool" => Typ::Bool, + "f32" | "f64" => Typ::Float, + "Vec" => { + if let syn::PathArguments::AngleBracketed(t) = &u.arguments { + if let Some(syn::GenericArgument::Type(a)) = t.args.last() { + Typ::List(Box::new(parse_pat_type(Box::new(a.clone())))) + } else { + Typ::Unknown + } + } else { + Typ::Unknown + } + } + _ => Typ::Unknown, + } + } else { + Typ::Unknown + } + } + // syn::Type::Ptr(_) => todo!(), + syn::Type::Reference(e) => parse_pat_type(e.elem), + syn::Type::Slice(e) => Typ::List(Box::new(parse_pat_type(e.elem))), + // syn::Type::TraitObject(_) => todo!(), + // syn::Type::Tuple(_) => todo!(), + // syn::Type::Verbatim(_) => todo!(), + _ => Typ::Unknown, + } +} + +fn parse_rust_typ(param_typ: &syn::FnArg) -> (Option, Typ, String) { + match param_typ { + syn::FnArg::Receiver(_) => (None, Typ::Unknown, "self".to_string()), + syn::FnArg::Typed(s) => { + let name = match *s.pat.clone() { + syn::Pat::Ident(p) => p.ident.to_string(), + _ => "undefined".to_string(), + }; + + let otyp = Some(s.ty.to_token_stream().to_string()); + let typ = parse_pat_type(s.ty.clone()); + (otyp, typ, name) + } + } +} + +#[derive(Debug, PartialEq)] +enum Manifest { + Toml(String), + DepList(String), +} + +impl Manifest { + pub fn into_toml(self) -> anyhow::Result { + match self { + Manifest::Toml(s) => toml::from_str(&s), + Manifest::DepList(s) => Manifest::dep_list_to_toml(&s), + } + .map_err(|e| anyhow!("Could not parse embedded manifest: {}", e)) + } + + fn dep_list_to_toml(s: &str) -> ::std::result::Result { + let mut r = String::new(); + r.push_str("[dependencies]\n"); + for dep in s.trim().split(',') { + // If there's no version specified, add one. + match dep.contains('=') { + true => { + r.push_str(dep); + r.push('\n'); + } + false => { + r.push_str(dep); + r.push_str("=\"*\"\n"); + } + } + } + + toml::from_str(&r) + } +} + +fn default_manifest() -> toml::value::Table { + toml::from_str(include_str!("../manifest/Cargo.toml.default")) + .expect("Failed to parse Cargo.toml.default") +} + +/** +* Get a `Manifest` that can be made into a TOML table. The format and logic are the same as in +* the rust-script or cargo-eval projects. +*/ +fn find_embedded_manifest(s: &str) -> Option { + find_short_hand_manifest(s).or_else(|| find_code_block_manifest(s)) +} + +fn find_short_hand_manifest(s: &str) -> Option { + let re: Regex = Regex::new(r"^(?i)\s*//\s*cargo-deps\s*:(.*?)(\r\n|\n)").unwrap(); + /* + This is pretty simple: the only valid syntax for this is for the first, non-blank line to contain a single-line comment whose first token is `cargo-deps:`. That's it. + */ + if let Some(cap) = re.captures(s) { + if let Some(m) = cap.get(1) { + return Some(Manifest::DepList(m.as_str().to_string())); + } + } + None +} + +/** +Locates a "code block manifest" in Rust source. +*/ +fn find_code_block_manifest(s: &str) -> Option { + let re_crate_comment: Regex = { + Regex::new( + r"(?x) + ^\s* + (/\*!|//(!|/)) + ", + ) + .unwrap() + }; + + let start = match re_crate_comment.captures(s) { + Some(cap) => match cap.get(1) { + Some(m) => m.start(), + None => return None, + }, + None => return None, + }; + + let comment = match extract_comment(&s[start..]) { + Some(s) => s, + None => { + return None; + } + }; + + scrape_markdown_manifest(&comment).map(|s| Manifest::Toml(s)) +} + +/** +Extracts the first `Cargo` fenced code block from a chunk of Markdown. +*/ +fn scrape_markdown_manifest(content: &str) -> Option { + use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag}; + + // To match librustdoc/html/markdown.rs, opts. + let exts = Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES; + + let md = Parser::new_ext(content, exts); + + let mut found = false; + let mut output = None; + + for item in md { + match item { + Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(ref info))) + if info.to_lowercase() == "cargo" && output.is_none() => + { + found = true; + } + Event::Text(ref text) if found => { + let s = output.get_or_insert(String::new()); + s.push_str(text); + } + Event::End(Tag::CodeBlock(_)) if found => { + found = false; + } + _ => (), + } + } + + output +} + +/** +Extracts the contents of a Rust doc comment. +*/ +fn extract_comment(s: &str) -> Option { + use std::cmp::min; + + fn extract_block(s: &str) -> Option { + /* + On every line: + + - update nesting level and detect end-of-comment + - if margin is None: + - if there appears to be a margin, set margin. + - strip off margin marker + - update the leading space counter + - strip leading space + - append content + */ + let mut r = String::new(); + + let margin_re: Regex = Regex::new(r"^\s*\*( |$)").unwrap(); + let space_re: Regex = Regex::new(r"^(\s+)").unwrap(); + let nesting_re: Regex = Regex::new(r"/\*|\*/").unwrap(); + + let mut leading_space = None; + let mut margin = None; + let mut depth: u32 = 1; + + for line in s.lines() { + if depth == 0 { + break; + } + + let mut end_of_comment = None; + + for (end, marker) in nesting_re.find_iter(line).map(|m| (m.start(), m.as_str())) { + match (marker, depth) { + ("/*", _) => depth += 1, + ("*/", 1) => { + end_of_comment = Some(end); + depth = 0; + break; + } + ("*/", _) => depth -= 1, + _ => return None, + } + } + + let line = end_of_comment.map(|end| &line[..end]).unwrap_or(line); + + margin = margin.or_else(|| margin_re.find(line).map(|m| m.as_str())); + + let line = if let Some(margin) = margin { + let end = line + .char_indices() + .take(margin.len()) + .map(|(i, c)| i + c.len_utf8()) + .last() + .unwrap_or(0); + &line[end..] + } else { + line + }; + + leading_space = leading_space.or_else(|| space_re.find(line).map(|m| m.end())); + + let strip_len = min(leading_space.unwrap_or(0), line.len()); + let line = &line[strip_len..]; + + r.push_str(line); + + r.push('\n'); + } + + Some(r) + } + + fn extract_line(s: &str) -> Option { + let mut r = String::new(); + + let comment_re = Regex::new(r"^\s*//(!|/)").unwrap(); + + let space_re = Regex::new(r"^(\s+)").unwrap(); + + let mut leading_space = None; + + for line in s.lines() { + let content = match comment_re.find(line) { + Some(m) => &line[m.end()..], + None => break, + }; + + leading_space = leading_space.or_else(|| { + space_re + .captures(content) + .and_then(|c| c.get(1)) + .map(|m| m.end()) + }); + + let strip_len = min(leading_space.unwrap_or(0), content.len()); + let content = &content[strip_len..]; + + r.push_str(content); + + r.push('\n'); + } + + Some(r) + } + + if let Some(stripped) = s.strip_prefix("/*!") { + extract_block(stripped) + } else if s.starts_with("//!") || s.starts_with("///") { + extract_line(s) + } else { + None + } +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_parse_rust_signature() { + let code = r#" +// commenting comments + +fn main( + my_int: i8, + my_vec: Vec, + mut my_arr: [u8; 9], + my_complex: Vec>, +) -> Result { + println!("My int is {}", my_int); +}"#; + + let ret = parse_rust_signature(code).unwrap(); + + assert_eq!(ret.args.len(), 4); + + assert_eq!(ret.args[0].name, "my_int"); + assert_eq!(ret.args[0].otyp, Some("i8".to_string())); + assert_eq!(ret.args[0].typ, Typ::Int); + + assert_eq!(ret.args[1].name, "my_vec"); + assert_eq!(ret.args[1].otyp, Some("Vec < u8 >".to_string())); + assert_eq!(ret.args[1].typ, Typ::List(Box::new(Typ::Int))); + + assert_eq!(ret.args[2].name, "my_arr"); + assert_eq!(ret.args[2].otyp, Some("[u8 ; 9]".to_string())); + assert_eq!(ret.args[2].typ, Typ::List(Box::new(Typ::Int))); + + assert_eq!(ret.args[3].name, "my_complex"); + assert_eq!( + ret.args[3].otyp, + Some("Vec < Result < MyStruct , anyhow :: Error > >".to_string()) + ); + assert_eq!(ret.args[3].typ, Typ::List(Box::new(Typ::Unknown))); + + let code = r#" +// commenting comments + +fn main( + my_str_slice: &str, + my_String: String, + mut my_mut_ref_to_string: &mut String, + my_string_vec: Vec, +) -> Result { + println!("My int is {}", my_int); +}"#; + + let ret = parse_rust_signature(code).unwrap(); + + assert_eq!(ret.args.len(), 4); + + assert_eq!(ret.args[0].name, "my_str_slice"); + assert_eq!(ret.args[0].otyp, Some("& str".to_string())); + assert_eq!(ret.args[0].typ, Typ::Str(None)); + + assert_eq!(ret.args[1].name, "my_String"); + assert_eq!(ret.args[1].otyp, Some("String".to_string())); + assert_eq!(ret.args[1].typ, Typ::Str(None)); + + assert_eq!(ret.args[2].name, "my_mut_ref_to_string"); + assert_eq!(ret.args[2].otyp, Some("& mut String".to_string())); + assert_eq!(ret.args[2].typ, Typ::Str(None)); + + assert_eq!(ret.args[3].name, "my_string_vec"); + assert_eq!(ret.args[3].otyp, Some("Vec < String >".to_string())); + assert_eq!(ret.args[3].typ, Typ::List(Box::new(Typ::Str(None)))); + } + + #[test] + fn test_parse_rust_manifest() { + assert_eq!(find_embedded_manifest("fn main() {}"), None); + + let code = r#" + +//! Crate doc comment right here +//! We need to use the `cargo` language in the code bloc +//! +//! ```cargo +//! [dependencies] +//! time = "0.1.25" +//! ``` + +fn main() { + println!("{}", time::now().rfc822z()); +} + "#; + let manif = find_embedded_manifest(code); + + assert_eq!( + manif, + Some(Manifest::Toml( + r#"[dependencies] +time = "0.1.25" +"# + .to_string() + )) + ); + let _full_manif = parse_rust_deps_into_manifest(code).unwrap(); + } + + #[test] + fn test_default_manifest() { + default_manifest(); + } +} diff --git a/backend/parsers/windmill-parser-sql/Cargo.toml b/backend/parsers/windmill-parser-sql/Cargo.toml index 421aff33a2..085b709faa 100644 --- a/backend/parsers/windmill-parser-sql/Cargo.toml +++ b/backend/parsers/windmill-parser-sql/Cargo.toml @@ -8,9 +8,14 @@ authors.workspace = true name = "windmill_parser_sql" path = "./src/lib.rs" +[target.'cfg(target_arch = "wasm32")'.dependencies] +regex-lite.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +regex.workspace = true + [dependencies] windmill-parser.workspace = true anyhow.workspace = true -regex.workspace = true lazy_static.workspace = true -serde_json.workspace = true \ No newline at end of file +serde_json.workspace = true diff --git a/backend/parsers/windmill-parser-sql/src/lib.rs b/backend/parsers/windmill-parser-sql/src/lib.rs index 8f22bd1faa..dd6bc2b955 100644 --- a/backend/parsers/windmill-parser-sql/src/lib.rs +++ b/backend/parsers/windmill-parser-sql/src/lib.rs @@ -1,7 +1,12 @@ #![allow(non_snake_case)] // TODO: switch to parse_* function naming use anyhow::anyhow; + +#[cfg(not(target_arch = "wasm32"))] use regex::Regex; +#[cfg(target_arch = "wasm32")] +use regex_lite::Regex; + use serde_json::json; use std::{ @@ -15,7 +20,13 @@ pub fn parse_mysql_sig(code: &str) -> anyhow::Result { let parsed = parse_mysql_file(&code)?; if let Some(x) = parsed { let args = x; - Ok(MainArgSignature { star_args: false, star_kwargs: false, args, no_main_func: None }) + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) } else { Err(anyhow!("Error parsing sql".to_string())) } @@ -25,7 +36,13 @@ pub fn parse_pgsql_sig(code: &str) -> anyhow::Result { let parsed = parse_pg_file(&code)?; if let Some(x) = parsed { let args = x; - Ok(MainArgSignature { star_args: false, star_kwargs: false, args, no_main_func: None }) + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) } else { Err(anyhow!("Error parsing sql".to_string())) } @@ -35,7 +52,13 @@ pub fn parse_bigquery_sig(code: &str) -> anyhow::Result { let parsed = parse_bigquery_file(&code)?; if let Some(x) = parsed { let args = x; - Ok(MainArgSignature { star_args: false, star_kwargs: false, args, no_main_func: None }) + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) } else { Err(anyhow!("Error parsing sql".to_string())) } @@ -45,7 +68,13 @@ pub fn parse_snowflake_sig(code: &str) -> anyhow::Result { let parsed = parse_snowflake_file(&code)?; if let Some(x) = parsed { let args = x; - Ok(MainArgSignature { star_args: false, star_kwargs: false, args, no_main_func: None }) + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) } else { Err(anyhow!("Error parsing sql".to_string())) } @@ -55,7 +84,13 @@ pub fn parse_mssql_sig(code: &str) -> anyhow::Result { let parsed = parse_mssql_file(&code)?; if let Some(x) = parsed { let args = x; - Ok(MainArgSignature { star_args: false, star_kwargs: false, args, no_main_func: None }) + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) } else { Err(anyhow!("Error parsing sql".to_string())) } @@ -565,7 +600,8 @@ SELECT * FROM table WHERE token=$1::TEXT AND image=$2::BIGINT oidx: Some(2), }, ], - no_main_func: None + no_main_func: None, + has_preprocessor: None } ); @@ -613,7 +649,8 @@ SELECT $2::TEXT; oidx: Some(3), }, ], - no_main_func: None + no_main_func: None, + has_preprocessor: None } ); @@ -739,7 +776,8 @@ SELECT ?, ?; oidx: None, }, ], - no_main_func: None + no_main_func: None, + has_preprocessor: None } ); @@ -786,7 +824,8 @@ SELECT :param2; oidx: None, }, ], - no_main_func: None + no_main_func: None, + has_preprocessor: None } ); @@ -825,7 +864,8 @@ SELECT @token; oidx: None, }, ], - no_main_func: None + no_main_func: None, + has_preprocessor: None } ); @@ -872,7 +912,8 @@ SELECT ?; oidx: None, } ], - no_main_func: None + no_main_func: None, + has_preprocessor: None } ); @@ -919,7 +960,8 @@ SELECT @p2; oidx: None, }, ], - no_main_func: None + no_main_func: None, + has_preprocessor: None } ); diff --git a/backend/parsers/windmill-parser-ts/Cargo.toml b/backend/parsers/windmill-parser-ts/Cargo.toml index 2a84c4e542..5f04b14f3b 100644 --- a/backend/parsers/windmill-parser-ts/Cargo.toml +++ b/backend/parsers/windmill-parser-ts/Cargo.toml @@ -22,6 +22,5 @@ swc_ecma_ast.workspace = true swc_ecma_visit.workspace = true serde_json.workspace = true anyhow.workspace = true -convert_case.workspace = true regex.workspace = true lazy_static.workspace = true diff --git a/backend/parsers/windmill-parser-ts/src/lib.rs b/backend/parsers/windmill-parser-ts/src/lib.rs index 56d645edf4..d68b2eeb6e 100644 --- a/backend/parsers/windmill-parser-ts/src/lib.rs +++ b/backend/parsers/windmill-parser-ts/src/lib.rs @@ -1,5 +1,3 @@ -use convert_case::{Case, Casing}; -use regex::Regex; /* * Author: Ruben Fiszel * Copyright: Windmill Labs, Inc 2022 @@ -11,18 +9,21 @@ use regex::Regex; use serde_json::Value; use std::collections::HashSet; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; -use windmill_parser::{json_to_typ, Arg, MainArgSignature, ObjectProperty, OneOfVariant, Typ}; +use windmill_parser::{ + json_to_typ, to_snake_case, Arg, MainArgSignature, ObjectProperty, OneOfVariant, Typ, +}; use swc_common::{sync::Lrc, FileName, SourceMap, SourceMapper, Span, Spanned}; use swc_ecma_ast::{ - ArrayLit, AssignPat, BigInt, BindingIdent, Bool, Decl, ExportDecl, Expr, FnDecl, Ident, Lit, - MemberExpr, MemberProp, ModuleDecl, ModuleItem, Number, ObjectLit, ObjectPat, Param, Pat, Str, - TsArrayType, TsEntityName, TsKeywordType, TsKeywordTypeKind, TsLit, TsLitType, TsOptionalType, - TsParenthesizedType, TsPropertySignature, TsType, TsTypeAnn, TsTypeElement, TsTypeLit, - TsTypeRef, TsUnionOrIntersectionType, TsUnionType, + ArrayLit, AssignPat, BigInt, BindingIdent, Bool, Decl, ExportDecl, Expr, FnDecl, Ident, + IdentName, Lit, MemberExpr, MemberProp, ModuleDecl, ModuleItem, Number, ObjectLit, ObjectPat, + Param, Pat, Str, TsArrayType, TsEntityName, TsKeywordType, TsKeywordTypeKind, TsLit, TsLitType, + TsOptionalType, TsParenthesizedType, TsPropertySignature, TsType, TsTypeAnn, TsTypeElement, + TsTypeLit, TsTypeRef, TsUnionOrIntersectionType, TsUnionType, }; -use swc_ecma_parser::{lexer::Lexer, EsConfig, Parser, StringInput, Syntax, TsConfig}; +use swc_ecma_parser::{lexer::Lexer, EsSyntax, Parser, StringInput, Syntax, TsSyntax}; +use regex::Regex; #[cfg(target_arch = "wasm32")] use wasm_bindgen::prelude::*; @@ -47,9 +48,9 @@ impl Visit for ImportsFinder { pub fn parse_expr_for_imports(code: &str) -> anyhow::Result> { let cm: Lrc = Default::default(); - let fm = cm.new_source_file(FileName::Custom("main.d.ts".into()), code.into()); + let fm = cm.new_source_file(FileName::Custom("main.d.ts".into()).into(), code.into()); let lexer = Lexer::new( - Syntax::Typescript(TsConfig::default()), + Syntax::Typescript(TsSyntax::default()), // EsVersion defaults to es5 Default::default(), StringInput::from(&*fm), @@ -68,7 +69,7 @@ pub fn parse_expr_for_imports(code: &str) -> anyhow::Result> { })?; let mut visitor = ImportsFinder { imports: HashSet::new() }; - swc_ecma_visit::visit_module(&mut visitor, &expr); + visitor.visit_module(&expr); Ok(visitor.imports.into_iter().collect()) } @@ -86,7 +87,7 @@ impl Visit for OutputFinder { c.visit_with(self); } match m { - MemberExpr { obj, prop: MemberProp::Ident(Ident { sym, .. }), .. } => { + MemberExpr { obj, prop: MemberProp::Ident(IdentName { sym, .. }), .. } => { match *obj.to_owned() { Expr::Ident(Ident { sym: sym_i, .. }) => { self.idents.insert((sym_i.to_string(), sym.to_string())); @@ -101,10 +102,10 @@ impl Visit for OutputFinder { pub fn parse_expr_for_ids(code: &str) -> anyhow::Result> { let cm: Lrc = Default::default(); - let fm = cm.new_source_file(FileName::Custom("main.ts".into()), code.into()); + let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.into()); let lexer = Lexer::new( // We want to parse ecmascript - Syntax::Es(EsConfig { jsx: false, ..Default::default() }), + Syntax::Es(EsSyntax { jsx: false, ..Default::default() }), // EsVersion defaults to es5 Default::default(), StringInput::from(&*fm), @@ -123,7 +124,7 @@ pub fn parse_expr_for_ids(code: &str) -> anyhow::Result> { })?; let mut visitor = OutputFinder { idents: HashSet::new() }; - swc_ecma_visit::visit_module(&mut visitor, &expr); + visitor.visit_module(&expr); Ok(visitor.idents.into_iter().collect()) } @@ -134,10 +135,10 @@ pub fn parse_deno_signature( main_override: Option, ) -> anyhow::Result { let cm: Lrc = Default::default(); - let fm = cm.new_source_file(FileName::Custom("main.ts".into()), code.into()); + let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.into()); let lexer = Lexer::new( // We want to parse ecmascript - Syntax::Typescript(TsConfig::default()), + Syntax::Typescript(TsSyntax::default()), // EsVersion defaults to es5 Default::default(), StringInput::from(&*fm), @@ -158,6 +159,14 @@ pub fn parse_deno_signature( })? .body; + let has_preprocessor = ast.iter().any(|x| match x { + ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl { + decl: Decl::Fn(FnDecl { ident: Ident { sym, .. }, .. }), + .. + })) => &sym.to_string() == "preprocessor", + _ => false, + }); + let main_name = main_override.unwrap_or("main".to_string()); let params = ast.into_iter().find_map(|x| match x { ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl { @@ -177,6 +186,7 @@ pub fn parse_deno_signature( .map(|x| parse_param(x, &cm, skip_dflt, &mut c)) .collect::>>()?, no_main_func: Some(false), + has_preprocessor: Some(has_preprocessor), }; Ok(r) } else { @@ -185,6 +195,7 @@ pub fn parse_deno_signature( star_kwargs: false, args: vec![], no_main_func: Some(true), + has_preprocessor: Some(has_preprocessor), }) } } @@ -294,7 +305,6 @@ fn binding_ident_to_arg(BindingIdent { id, type_ann }: &BindingIdent) -> (String } lazy_static::lazy_static! { - static ref RE_SNK_CASE: Regex = Regex::new(r"_(\d)").unwrap(); static ref IMPORTS_VERSION: Regex = Regex::new(r"^((?:\@[^\/\@]+\/[^\/\@]+)|(?:[^\/\@]+))(?:\@(?:[^\/]+))?(.*)$").unwrap(); } @@ -320,13 +330,6 @@ pub fn remove_pinned_imports(code: &str) -> anyhow::Result { Ok(content) } -fn to_snake_case(s: &str) -> String { - let r = s.to_case(Case::Snake); - - // s_3 => s3 - RE_SNK_CASE.replace_all(&r, "$1").to_string() -} - fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) { match ts_type { TsType::TsKeywordType(t) => ( diff --git a/backend/parsers/windmill-parser-wasm/Cargo.toml b/backend/parsers/windmill-parser-wasm/Cargo.toml index a42672e7af..2513ece67b 100644 --- a/backend/parsers/windmill-parser-wasm/Cargo.toml +++ b/backend/parsers/windmill-parser-wasm/Cargo.toml @@ -12,17 +12,33 @@ path = "./src/lib.rs" [dev-dependencies] wasm-bindgen-test.workspace = true +windmill-parser-ts.workspace = true +windmill-parser-bash.workspace = true + +[features] +default = [] +go-parser = [ "dep:windmill-parser-go"] +bash-parser = [ "dep:windmill-parser-bash"] +sql-parser = [ "dep:windmill-parser-sql"] +py-parser = [ "dep:windmill-parser-py"] +ts-parser = [ "dep:windmill-parser-ts"] +php-parser = [ "dep:windmill-parser-php"] +rust-parser = [ "dep:windmill-parser-rust"] +graphql-parser = [ "dep:windmill-parser-graphql"] +ansible-parser = [ "dep:windmill-parser-yaml"] [dependencies] anyhow.workspace = true windmill-parser.workspace = true -windmill-parser-go.workspace = true -windmill-parser-bash.workspace = true -windmill-parser-sql.workspace = true -windmill-parser-py.workspace = true -windmill-parser-ts.workspace = true -windmill-parser-php.workspace = true -windmill-parser-graphql.workspace = true +windmill-parser-go = { workspace = true, optional = true } +windmill-parser-bash = { workspace = true, optional = true } +windmill-parser-sql = { workspace = true, optional = true } +windmill-parser-py = { workspace = true, optional = true } +windmill-parser-ts = { workspace = true, optional = true } +windmill-parser-php = { workspace = true, optional = true } +windmill-parser-graphql = { workspace = true, optional = true } +windmill-parser-rust = { workspace = true, optional = true } +windmill-parser-yaml = { 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/README_DEV.md b/backend/parsers/windmill-parser-wasm/README_DEV.md new file mode 100644 index 0000000000..ff3f866f4e --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/README_DEV.md @@ -0,0 +1,25 @@ +### Windmill parser wasm + +How to build + +``` +wasm-pack build --release --target web +``` + +#### Prerequisite + +Install wasm-pack + +``` +cargo install wasm-pack +``` + +#### To use it on a dev environment + +Go to frontend and run: + +``` +npm install ../backend/parsers/windmill-parser-wasm/pkg +``` + +Make sure to not reset the package.json before commiting diff --git a/backend/parsers/windmill-parser-wasm/build-pkgs-mac.sh b/backend/parsers/windmill-parser-wasm/build-pkgs-mac.sh new file mode 100755 index 0000000000..7803fe22f0 --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/build-pkgs-mac.sh @@ -0,0 +1,50 @@ +#!/bin/bash +set -eou pipefail + +# full pkg +OUT_DIR="pkg" +wasm-pack build --release --target web --out-dir $OUT_DIR --all-features \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort + +# bun and deno +OUT_DIR="pkg-ts" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "ts-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-ts"/' $OUT_DIR/package.json + +# sql languages, graphql and bash/powershell, since they all use regex +OUT_DIR="pkg-regex" +wasm-pack build --release --target web --out-dir $OUT_DIR \ + --features "sql-parser,graphql-parser,bash-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-regex"/' $OUT_DIR/package.json + +# python +OUT_DIR="pkg-py" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "py-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-py"/' $OUT_DIR/package.json + +# go +OUT_DIR="pkg-go" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "go-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-go"/' $OUT_DIR/package.json + +# php +OUT_DIR="pkg-php" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "php-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-php"/' $OUT_DIR/package.json + +# rust +OUT_DIR="pkg-rust" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "rust-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-rust"/' $OUT_DIR/package.json + +# ansible +OUT_DIR="pkg-yaml" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "ansible-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-yaml"/' $OUT_DIR/package.json diff --git a/backend/parsers/windmill-parser-wasm/build-pkgs.sh b/backend/parsers/windmill-parser-wasm/build-pkgs.sh new file mode 100755 index 0000000000..66dafe3ccc --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/build-pkgs.sh @@ -0,0 +1,50 @@ +#!/bin/bash +set -eou pipefail + +# full pkg +OUT_DIR="pkg" +wasm-pack build --release --target web --out-dir $OUT_DIR --all-features \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort + +# bun and deno +OUT_DIR="pkg-ts" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "ts-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-ts"/' $OUT_DIR/package.json + +# sql languages, graphql and bash/powershell, since they all use regex +OUT_DIR="pkg-regex" +wasm-pack build --release --target web --out-dir $OUT_DIR \ + --features "sql-parser,graphql-parser,bash-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-regex"/' $OUT_DIR/package.json + +# python +OUT_DIR="pkg-py" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "py-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-py"/' $OUT_DIR/package.json + +# go +OUT_DIR="pkg-go" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "go-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-go"/' $OUT_DIR/package.json + +# php +OUT_DIR="pkg-php" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "php-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-php"/' $OUT_DIR/package.json + +# rust +OUT_DIR="pkg-rust" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "rust-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-rust"/' $OUT_DIR/package.json + +# ansible +OUT_DIR="pkg-yaml" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "ansible-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-yaml"/' $OUT_DIR/package.json diff --git a/backend/parsers/windmill-parser-wasm/build.sh b/backend/parsers/windmill-parser-wasm/build.sh index 044f92d93b..b872e2c912 100755 --- a/backend/parsers/windmill-parser-wasm/build.sh +++ b/backend/parsers/windmill-parser-wasm/build.sh @@ -1,4 +1,4 @@ #!/bin/bash set -eou pipefail -deno task wasmbuild --out ../../../cli/wasm/ -p windmill-parser-wasm +deno task wasmbuild --out ../../../cli/wasm/ -p windmill-parser-wasm --all-features diff --git a/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.d.ts b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.d.ts new file mode 100644 index 0000000000..10824a1c62 --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.d.ts @@ -0,0 +1,126 @@ +// deno-lint-ignore-file +// deno-fmt-ignore-file + +export interface InstantiateResult { + instance: WebAssembly.Instance; + exports: { + parse_deno: typeof parse_deno; + parse_outputs: typeof parse_outputs; + parse_ts_imports: typeof parse_ts_imports; + parse_bash: typeof parse_bash; + parse_powershell: typeof parse_powershell; + parse_go: typeof parse_go; + parse_python: typeof parse_python; + parse_sql: typeof parse_sql; + parse_mysql: typeof parse_mysql; + parse_bigquery: typeof parse_bigquery; + parse_snowflake: typeof parse_snowflake; + parse_mssql: typeof parse_mssql; + parse_db_resource: typeof parse_db_resource; + parse_graphql: typeof parse_graphql; + parse_php: typeof parse_php; + parse_rust: typeof parse_rust + }; +} + +/** Gets if the Wasm module has been instantiated. */ +export function isInstantiated(): boolean; + +/** Options for instantiating a Wasm instance. */ +export interface InstantiateOptions { + /** Optional url to the Wasm file to instantiate. */ + url?: URL; + /** Callback to decompress the raw Wasm file bytes before instantiating. */ + decompress?: (bytes: Uint8Array) => Uint8Array; +} + +/** Instantiates an instance of the Wasm module returning its functions. +* @remarks It is safe to call this multiple times and once successfully +* loaded it will always return a reference to the same object. */ +export function instantiate(opts?: InstantiateOptions): Promise; + +/** Instantiates an instance of the Wasm module along with its exports. + * @remarks It is safe to call this multiple times and once successfully + * loaded it will always return a reference to the same object. */ +export function instantiateWithInstance(opts?: InstantiateOptions): Promise; + +/** +* @param {string} code +* @returns {string} +*/ +export function parse_deno(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_outputs(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_ts_imports(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_bash(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_powershell(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_go(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_python(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_sql(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_mysql(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_bigquery(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_snowflake(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_mssql(code: string): string; +/** +* @param {string} code +* @returns {string | undefined} +*/ +export function parse_db_resource(code: string): string | undefined; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_graphql(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_php(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_rust(code: string): string; diff --git a/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.js b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.js new file mode 100644 index 0000000000..ea2404efeb --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.js @@ -0,0 +1,1166 @@ +// @generated file from wasmbuild -- do not edit +// @ts-nocheck: generated +// deno-lint-ignore-file +// deno-fmt-ignore-file +/// + +// source-hash: d36b5583d8f6223c130a246a8713b8621d55b990 +let wasm; + +const heap = new Array(128).fill(undefined); + +heap.push(undefined, null, true, false); + +function getObject(idx) { + return heap[idx]; +} + +let WASM_VECTOR_LEN = 0; + +let cachedUint8Memory0 = null; + +function getUint8Memory0() { + if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { + cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8Memory0; +} + +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; + getUint8Memory0().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 = getUint8Memory0(); + + 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 = getUint8Memory0().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; +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +let cachedInt32Memory0 = null; + +function getInt32Memory0() { + if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { + cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32Memory0; +} + +let heap_next = heap.length; + +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +let cachedFloat64Memory0 = null; + +function getFloat64Memory0() { + if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { + cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); + } + return cachedFloat64Memory0; +} + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +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(getUint8Memory0().subarray(ptr, ptr + len)); +} + +let cachedBigInt64Memory0 = null; + +function getBigInt64Memory0() { + if ( + cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0 + ) { + cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer); + } + return cachedBigInt64Memory0; +} + +function debugString(val) { + // primitive types + const type = typeof val; + if (type == "number" || type == "boolean" || val == null) { + return `${val}`; + } + if (type == "string") { + return `"${val}"`; + } + if (type == "symbol") { + const description = val.description; + if (description == null) { + return "Symbol"; + } else { + return `Symbol(${description})`; + } + } + if (type == "function") { + const name = val.name; + if (typeof name == "string" && name.length > 0) { + return `Function(${name})`; + } else { + return "Function"; + } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = "["; + if (length > 0) { + debug += debugString(val[0]); + } + for (let i = 1; i < length; i++) { + debug += ", " + debugString(val[i]); + } + debug += "]"; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == "Object") { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return "Object(" + JSON.stringify(val) + ")"; + } catch (_) { + return "Object"; + } + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; +} +/** + * @param {string} code + * @returns {string} + */ +export function parse_deno(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_deno(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_outputs(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_outputs(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_ts_imports(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_ts_imports(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_bash(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_bash(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_powershell(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_powershell(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_go(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_go(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_python(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_python(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_sql(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_sql(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_mysql(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_mysql(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_bigquery(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_bigquery(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_snowflake(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_snowflake(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_mssql(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_mssql(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string | undefined} + */ +export function parse_db_resource(code) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_db_resource(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + let v2; + if (r0 !== 0) { + v2 = getStringFromWasm0(r0, r1).slice(); + wasm.__wbindgen_free(r0, r1 * 1, 1); + } + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_graphql(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_graphql(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_php(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_php(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_rust(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_rust(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } +} + +const imports = { + __wbindgen_placeholder__: { + __wbindgen_string_get: function (arg0, arg1) { + const obj = getObject(arg1); + const ret = typeof obj === "string" ? obj : undefined; + var ptr1 = isLikeNone(ret) + ? 0 + : passStringToWasm0( + ret, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + var len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, + __wbindgen_object_drop_ref: function (arg0) { + takeObject(arg0); + }, + __wbindgen_boolean_get: function (arg0) { + const v = getObject(arg0); + const ret = typeof v === "boolean" ? (v ? 1 : 0) : 2; + return ret; + }, + __wbindgen_is_bigint: function (arg0) { + const ret = typeof (getObject(arg0)) === "bigint"; + return ret; + }, + __wbindgen_number_get: function (arg0, arg1) { + const obj = getObject(arg1); + const ret = typeof obj === "number" ? obj : undefined; + getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret; + getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + }, + __wbindgen_is_object: function (arg0) { + const val = getObject(arg0); + const ret = typeof val === "object" && val !== null; + return ret; + }, + __wbindgen_in: function (arg0, arg1) { + const ret = getObject(arg0) in getObject(arg1); + return ret; + }, + __wbindgen_bigint_from_i64: function (arg0) { + const ret = arg0; + return addHeapObject(ret); + }, + __wbindgen_jsval_eq: function (arg0, arg1) { + const ret = getObject(arg0) === getObject(arg1); + return ret; + }, + __wbindgen_bigint_from_u64: function (arg0) { + const ret = BigInt.asUintN(64, arg0); + return addHeapObject(ret); + }, + __wbindgen_error_new: function (arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }, + __wbg_eval_c227cc6614cd76e5: function (arg0, arg1) { + const ret = eval(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }, + __wbindgen_jsval_loose_eq: function (arg0, arg1) { + const ret = getObject(arg0) == getObject(arg1); + return ret; + }, + __wbg_get_bd8e338fbd5f5cc8: function (arg0, arg1) { + const ret = getObject(arg0)[arg1 >>> 0]; + return addHeapObject(ret); + }, + __wbg_length_cd7af8117672b8b8: function (arg0) { + const ret = getObject(arg0).length; + return ret; + }, + __wbindgen_is_function: function (arg0) { + const ret = typeof (getObject(arg0)) === "function"; + return ret; + }, + __wbg_next_40fc327bfc8770e6: function (arg0) { + const ret = getObject(arg0).next; + return addHeapObject(ret); + }, + __wbg_next_196c84450b364254: function () { + return handleError(function (arg0) { + const ret = getObject(arg0).next(); + return addHeapObject(ret); + }, arguments); + }, + __wbg_done_298b57d23c0fc80c: function (arg0) { + const ret = getObject(arg0).done; + return ret; + }, + __wbg_value_d93c65011f51a456: function (arg0) { + const ret = getObject(arg0).value; + return addHeapObject(ret); + }, + __wbg_iterator_2cee6dadfd956dfa: function () { + const ret = Symbol.iterator; + return addHeapObject(ret); + }, + __wbg_get_e3c254076557e348: function () { + return handleError(function (arg0, arg1) { + const ret = Reflect.get(getObject(arg0), getObject(arg1)); + return addHeapObject(ret); + }, arguments); + }, + __wbg_call_27c0f87801dedf93: function () { + return handleError(function (arg0, arg1) { + const ret = getObject(arg0).call(getObject(arg1)); + return addHeapObject(ret); + }, arguments); + }, + __wbg_isArray_2ab64d95e09ea0ae: function (arg0) { + const ret = Array.isArray(getObject(arg0)); + return ret; + }, + __wbg_instanceof_ArrayBuffer_836825be07d4c9d2: function (arg0) { + let result; + try { + result = getObject(arg0) instanceof ArrayBuffer; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_Map_87917e0a7aaf4012: function (arg0) { + let result; + try { + result = getObject(arg0) instanceof Map; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_isSafeInteger_f7b04ef02296c4d2: function (arg0) { + const ret = Number.isSafeInteger(getObject(arg0)); + return ret; + }, + __wbg_entries_95cc2c823b285a09: function (arg0) { + const ret = Object.entries(getObject(arg0)); + return addHeapObject(ret); + }, + __wbg_buffer_12d079cc21e14bdb: function (arg0) { + const ret = getObject(arg0).buffer; + return addHeapObject(ret); + }, + __wbg_new_63b92bc8671ed464: function (arg0) { + const ret = new Uint8Array(getObject(arg0)); + return addHeapObject(ret); + }, + __wbg_set_a47bac70306a19a7: function (arg0, arg1, arg2) { + getObject(arg0).set(getObject(arg1), arg2 >>> 0); + }, + __wbg_length_c20a40f15020d68a: function (arg0) { + const ret = getObject(arg0).length; + return ret; + }, + __wbg_instanceof_Uint8Array_2b3bbecd033d19f6: function (arg0) { + let result; + try { + result = getObject(arg0) instanceof Uint8Array; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbindgen_bigint_get_as_i64: function (arg0, arg1) { + const v = getObject(arg1); + const ret = typeof v === "bigint" ? v : undefined; + getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret; + getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + }, + __wbindgen_debug_string: function (arg0, arg1) { + const ret = debugString(getObject(arg1)); + const ptr1 = passStringToWasm0( + ret, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, + __wbindgen_throw: function (arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }, + __wbindgen_memory: function () { + const ret = wasm.memory; + return addHeapObject(ret); + }, + }, +}; + +class WasmBuildLoader { + #options; + #lastLoadPromise; + #instantiated; + + constructor(options) { + this.#options = options; + } + + get instance() { + return this.#instantiated?.instance; + } + + get module() { + return this.#instantiated?.module; + } + + load( + url, + decompress, + ) { + if (this.#instantiated) { + return Promise.resolve(this.#instantiated); + } else if (this.#lastLoadPromise == null) { + this.#lastLoadPromise = (async () => { + try { + this.#instantiated = await this.#instantiate(url, decompress); + return this.#instantiated; + } finally { + this.#lastLoadPromise = undefined; + } + })(); + } + return this.#lastLoadPromise; + } + + async #instantiate(url, decompress) { + const imports = this.#options.imports; + if (this.#options.cache != null && url.protocol !== "file:") { + try { + const result = await this.#options.cache( + url, + decompress ?? ((bytes) => bytes), + ); + if (result instanceof URL) { + url = result; + decompress = undefined; // already decompressed + } else if (result != null) { + return WebAssembly.instantiate(result, imports); + } + } catch { + // ignore if caching ever fails (ex. when on deploy) + } + } + + const isFile = url.protocol === "file:"; + + // make file urls work in Node via dnt + const isNode = globalThis.process?.versions?.node != null; + if (isFile && typeof Deno !== "object") { + throw new Error( + "Loading local files are not supported in this environment", + ); + } + if (isNode && isFile) { + // the deno global will be shimmed by dnt + const wasmCode = await Deno.readFile(url); + return WebAssembly.instantiate( + decompress ? decompress(wasmCode) : wasmCode, + imports, + ); + } + + switch (url.protocol) { + case "file:": + case "https:": + case "http:": { + const wasmResponse = await fetchWithRetries(url); + if (decompress) { + const wasmCode = new Uint8Array(await wasmResponse.arrayBuffer()); + return WebAssembly.instantiate(decompress(wasmCode), imports); + } + if ( + isFile || + wasmResponse.headers.get("content-type")?.toLowerCase() + .startsWith("application/wasm") + ) { + return WebAssembly.instantiateStreaming(wasmResponse, imports); + } else { + return WebAssembly.instantiate( + await wasmResponse.arrayBuffer(), + imports, + ); + } + } + default: + throw new Error(`Unsupported protocol: ${url.protocol}`); + } + } +} +const isNodeOrDeno = typeof Deno === "object" || + (typeof process !== "undefined" && process.versions != null && + process.versions.node != null); + +const loader = new WasmBuildLoader({ + imports, + cache: isNodeOrDeno ? cacheToLocalDir : undefined, +}); + +export async function instantiate(opts) { + return (await instantiateWithInstance(opts)).exports; +} + +export async function instantiateWithInstance(opts) { + const { instance } = await loader.load( + opts?.url ?? new URL("windmill_parser_wasm_bg.wasm", import.meta.url), + opts?.decompress, + ); + wasm = wasm ?? instance.exports; + cachedInt32Memory0 = cachedInt32Memory0 ?? new Int32Array(wasm.memory.buffer); + cachedUint8Memory0 = cachedUint8Memory0 ?? new Uint8Array(wasm.memory.buffer); + return { + instance, + exports: getWasmInstanceExports(), + }; +} + +function getWasmInstanceExports() { + return { + parse_deno, + parse_outputs, + parse_ts_imports, + parse_bash, + parse_powershell, + parse_go, + parse_python, + parse_sql, + parse_mysql, + parse_bigquery, + parse_snowflake, + parse_mssql, + parse_db_resource, + parse_graphql, + parse_php, + parse_rust, + }; +} + +export function isInstantiated() { + return loader.instance != null; +} +export async function cacheToLocalDir(url, decompress) { + const localPath = await getUrlLocalPath(url); + if (localPath == null) { + return undefined; + } + if (!await exists(localPath)) { + const fileBytes = decompress(new Uint8Array(await getUrlBytes(url))); + try { + await Deno.writeFile(localPath, fileBytes); + } catch { + // ignore and return the wasm bytes + return fileBytes; + } + } + return toFileUrl(localPath); +} +async function getUrlLocalPath(url) { + try { + const dataDirPath = await getInitializedLocalDataDirPath(); + const hash = await getUrlHash(url); + return `${dataDirPath}/${hash}.wasm`; + } catch { + return undefined; + } +} +async function getInitializedLocalDataDirPath() { + const dataDir = localDataDir(); + if (dataDir == null) { + throw new Error(`Could not find local data directory.`); + } + const dirPath = `${dataDir}/deno-wasmbuild`; + await ensureDir(dirPath); + return dirPath; +} +async function exists(filePath) { + try { + await Deno.lstat(filePath); + return true; + } catch (error) { + if (error instanceof Deno.errors.NotFound) { + return false; + } + throw error; + } +} +async function ensureDir(dir) { + try { + const fileInfo = await Deno.lstat(dir); + if (!fileInfo.isDirectory) { + throw new Error(`Path was not a directory '${dir}'`); + } + } catch (err) { + if (err instanceof Deno.errors.NotFound) { + // if dir not exists. then create it. + await Deno.mkdir(dir, { recursive: true }); + return; + } + throw err; + } +} +async function getUrlHash(url) { + // Taken from MDN: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest + const hashBuffer = await crypto.subtle.digest( + "SHA-256", + new TextEncoder().encode(url.href), + ); + // convert buffer to byte array + const hashArray = Array.from(new Uint8Array(hashBuffer)); + // convert bytes to hex string + const hashHex = hashArray + .map((b) => b.toString(16).padStart(2, "0")) + .join(""); + return hashHex; +} +async function getUrlBytes(url) { + const response = await fetchWithRetries(url); + return await response.arrayBuffer(); +} +// the below is extracted from deno_std/path +const WHITESPACE_ENCODINGS = { + "\u0009": "%09", + "\u000A": "%0A", + "\u000B": "%0B", + "\u000C": "%0C", + "\u000D": "%0D", + "\u0020": "%20", +}; +function encodeWhitespace(string) { + return string.replaceAll(/[\s]/g, (c) => { + return WHITESPACE_ENCODINGS[c] ?? c; + }); +} +function toFileUrl(path) { + return Deno.build.os === "windows" + ? windowsToFileUrl(path) + : posixToFileUrl(path); +} +function posixToFileUrl(path) { + const url = new URL("file:///"); + url.pathname = encodeWhitespace( + path.replace(/%/g, "%25").replace(/\\/g, "%5C"), + ); + return url; +} +function windowsToFileUrl(path) { + const [, hostname, pathname] = path.match( + /^(?:[/\\]{2}([^/\\]+)(?=[/\\](?:[^/\\]|$)))?(.*)/, + ); + const url = new URL("file:///"); + url.pathname = encodeWhitespace(pathname.replace(/%/g, "%25")); + if (hostname != null && hostname != "localhost") { + url.hostname = hostname; + if (!url.hostname) { + throw new TypeError("Invalid hostname."); + } + } + return url; +} +export async function fetchWithRetries(url, maxRetries = 5) { + let sleepMs = 250; + let iterationCount = 0; + while (true) { + iterationCount++; + try { + const res = await fetch(url); + if (res.ok || iterationCount > maxRetries) { + return res; + } + } catch (err) { + if (iterationCount > maxRetries) { + throw err; + } + } + console.warn(`Failed fetching. Retrying in ${sleepMs}ms...`); + await new Promise((resolve) => setTimeout(resolve, sleepMs)); + sleepMs = Math.min(sleepMs * 2, 10000); + } +} +// MIT License - Copyright (c) justjavac. +// https://github.com/justjavac/deno_dirs/blob/e8c001bbef558f08fd486d444af391729b0b8068/data_local_dir/mod.ts +function localDataDir() { + switch (Deno.build.os) { + case "linux": { + const xdg = Deno.env.get("XDG_DATA_HOME"); + if (xdg) { + return xdg; + } + const home = Deno.env.get("HOME"); + if (home) { + return `${home}/.local/share`; + } + break; + } + case "darwin": { + const home = Deno.env.get("HOME"); + if (home) { + return `${home}/Library/Application Support`; + } + break; + } + case "windows": + return Deno.env.get("LOCALAPPDATA") ?? undefined; + } + return undefined; +} diff --git a/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm_bg.wasm b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm_bg.wasm new file mode 100644 index 0000000000..de163879c8 Binary files /dev/null and b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm_bg.wasm differ diff --git a/backend/parsers/windmill-parser-wasm/pkg/package.json b/backend/parsers/windmill-parser-wasm/pkg/package.json index 0c70400479..e63340cf07 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/package.json +++ b/backend/parsers/windmill-parser-wasm/pkg/package.json @@ -3,7 +3,7 @@ "collaborators": [ "Ruben Fiszel " ], - "version": "1.367.2", + "version": "1.385.0", "files": [ "windmill_parser_wasm_bg.wasm", "windmill_parser_wasm.js", diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.d.ts b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.d.ts index 30e4bc2f54..439090ee9a 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.d.ts +++ b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.d.ts @@ -75,6 +75,11 @@ export function parse_graphql(code: string): string; * @returns {string} */ export function parse_php(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_rust(code: string): string; export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; @@ -95,6 +100,7 @@ export interface InitOutput { readonly parse_db_resource: (a: number, b: number, c: number) => void; readonly parse_graphql: (a: number, b: number, c: number) => void; readonly parse_php: (a: number, b: number, c: number) => void; + readonly parse_rust: (a: number, b: number, c: number) => void; readonly __wbindgen_malloc: (a: number, b: number) => number; readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; readonly __wbindgen_add_to_stack_pointer: (a: number) => number; @@ -107,18 +113,18 @@ export type SyncInitInput = BufferSource | WebAssembly.Module; * Instantiates the given `module`, which can either be bytes or * a precompiled `WebAssembly.Module`. * -* @param {SyncInitInput} module +* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated. * * @returns {InitOutput} */ -export function initSync(module: SyncInitInput): InitOutput; +export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput; /** * If `module_or_path` is {RequestInfo} or {URL}, makes a request and * for everything else, calls `WebAssembly.instantiate` directly. * -* @param {InitInput | Promise} module_or_path +* @param {{ module_or_path: InitInput | Promise }} module_or_path - Passing `InitInput` directly is deprecated. * * @returns {Promise} */ -export default function __wbg_init (module_or_path?: InitInput | Promise): Promise; +export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise } | InitInput | Promise): Promise; diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js index a945347d31..ae0865a76c 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js +++ b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js @@ -22,13 +22,13 @@ function takeObject(idx) { let WASM_VECTOR_LEN = 0; -let cachedUint8Memory0 = null; +let cachedUint8ArrayMemory0 = null; -function getUint8Memory0() { - if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { - cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); } - return cachedUint8Memory0; + return cachedUint8ArrayMemory0; } const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); @@ -51,7 +51,7 @@ function passStringToWasm0(arg, malloc, realloc) { if (realloc === undefined) { const buf = cachedTextEncoder.encode(arg); const ptr = malloc(buf.length, 1) >>> 0; - getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); WASM_VECTOR_LEN = buf.length; return ptr; } @@ -59,7 +59,7 @@ function passStringToWasm0(arg, malloc, realloc) { let len = arg.length; let ptr = malloc(len, 1) >>> 0; - const mem = getUint8Memory0(); + const mem = getUint8ArrayMemory0(); let offset = 0; @@ -74,7 +74,7 @@ function passStringToWasm0(arg, malloc, realloc) { arg = arg.slice(offset); } ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; - const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); const ret = encodeString(arg, view); offset += ret.written; @@ -89,22 +89,13 @@ function isLikeNone(x) { return x === undefined || x === null; } -let cachedInt32Memory0 = null; +let cachedDataViewMemory0 = null; -function getInt32Memory0() { - if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { - cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); +function getDataViewMemory0() { + if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) { + cachedDataViewMemory0 = new DataView(wasm.memory.buffer); } - return cachedInt32Memory0; -} - -let cachedFloat64Memory0 = null; - -function getFloat64Memory0() { - if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { - cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); - } - return cachedFloat64Memory0; + return cachedDataViewMemory0; } function addHeapObject(obj) { @@ -122,16 +113,7 @@ if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; function getStringFromWasm0(ptr, len) { ptr = ptr >>> 0; - return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); -} - -let cachedBigInt64Memory0 = null; - -function getBigInt64Memory0() { - if (cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0) { - cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer); - } - return cachedBigInt64Memory0; + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); } function debugString(val) { @@ -210,8 +192,8 @@ export function parse_deno(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_deno(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -233,8 +215,8 @@ export function parse_outputs(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_outputs(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -256,8 +238,8 @@ export function parse_ts_imports(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_ts_imports(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -279,8 +261,8 @@ export function parse_bash(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_bash(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -302,8 +284,8 @@ export function parse_powershell(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_powershell(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -325,8 +307,8 @@ export function parse_go(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_go(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -348,8 +330,8 @@ export function parse_python(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_python(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -371,8 +353,8 @@ export function parse_sql(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_sql(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -394,8 +376,8 @@ export function parse_mysql(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_mysql(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -417,8 +399,8 @@ export function parse_bigquery(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_bigquery(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -440,8 +422,8 @@ export function parse_snowflake(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_snowflake(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -463,8 +445,8 @@ export function parse_mssql(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_mssql(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -484,8 +466,8 @@ export function parse_db_resource(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_db_resource(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); let v2; if (r0 !== 0) { v2 = getStringFromWasm0(r0, r1).slice(); @@ -509,8 +491,8 @@ export function parse_graphql(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_graphql(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -532,8 +514,8 @@ export function parse_php(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_php(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -585,7 +567,7 @@ async function __wbg_load(module, imports) { function __wbg_get_imports() { const imports = {}; imports.wbg = {}; - imports.wbg.__wbg_eval_aa725d466edcea2c = function(arg0, arg1) { + imports.wbg.__wbg_eval_204ec87eadeaef4a = function(arg0, arg1) { const ret = eval(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }; @@ -597,8 +579,8 @@ function __wbg_get_imports() { const ret = typeof(obj) === 'string' ? obj : undefined; var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); }; imports.wbg.__wbindgen_boolean_get = function(arg0) { const v = getObject(arg0); @@ -612,8 +594,8 @@ function __wbg_get_imports() { imports.wbg.__wbindgen_number_get = function(arg0, arg1) { const obj = getObject(arg1); const ret = typeof(obj) === 'number' ? obj : undefined; - getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret; - getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true); }; imports.wbg.__wbindgen_is_object = function(arg0) { const val = getObject(arg0); @@ -644,11 +626,11 @@ function __wbg_get_imports() { const ret = getObject(arg0) == getObject(arg1); return ret; }; - imports.wbg.__wbg_get_bd8e338fbd5f5cc8 = function(arg0, arg1) { + imports.wbg.__wbg_get_3baa728f9d58d3f6 = function(arg0, arg1) { const ret = getObject(arg0)[arg1 >>> 0]; return addHeapObject(ret); }; - imports.wbg.__wbg_length_cd7af8117672b8b8 = function(arg0) { + imports.wbg.__wbg_length_ae22078168b726f5 = function(arg0) { const ret = getObject(arg0).length; return ret; }; @@ -656,39 +638,39 @@ function __wbg_get_imports() { const ret = typeof(getObject(arg0)) === 'function'; return ret; }; - imports.wbg.__wbg_next_40fc327bfc8770e6 = function(arg0) { + imports.wbg.__wbg_next_de3e9db4440638b2 = function(arg0) { const ret = getObject(arg0).next; return addHeapObject(ret); }; - imports.wbg.__wbg_next_196c84450b364254 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_next_f9cb570345655b9a = function() { return handleError(function (arg0) { const ret = getObject(arg0).next(); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_done_298b57d23c0fc80c = function(arg0) { + imports.wbg.__wbg_done_bfda7aa8f252b39f = function(arg0) { const ret = getObject(arg0).done; return ret; }; - imports.wbg.__wbg_value_d93c65011f51a456 = function(arg0) { + imports.wbg.__wbg_value_6d39332ab4788d86 = function(arg0) { const ret = getObject(arg0).value; return addHeapObject(ret); }; - imports.wbg.__wbg_iterator_2cee6dadfd956dfa = function() { + imports.wbg.__wbg_iterator_888179a48810a9fe = function() { const ret = Symbol.iterator; return addHeapObject(ret); }; - imports.wbg.__wbg_get_e3c254076557e348 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_get_224d16597dbbfd96 = function() { return handleError(function (arg0, arg1) { const ret = Reflect.get(getObject(arg0), getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_call_27c0f87801dedf93 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_call_1084a111329e68ce = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).call(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_isArray_2ab64d95e09ea0ae = function(arg0) { + imports.wbg.__wbg_isArray_8364a5371e9737d8 = function(arg0) { const ret = Array.isArray(getObject(arg0)); return ret; }; - imports.wbg.__wbg_instanceof_ArrayBuffer_836825be07d4c9d2 = function(arg0) { + imports.wbg.__wbg_instanceof_ArrayBuffer_61dfc3198373c902 = function(arg0) { let result; try { result = getObject(arg0) instanceof ArrayBuffer; @@ -698,7 +680,7 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_instanceof_Map_87917e0a7aaf4012 = function(arg0) { + imports.wbg.__wbg_instanceof_Map_763ce0e95960d55e = function(arg0) { let result; try { result = getObject(arg0) instanceof Map; @@ -708,30 +690,30 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_isSafeInteger_f7b04ef02296c4d2 = function(arg0) { + imports.wbg.__wbg_isSafeInteger_7f1ed56200d90674 = function(arg0) { const ret = Number.isSafeInteger(getObject(arg0)); return ret; }; - imports.wbg.__wbg_entries_95cc2c823b285a09 = function(arg0) { + imports.wbg.__wbg_entries_7a0e06255456ebcd = function(arg0) { const ret = Object.entries(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_buffer_12d079cc21e14bdb = function(arg0) { + imports.wbg.__wbg_buffer_b7b08af79b0b0974 = function(arg0) { const ret = getObject(arg0).buffer; return addHeapObject(ret); }; - imports.wbg.__wbg_new_63b92bc8671ed464 = function(arg0) { + imports.wbg.__wbg_new_ea1883e1e5e86686 = function(arg0) { const ret = new Uint8Array(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_set_a47bac70306a19a7 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_set_d1e79e2388520f18 = function(arg0, arg1, arg2) { getObject(arg0).set(getObject(arg1), arg2 >>> 0); }; - imports.wbg.__wbg_length_c20a40f15020d68a = function(arg0) { + imports.wbg.__wbg_length_8339fcf5d8ecd12e = function(arg0) { const ret = getObject(arg0).length; return ret; }; - imports.wbg.__wbg_instanceof_Uint8Array_2b3bbecd033d19f6 = function(arg0) { + imports.wbg.__wbg_instanceof_Uint8Array_247a91427532499e = function(arg0) { let result; try { result = getObject(arg0) instanceof Uint8Array; @@ -744,15 +726,15 @@ function __wbg_get_imports() { imports.wbg.__wbindgen_bigint_get_as_i64 = function(arg0, arg1) { const v = getObject(arg1); const ret = typeof(v) === 'bigint' ? v : undefined; - getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret; - getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + getDataViewMemory0().setBigInt64(arg0 + 8 * 1, isLikeNone(ret) ? BigInt(0) : ret, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true); }; imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { const ret = debugString(getObject(arg1)); const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); }; imports.wbg.__wbindgen_throw = function(arg0, arg1) { throw new Error(getStringFromWasm0(arg0, arg1)); @@ -765,17 +747,16 @@ function __wbg_get_imports() { return imports; } -function __wbg_init_memory(imports, maybe_memory) { +function __wbg_init_memory(imports, memory) { } function __wbg_finalize_init(instance, module) { wasm = instance.exports; __wbg_init.__wbindgen_wasm_module = module; - cachedBigInt64Memory0 = null; - cachedFloat64Memory0 = null; - cachedInt32Memory0 = null; - cachedUint8Memory0 = null; + cachedDataViewMemory0 = null; + cachedUint8ArrayMemory0 = null; + return wasm; @@ -784,6 +765,12 @@ function __wbg_finalize_init(instance, module) { function initSync(module) { if (wasm !== undefined) return wasm; + + if (typeof module !== 'undefined' && Object.getPrototypeOf(module) === Object.prototype) + ({module} = module) + else + console.warn('using deprecated parameters for `initSync()`; pass a single object instead') + const imports = __wbg_get_imports(); __wbg_init_memory(imports); @@ -797,24 +784,30 @@ function initSync(module) { return __wbg_finalize_init(instance, module); } -async function __wbg_init(input) { +async function __wbg_init(module_or_path) { if (wasm !== undefined) return wasm; - if (typeof input === 'undefined') { - input = new URL('windmill_parser_wasm_bg.wasm', import.meta.url); + + if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype) + ({module_or_path} = module_or_path) + else + console.warn('using deprecated parameters for the initialization function; pass a single object instead') + + if (typeof module_or_path === 'undefined') { + module_or_path = new URL('windmill_parser_wasm_bg.wasm', import.meta.url); } const imports = __wbg_get_imports(); - if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { - input = fetch(input); + if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) { + module_or_path = fetch(module_or_path); } __wbg_init_memory(imports); - const { instance, module } = await __wbg_load(await input, imports); + const { instance, module } = await __wbg_load(await module_or_path, imports); return __wbg_finalize_init(instance, module); } -export { initSync } +export { initSync }; export default __wbg_init; diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm index eb64263b45..501033c565 100644 Binary files a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm and b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm differ diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm.d.ts b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm.d.ts index 1fdcb8941c..5e6938f873 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm.d.ts +++ b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm.d.ts @@ -16,6 +16,7 @@ export function parse_mssql(a: number, b: number, c: number): void; export function parse_db_resource(a: number, b: number, c: number): void; export function parse_graphql(a: number, b: number, c: number): void; export function parse_php(a: number, b: number, c: number): void; +export function parse_rust(a: number, b: number, c: number): void; export function __wbindgen_malloc(a: number, b: number): number; export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number; export function __wbindgen_add_to_stack_pointer(a: number): number; diff --git a/backend/parsers/windmill-parser-wasm/publish-pkgs.sh b/backend/parsers/windmill-parser-wasm/publish-pkgs.sh new file mode 100755 index 0000000000..c2f2c0d7ad --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/publish-pkgs.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -eou pipefail +cd "$(dirname "${BASH_SOURCE[0]}")" + +args=${1:-} + +pushd "pkg-ts" && npm publish ${args} +popd + +pushd "pkg-regex" && npm publish ${args} +popd + +pushd "pkg-py" && npm publish ${args} +popd + +pushd "pkg-go" && npm publish ${args} +popd + +pushd "pkg-php" && npm publish ${args} +popd + +pushd "pkg-rust" && npm publish ${args} +popd + +pushd "pkg-yaml" && npm publish ${args} +popd diff --git a/backend/parsers/windmill-parser-wasm/src/lib.rs b/backend/parsers/windmill-parser-wasm/src/lib.rs index 5218357656..a5dd03ad91 100644 --- a/backend/parsers/windmill-parser-wasm/src/lib.rs +++ b/backend/parsers/windmill-parser-wasm/src/lib.rs @@ -1,8 +1,12 @@ +#[cfg(feature = "ts-parser")] use serde_json::json; +#[allow(unused_imports)] use wasm_bindgen::prelude::*; use windmill_parser::MainArgSignature; +#[cfg(feature = "ts-parser")] use windmill_parser_ts::{parse_expr_for_ids, parse_expr_for_imports}; +#[allow(dead_code)] fn wrap_sig(r: anyhow::Result) -> String { if let Ok(r) = r { return serde_json::to_string(&r).unwrap(); @@ -11,11 +15,17 @@ fn wrap_sig(r: anyhow::Result) -> String { } } +#[cfg(feature = "ts-parser")] #[wasm_bindgen] -pub fn parse_deno(code: &str) -> String { - wrap_sig(windmill_parser_ts::parse_deno_signature(code, false, None)) +pub fn parse_deno(code: &str, main_override: Option) -> String { + wrap_sig(windmill_parser_ts::parse_deno_signature( + code, + false, + main_override, + )) } +#[cfg(feature = "ts-parser")] #[wasm_bindgen] pub fn parse_outputs(code: &str) -> String { let parsed = parse_expr_for_ids(code); @@ -27,6 +37,7 @@ pub fn parse_outputs(code: &str) -> String { return serde_json::to_string(&r).unwrap(); } +#[cfg(feature = "ts-parser")] #[wasm_bindgen] pub fn parse_ts_imports(code: &str) -> String { let parsed = parse_expr_for_imports(code); @@ -38,62 +49,89 @@ pub fn parse_ts_imports(code: &str) -> String { return serde_json::to_string(&r).unwrap(); } +#[cfg(feature = "bash-parser")] #[wasm_bindgen] pub fn parse_bash(code: &str) -> String { wrap_sig(windmill_parser_bash::parse_bash_sig(code)) } +#[cfg(feature = "bash-parser")] #[wasm_bindgen] pub fn parse_powershell(code: &str) -> String { wrap_sig(windmill_parser_bash::parse_powershell_sig(code)) } +#[cfg(feature = "go-parser")] #[wasm_bindgen] pub fn parse_go(code: &str) -> String { wrap_sig(windmill_parser_go::parse_go_sig(code)) } +#[cfg(feature = "py-parser")] #[wasm_bindgen] -pub fn parse_python(code: &str) -> String { - wrap_sig(windmill_parser_py::parse_python_signature(code, None)) +pub fn parse_python(code: &str, main_override: Option) -> String { + wrap_sig(windmill_parser_py::parse_python_signature( + code, + main_override, + )) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_sql(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_pgsql_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_mysql(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_mysql_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_bigquery(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_bigquery_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_snowflake(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_snowflake_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_mssql(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_mssql_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_db_resource(code: &str) -> Option { windmill_parser_sql::parse_db_resource(code) } +#[cfg(feature = "graphql-parser")] #[wasm_bindgen] pub fn parse_graphql(code: &str) -> String { wrap_sig(windmill_parser_graphql::parse_graphql_sig(code)) } +#[cfg(feature = "php-parser")] #[wasm_bindgen] pub fn parse_php(code: &str) -> String { wrap_sig(windmill_parser_php::parse_php_signature(code, None)) } + +#[cfg(feature = "rust-parser")] +#[wasm_bindgen] +pub fn parse_rust(code: &str) -> String { + wrap_sig(windmill_parser_rust::parse_rust_signature(code)) +} + +#[cfg(feature = "ansible-parser")] +#[wasm_bindgen] +pub fn parse_ansible(code: &str) -> String { + wrap_sig(windmill_parser_yaml::parse_ansible_sig(code)) +} diff --git a/backend/parsers/windmill-parser-wasm/tests/wasm.rs b/backend/parsers/windmill-parser-wasm/tests/wasm.rs index 9f0feacbed..1c201ecd4e 100644 --- a/backend/parsers/windmill-parser-wasm/tests/wasm.rs +++ b/backend/parsers/windmill-parser-wasm/tests/wasm.rs @@ -139,7 +139,8 @@ export function main(test1?: string, test2: string = \"burkina\", oidx: None } ], - no_main_func: Some(false) + no_main_func: Some(false), + has_preprocessor: Some(false) } ); @@ -215,7 +216,8 @@ export function main(test2 = \"burkina\", oidx: None } ], - no_main_func: Some(false) + no_main_func: Some(false), + has_preprocessor: Some(false) } ); @@ -264,7 +266,8 @@ export function main(foo: FooBar, {a, b}: FooBar, {c, d}: FooBar = {a: \"foo\", oidx: None } ], - no_main_func: Some(false) + no_main_func: Some(false), + has_preprocessor: Some(false) } ); @@ -294,7 +297,8 @@ export function main(foo: (\"foo\" | \"bar\")[]) { has_default: false, oidx: None }], - no_main_func: Some(false) + no_main_func: Some(false), + has_preprocessor: Some(false) } ); @@ -434,6 +438,7 @@ Write-Output 'Testing...' } ], no_main_func: None, + has_preprocessor: None } ); diff --git a/backend/parsers/windmill-parser-yaml/Cargo.toml b/backend/parsers/windmill-parser-yaml/Cargo.toml new file mode 100644 index 0000000000..9bcfbea7a7 --- /dev/null +++ b/backend/parsers/windmill-parser-yaml/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "windmill-parser-yaml" +version.workspace = true +authors.workspace = true +edition.workspace = true + +[lib] +name = "windmill_parser_yaml" +path = "./src/lib.rs" + +[dependencies] +yaml-rust.workspace = true +windmill-parser.workspace = true +anyhow.workspace = true +serde_json.workspace = true diff --git a/backend/parsers/windmill-parser-yaml/src/lib.rs b/backend/parsers/windmill-parser-yaml/src/lib.rs new file mode 100644 index 0000000000..8c29c97b7e --- /dev/null +++ b/backend/parsers/windmill-parser-yaml/src/lib.rs @@ -0,0 +1,501 @@ +use anyhow::anyhow; +use serde_json::json; +use windmill_parser::{Arg, MainArgSignature, ObjectProperty, Typ}; +use yaml_rust::{Yaml, YamlEmitter, YamlLoader}; + +pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result { + let docs = YamlLoader::load_from_str(inner_content) + .map_err(|e| anyhow!("Failed to parse yaml: {}", e))?; + + if docs.len() < 2 { + return Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args: vec![], + no_main_func: None, + has_preprocessor: None, + }); + } + + let mut args = vec![]; + if let Yaml::Hash(doc) = &docs[0] { + for (key, value) in doc { + match key { + Yaml::String(key) if key == "extra_vars" => { + if let Yaml::Hash(v) = &value { + for (key, arg) in v { + if let Yaml::String(arg_name) = key { + // if not then it is a static resource or var, so skip + // it will be fetched by the worker + if let ArgTyp::Typ(typ) = parse_ansible_arg_typ(arg) { + let default = get_default_for_typ(&arg); + args.push(Arg { + name: arg_name.to_string(), + otyp: None, + typ, + has_default: default.is_some(), + default, + oidx: None, + }) + } + } + } + } + } + Yaml::String(key) if key == "inventory" => { + for inv in parse_inventories(value)? { + if inv.pinned_resource.is_some() { + continue; + } + args.push(Arg { + name: inv.name, + otyp: None, + typ: Typ::Resource(inv.resource_type.unwrap_or("Unknown".to_string())), + has_default: inv.default.is_some(), + default: inv.default.map(|v| json!(format!("$res:{}", v))), + oidx: None, + }) + } + } + _ => (), + } + } + } + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) +} + +fn get_default_for_typ(arg: &Yaml) -> Option { + if let Yaml::Hash(arg) = arg { + if let Some(def) = arg.get(&Yaml::String("default".to_string())) { + if let Some(Yaml::String(typ)) = arg.get(&Yaml::String("type".to_string())) { + if let Yaml::String(path) = def { + if typ.as_str() == "windmill_resource" { + return Some(serde_json::Value::String(format!("$res:{}", path))); + } + } + } + return Some(yaml_to_json(def)); + } + } + None +} + +enum ArgTyp { + Typ(Typ), + StaticVar(String), + StaticResource(String), +} + +fn parse_ansible_arg_typ(arg: &Yaml) -> ArgTyp { + if let Yaml::Hash(a) = arg { + if let Some(Yaml::String(typ)) = a.get(&Yaml::String("type".to_string())) { + if typ.as_str() == "windmill_variable" { + if let Some(Yaml::String(variable_path)) = + a.get(&Yaml::String("variable".to_string())) + { + return ArgTyp::StaticVar(variable_path.to_string()); + } + } + if typ.as_str() == "windmill_resource" { + if let Some(Yaml::String(resource_path)) = + a.get(&Yaml::String("resource".to_string())) + { + return ArgTyp::StaticResource(resource_path.to_string()); + } + } + } + } + ArgTyp::Typ(parse_ansible_typ(arg)) +} + +fn parse_ansible_typ(arg: &Yaml) -> Typ { + if let Yaml::Hash(arg) = arg { + if let Some(Yaml::String(typ)) = arg.get(&Yaml::String("type".to_string())) { + match typ.as_ref() { + "boolean" => Typ::Bool, + "integer" => Typ::Int, + "number" => Typ::Float, + "string" => { + if let Some(Yaml::String(fmt)) = arg.get(&Yaml::String("format".to_string())) { + match fmt.as_ref() { + "date-time" | "datetime" => Typ::Datetime, + "email" => Typ::Email, + _ => Typ::Str(None), + } + } else { + Typ::Str(None) + } + } + "object" => { + if let Some(Yaml::Hash(props)) = + arg.get(&Yaml::String("properties".to_string())) + { + let mut prop_vec = vec![]; + for (key, value) in props { + if let Yaml::String(key) = key { + prop_vec.push(ObjectProperty { + key: key.clone(), + typ: Box::new(parse_ansible_typ(value)), + }) + } + } + Typ::Object(prop_vec) + } else { + Typ::Object(vec![]) + } + } + "array" => { + if let Some(items) = arg.get(&Yaml::String("items".to_string())) { + Typ::List(Box::new(parse_ansible_typ(items))) + } else { + Typ::List(Box::new(Typ::Unknown)) + } + } + "windmill_resource" => { + if let Some(Yaml::String(res_name)) = + arg.get(&Yaml::String("resource_type".to_string())) + { + Typ::Resource(res_name.clone()) + } else { + Typ::Resource("".to_string()) + } + } + _ => Typ::Unknown, + } + } else { + Typ::Unknown + } + } else { + Typ::Unknown + } +} + +#[derive(Debug, Clone)] +pub struct AnsiblePlaybookOptions { + // There are a lot more options + // TODO: Add the options as customers require them + // Add it here and then on the executors cmd_options + pub verbosity: Option, + pub forks: Option, + pub timeout: Option, + pub flush_cache: Option<()>, + pub force_handlers: Option<()>, +} + +#[derive(Debug, Clone)] +pub enum ResourceOrVariablePath { + Resource(String), + Variable(String), +} + +#[derive(Debug, Clone)] +pub struct FileResource { + pub resource_path: ResourceOrVariablePath, + pub target_path: String, +} + +#[derive(Debug, Clone)] +pub struct AnsibleInventory { + pub default: Option, + pub name: String, + resource_type: Option, + pub pinned_resource: Option, +} +#[derive(Debug, Clone)] +pub struct AnsibleRequirements { + pub python_reqs: Vec, + pub collections: Option, + pub file_resources: Vec, + pub inventories: Vec, + pub vars: Vec<(String, String)>, + pub resources: Vec<(String, String)>, + pub options: AnsiblePlaybookOptions, +} + +fn parse_inventories(inventory_yaml: &Yaml) -> anyhow::Result> { + if let Yaml::Array(arr) = inventory_yaml { + let mut ret = vec![]; + for (i, inv) in arr.iter().enumerate() { + if let Yaml::Hash(inv) = inv { + let resource_type = inv + .get(&Yaml::String("resource_type".to_string())) + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + let windmill_path = inv + .get(&Yaml::String("default".to_string())) + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + let name = if i == 0 { + "inventory.ini".to_string() + } else { + format!("inventory-{}.ini", i) + }; + + let name = inv + .get(&Yaml::String("name".to_string())) + .and_then(|v| v.as_str()) + .unwrap_or(name.as_str()) + .to_string(); + + let pin = inv + .get(&Yaml::String("resource".to_string())) + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + ret.push(AnsibleInventory { + default: windmill_path, + name, + resource_type, + pinned_resource: pin, + }); + } + } + return Ok(ret); + } + return Err(anyhow!("Invalid inventory definition")); +} + +pub fn parse_ansible_reqs( + inner_content: &str, +) -> anyhow::Result<(String, Option, String)> { + let mut logs = String::new(); + let docs = YamlLoader::load_from_str(inner_content) + .map_err(|e| anyhow!("Failed to parse yaml: {}", e))?; + + if docs.len() < 2 { + return Ok((logs, None, inner_content.to_string())); + } + + let opts = AnsiblePlaybookOptions { + verbosity: None, + forks: None, + timeout: None, + flush_cache: None, + force_handlers: None, + }; + let mut ret = AnsibleRequirements { + python_reqs: vec![], + collections: None, + file_resources: vec![], + inventories: vec![], + vars: vec![], + resources: vec![], + options: opts, + }; + + if let Yaml::Hash(doc) = &docs[0] { + for (key, value) in doc { + match key { + Yaml::String(key) if key == "dependencies" => { + if let Yaml::Hash(deps) = value { + if let Some(galaxy_requirements) = + deps.get(&Yaml::String("galaxy".to_string())) + { + let mut out_str = String::new(); + let mut emitter = YamlEmitter::new(&mut out_str); + emitter.dump(galaxy_requirements)?; + ret.collections = Some(out_str); + } + if let Some(Yaml::Array(py_reqs)) = + deps.get(&Yaml::String("python".to_string())) + { + ret.python_reqs = py_reqs + .iter() + .map(|d| d.as_str().map(|s| s.to_string())) + .filter_map(|x| x) + .collect(); + } + } + } + Yaml::String(key) if key == "files" || key == "file_resources" => { + if let Yaml::Array(file_resources) = value { + let resources: anyhow::Result> = + file_resources.iter().map(parse_file_resource).collect(); + ret.file_resources.append(&mut resources?); + } + } + Yaml::String(key) if key == "extra_vars" => { + if let Yaml::Hash(v) = &value { + for (key, arg) in v { + if let Yaml::String(arg_name) = key { + match parse_ansible_arg_typ(arg) { + ArgTyp::StaticVar(p) => { + ret.vars + .push((arg_name.to_string(), format!("$var:{}", p))); + } + ArgTyp::StaticResource(p) => { + ret.resources + .push((arg_name.to_string(), format!("$res:{}", p))); + } + ArgTyp::Typ(_) => (), + } + } + } + } + } + Yaml::String(key) if key == "inventory" => { + ret.inventories = parse_inventories(value)?; + } + Yaml::String(key) if key == "options" => { + if let Yaml::Array(opts) = &value { + ret.options = parse_ansible_options(opts); + } + } + Yaml::String(key) => logs.push_str(&format!("\nUnknown field `{}`. Ignoring", key)), + _ => (), + } + } + } + let mut out_str = String::new(); + let mut emitter = YamlEmitter::new(&mut out_str); + + for i in 1..docs.len() { + emitter.dump(&docs[i])?; + } + Ok((logs, Some(ret), out_str)) +} + +fn parse_ansible_options(opts: &Vec) -> AnsiblePlaybookOptions { + let mut ret = AnsiblePlaybookOptions { + verbosity: None, + forks: None, + timeout: None, + flush_cache: None, + force_handlers: None, + }; + for opt in opts { + if let Yaml::String(o) = opt { + match o.as_str() { + "flush_cache" => { + ret.flush_cache = Some(()); + } + "force_handlers" => { + ret.force_handlers = Some(()); + } + s if count_consecutive_vs(s) > 0 => { + ret.verbosity = Some("v".repeat(count_consecutive_vs(s).min(6))); + } + _ => (), + } + } + if let Yaml::Hash(m) = opt { + if let Some((Yaml::String(name), value)) = m.iter().last() { + match name.as_str() { + "forks" => { + if let Yaml::Integer(count) = value { + ret.forks = Some(*count); + } + } + "timeout" => { + if let Yaml::Integer(timeout) = value { + ret.timeout = Some(*timeout); + } + } + "verbosity" => { + if let Yaml::String(verbosity) = value { + let c = count_consecutive_vs(verbosity); + if c > 0 && c <= 6 { + ret.verbosity = Some("v".repeat(c.min(6))); + } + } + } + _ => (), + } + } + } + } + + ret +} + +fn count_consecutive_vs(s: &str) -> usize { + let mut max_count = 0; + let mut current_count = 0; + + for c in s.chars() { + if c == 'v' { + current_count += 1; + if current_count == 6 { + return 6; // Stop early if we reach 6 + } + } else { + current_count = 0; // Reset count if the character is not 'v' + } + max_count = max_count.max(current_count); + } + + max_count +} + +fn parse_file_resource(yaml: &Yaml) -> anyhow::Result { + if let Yaml::Hash(f) = yaml { + if let Some(Yaml::String(resource_path)) = f.get(&Yaml::String("resource".to_string())) { + let target_path = f + .get(&Yaml::String("target".to_string())) + .and_then(|x| x.as_str()) + .map(|x| x.to_string()) + .ok_or(anyhow!( + "No `target` provided for file resource {}. Please input a target relative path for the ansible playbook to see this file.", + resource_path + ))?; + return Ok(FileResource { + resource_path: ResourceOrVariablePath::Resource(resource_path.clone()), + target_path, + }); + } + if let Some(Yaml::String(resource_path)) = f.get(&Yaml::String("variable".to_string())) { + let target_path = f + .get(&Yaml::String("target".to_string())) + .and_then(|x| x.as_str()) + .map(|x| x.to_string()) + .ok_or(anyhow!( + "No `target` provided for file resource {}. Please input a target relative path for the ansible playbook to see this file.", + resource_path + ))?; + return Ok(FileResource { + resource_path: ResourceOrVariablePath::Variable(resource_path.clone()), + target_path, + }); + } + return Err(anyhow!( + "File resource should have a `resource` field, linking to a text file resource" + )); + } + return Err(anyhow!("Invalid file resource: Should be a dictionary.")); +} + +fn yaml_to_json(yaml: &Yaml) -> serde_json::Value { + match yaml { + Yaml::Array(arr) => { + let json_array: Vec = arr.into_iter().map(yaml_to_json).collect(); + serde_json::Value::Array(json_array) + } + Yaml::Hash(hash) => { + let json_object = hash + .into_iter() + .map(|(k, v)| { + let key = match k { + Yaml::String(s) => s.clone(), + _ => k.as_str().unwrap_or("").to_string(), + }; + (key, yaml_to_json(v)) + }) + .collect(); + serde_json::Value::Object(json_object) + } + Yaml::String(s) => serde_json::Value::String(s.to_string()), + Yaml::Integer(i) => serde_json::Value::Number(i.clone().into()), + Yaml::Real(r) => serde_json::Value::Number(r.parse().unwrap_or(0.into())), + Yaml::Boolean(b) => serde_json::Value::Bool(*b), + Yaml::Null => serde_json::Value::Null, + _ => serde_json::Value::Null, + } +} diff --git a/backend/parsers/windmill-parser/Cargo.toml b/backend/parsers/windmill-parser/Cargo.toml index 9bf4ad5eba..7dc464a4b3 100644 --- a/backend/parsers/windmill-parser/Cargo.toml +++ b/backend/parsers/windmill-parser/Cargo.toml @@ -11,3 +11,4 @@ path = "./src/lib.rs" [dependencies] serde = { version = "1.0", features = ["derive"] } serde_json.workspace = true +convert_case.workspace = true diff --git a/backend/parsers/windmill-parser/src/lib.rs b/backend/parsers/windmill-parser/src/lib.rs index a739dc53d2..6f793d0cc7 100644 --- a/backend/parsers/windmill-parser/src/lib.rs +++ b/backend/parsers/windmill-parser/src/lib.rs @@ -6,6 +6,7 @@ * LICENSE-AGPL for a copy of the license. */ +use convert_case::{Boundary, Case, Casing}; use serde::Serialize; use serde_json::Value; @@ -15,6 +16,7 @@ pub struct MainArgSignature { pub star_kwargs: bool, pub args: Vec, pub no_main_func: Option, + pub has_preprocessor: Option, } #[derive(Serialize, Clone, Debug, PartialEq)] @@ -75,3 +77,91 @@ pub fn json_to_typ(js: &Value) -> Typ { _ => Typ::Unknown, } } + +pub fn to_snake_case(s: &str) -> String { + s.with_boundaries(&Boundary::defaults()) + .without_boundaries(&Boundary::letter_digit()) + .to_case(Case::Snake) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_snake_case() { + assert_eq!("s3", to_snake_case("S3")); + assert_eq!("s3", to_snake_case("s3")); + assert_eq!("s_3", to_snake_case("S_3")); + assert_eq!("type_name_here", to_snake_case("typeNameHere")); + } + + #[test] + fn test_empty_string() { + assert_eq!(to_snake_case(""), ""); + } + + #[test] + fn test_single_char_lowercase() { + assert_eq!(to_snake_case("a"), "a"); + } + + #[test] + fn test_single_char_uppercase() { + assert_eq!(to_snake_case("A"), "a"); + } + + #[test] + fn test_all_uppercase() { + assert_eq!(to_snake_case("TEST"), "test"); + } + + #[test] + fn test_all_lowercase() { + assert_eq!(to_snake_case("test"), "test"); + } + + #[test] + fn test_mixed_case() { + assert_eq!(to_snake_case("testCase"), "test_case"); + } + + #[test] + fn test_mixed_case_with_numbers() { + assert_eq!(to_snake_case("testCase1"), "test_case1"); + assert_eq!(to_snake_case("Test123Case"), "test123_case"); + } + + #[test] + fn test_numbers_with_hyphen() { + assert_eq!(to_snake_case("test-3"), "test_3"); + } + + #[test] + fn test_string_with_spaces() { + assert_eq!(to_snake_case("This is a Test"), "this_is_a_test"); + } + + #[test] + fn test_snake_case_input() { + assert_eq!(to_snake_case("already_snake_case"), "already_snake_case"); + } + + #[test] + fn test_kebab_case_input() { + assert_eq!(to_snake_case("already-kebab-case"), "already_kebab_case"); + } + + #[test] + fn test_mixed_delimiters() { + assert_eq!( + to_snake_case("test-Case_with Spaces"), + "test_case_with_spaces" + ); + } + + #[test] + fn test_leading_and_trailing_spaces() { + assert_eq!(to_snake_case(" test case "), "test_case"); + } +} diff --git a/backend/plot.py b/backend/plot.py new file mode 100644 index 0000000000..2b02984a62 --- /dev/null +++ b/backend/plot.py @@ -0,0 +1,89 @@ +import json +import matplotlib.pyplot as plt + +# Function to load JSON data from a file +def load_json_data(filepath): + with open(filepath, 'r') as file: + data = json.load(file) + return data + +# Function to plot two arrays of subarrays with tuples (step_name, duration) +def plot_two_arrays_of_subarrays(arrays1, arrays2): + # Function to calculate sum of durations for each step + def calculate_sums(arrays): + steps = [step for step, _ in arrays[0]['timings']] # Extract steps from the first iteration + sums = {step: 0.0 for step in steps} # Initialize sums dictionary with step names + + # Sum up the durations for each step across all subarrays + for subarray in arrays: + for step_name, duration in subarray['timings']: + if step_name not in sums: + sums[step_name] = 0 + sums[step_name] += duration + + for step_name, duration in sums.items(): + sums[step_name] = duration / 1000000000 + + # Convert the sums dictionary to two lists (for plotting) + step_names = list(sums.keys()) + durations = list(sums.values()) + return step_names, durations + + # Calculate sums for both arrays of subarrays + step_names1, sums1 = calculate_sums(arrays1) + step_names2, sums2 = calculate_sums(arrays2) + + # Create two subplots, one on top of the other + fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 12)) + + # First plot (top) for the first array of subarrays + ax1.bar(step_names1, sums1, color='b') + ax1.set_title('Total Duration per Step - Main Loop') + ax1.set_xlabel('Step Name') + ax1.set_ylabel('Total Duration (s)') + ax1.grid(True, axis='y') + ax1.tick_params(axis='x', rotation=45) + + # Second plot (bottom) for the second array of subarrays + ax2.bar(step_names2, sums2, color='r') + ax2.set_title('Total Duration per Step - Result Processor') + ax2.set_xlabel('Step Name') + ax2.set_ylabel('Total Duration (s)') + ax2.grid(True, axis='y') + ax2.tick_params(axis='x', rotation=45) + + # Adjust layout so the plots don't overlap + plt.tight_layout() + + # Display the plot + plt.show() + +# Load arrays from the JSON files +main = load_json_data('/tmp/windmill/profiling_main.json') +result_processor = load_json_data('/tmp/windmill/profiling_result_processor.json') + +arrays1 = main['timings'] +arrays2 = result_processor['timings'] + +total_duration1 = main['total_duration']/1000 +total_duration2 = result_processor['total_duration']/1000 + +print(f"Total duration for main: {total_duration1}s") +print(f"Total duration for result processor: {total_duration2}s") + +iterations_total = sum(main['iter_durations']) / 1000000000 +iterations_total2 = sum(result_processor['iter_durations']) / 1000000000 + +print(f"Number of iterations: {len(main['iter_durations'])}") +print(f"Total iterations for main: {iterations_total}s") +print(f"Total iterations for result processor: {iterations_total2}s") + +# Calculate RPS +rps1 = len(main['iter_durations']) / total_duration1 +rps2 = len(result_processor['iter_durations']) / total_duration2 + +print(f"RPS for main: {rps1}") +print(f"RPS for result processor: {rps2}") + +# Plot the data +plot_two_arrays_of_subarrays(arrays1, arrays2) \ No newline at end of file diff --git a/backend/src/ee.rs b/backend/src/ee.rs index ef944b984b..91816cd1ba 100644 --- a/backend/src/ee.rs +++ b/backend/src/ee.rs @@ -1,16 +1,8 @@ -use anyhow::anyhow; -#[cfg(feature = "enterprise")] -use windmill_common::error::{Error, Result}; - -pub async fn set_license_key(_license_key: String) -> anyhow::Result<()> { +pub async fn set_license_key(_license_key: String) -> () { // Implementation is not open source - Err(anyhow!("License cannot be set in Windmill CE")) } #[cfg(feature = "enterprise")] -pub async fn verify_license_key() -> Result<()> { +pub async fn verify_license_key() -> () { // Implementation is not open source - Err(Error::InternalErr( - "License always invalid in Windmill CE".to_string(), - )) } diff --git a/backend/src/main.rs b/backend/src/main.rs index ebc7f6dc3b..11d12f9dab 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -7,8 +7,11 @@ */ use anyhow::Context; -use gethostname::gethostname; use git_version::git_version; +use monitor::{ + 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 std::{ @@ -20,10 +23,11 @@ use tokio::{ fs::{create_dir_all, DirBuilder, File}, io::AsyncReadExt, }; +use uuid::Uuid; use windmill_api::HTTP_CLIENT; #[cfg(feature = "enterprise")] -use windmill_common::ee::schedule_key_renewal; +use windmill_common::ee::{maybe_renew_license_key_on_start, LICENSE_KEY_ID, LICENSE_KEY_VALID}; use windmill_common::{ global_settings::{ @@ -34,11 +38,12 @@ use windmill_common::{ JWT_SECRET_SETTING, KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, NPM_CONFIG_REGISTRY_SETTING, OAUTH_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, + SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, SMTP_SETTING, TIMEOUT_WAIT_RESULT_SETTING, }, + scripts::ScriptLang, stats_ee::schedule_stats, - utils::{rd_string, Mode}, - worker::{reload_custom_tags_setting, WORKER_GROUP}, + utils::{hostname, rd_string, Mode}, + worker::{reload_custom_tags_setting, HUB_CACHE_DIR, TMP_DIR, WORKER_GROUP}, DB, METRICS_ENABLED, }; @@ -61,8 +66,8 @@ 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, BUN_DEPSTAR_CACHE_DIR, DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS, DENO_CACHE_DIR_NPM, - GO_BIN_CACHE_DIR, GO_CACHE_DIR, HUB_CACHE_DIR, LOCK_CACHE_DIR, PIP_CACHE_DIR, - POWERSHELL_CACHE_DIR, TAR_PIP_CACHE_DIR, TMP_LOGS_DIR, + GO_BIN_CACHE_DIR, GO_CACHE_DIR, LOCK_CACHE_DIR, PIP_CACHE_DIR, POWERSHELL_CACHE_DIR, + RUST_CACHE_DIR, TAR_PIP_CACHE_DIR, TMP_LOGS_DIR, UV_CACHE_DIR, }; use crate::monitor::{ @@ -72,7 +77,7 @@ use crate::monitor::{ reload_critical_error_channels_setting, reload_extra_pip_index_url_setting, reload_hub_base_url_setting, reload_job_default_timeout_setting, reload_jwt_secret_setting, reload_license_key, reload_npm_config_registry_setting, reload_pip_index_url_setting, - reload_retention_period_setting, reload_scim_token_setting, reload_server_config, + reload_retention_period_setting, reload_scim_token_setting, reload_smtp_config, reload_worker_config, }; @@ -87,9 +92,6 @@ const DEFAULT_SERVER_BIND_ADDR: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0); mod ee; mod monitor; -#[cfg(feature = "pg_embed")] -mod pg_embed; - #[inline(always)] fn create_and_run_current_thread_inner(future: F) -> R where @@ -113,7 +115,8 @@ where } pub fn main() -> anyhow::Result<()> { - deno_core::JsRuntime::init_platform(None); + #[cfg(feature = "deno_core")] + deno_core::JsRuntime::init_platform(None, false); create_and_run_current_thread_inner(windmill_main()) } @@ -132,9 +135,77 @@ async fn cache_hub_scripts(file_path: Option) -> anyhow::Result<()> { })?; create_dir_all(HUB_CACHE_DIR).await?; + create_dir_all(BUN_BUNDLE_CACHE_DIR).await?; for path in paths.values() { - get_hub_script_content_and_requirements(Some(path.to_string()), None).await?; + tracing::info!("Caching hub script at {path}"); + let res = get_hub_script_content_and_requirements(Some(path.to_string()), None).await?; + if res + .language + .as_ref() + .is_some_and(|x| x == &ScriptLang::Deno) + { + let job_dir = format!("{}/cache_init/{}", TMP_DIR, Uuid::new_v4()); + create_dir_all(&job_dir).await?; + let _ = windmill_worker::generate_deno_lock( + &Uuid::nil(), + &res.content, + &mut 0, + &mut None, + &job_dir, + None, + "global", + "global", + "", + &mut None, + ) + .await?; + tokio::fs::remove_dir_all(job_dir).await?; + } else if res.language.as_ref().is_some_and(|x| x == &ScriptLang::Bun) { + let job_id = Uuid::new_v4(); + let job_dir = format!("{}/cache_init/{}", TMP_DIR, job_id); + create_dir_all(&job_dir).await?; + if let Some(lockfile) = res.lockfile { + let _ = windmill_worker::prepare_job_dir(&lockfile, &job_dir).await?; + let envs = windmill_worker::get_common_bun_proc_envs(None).await; + let _ = windmill_worker::install_bun_lockfile( + &mut 0, + &mut None, + &job_id, + "admins", + None, + &job_dir, + "cache_init", + envs.clone(), + false, + &mut None, + ) + .await?; + + let _ = windmill_common::worker::write_file(&job_dir, "main.js", &res.content)?; + + if let Err(e) = windmill_worker::prebundle_bun_script( + &res.content, + Some(lockfile), + &path, + &job_id, + "admins", + None, + &job_dir, + "", + "cache_init", + "", + &mut None, + ) + .await + { + panic!("Error prebundling bun script: {e:#}"); + } + } else { + tracing::warn!("No lockfile found for bun script {path}, skipping..."); + } + tokio::fs::remove_dir_all(job_dir).await?; + } } Ok(()) } @@ -146,8 +217,10 @@ async fn windmill_main() -> anyhow::Result<()> { std::env::set_var("RUST_LOG", "info") } + let hostname = hostname(); + #[cfg(not(feature = "flamegraph"))] - windmill_common::tracing_init::initialize_tracing(); + let _guard = windmill_common::tracing_init::initialize_tracing(&hostname); #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] tracing::info!("jemalloc enabled"); @@ -211,7 +284,8 @@ async fn windmill_main() -> anyhow::Result<()> { tracing::info!("Binary is in 'indexer' mode"); #[cfg(not(feature = "tantivy"))] { - panic!("Indexer mode requires the tantivy feature flag"); + tracing::error!("Cannot start the indexer because tantivy is not included in this binary/image. Make sure you are using the EE image if you want to access the full text search features."); + panic!("Indexer mode requires compiling with the tantivy feature flag."); } #[cfg(feature = "tantivy")] Mode::Indexer @@ -234,7 +308,8 @@ async fn windmill_main() -> anyhow::Result<()> { Mode::Standalone }); - let num_workers = if mode == Mode::Server || mode == Mode::Indexer { + #[allow(unused_mut)] + let mut num_workers = if mode == Mode::Server || mode == Mode::Indexer { 0 } else { std::env::var("NUM_WORKERS") @@ -287,14 +362,6 @@ async fn windmill_main() -> anyhow::Result<()> { config }); - #[cfg(feature = "pg_embed")] - let _pg = { - let (db_url, pg) = pg_embed::start().await.expect("pg embed"); - tracing::info!("Use embedded pg: {db_url}"); - std::env::set_var("DATABASE_URL", db_url); - pg - }; - tracing::info!("Connecting to database..."); let db = windmill_common::connect_db(server_mode, indexer_mode).await?; tracing::info!("Database connected"); @@ -319,9 +386,18 @@ async fn windmill_main() -> anyhow::Result<()> { let is_agent = mode == Mode::Agent; if !is_agent { - // migration code to avoid break - windmill_api::migrate_db(&db).await?; + let skip_migration = std::env::var("SKIP_MIGRATION") + .map(|val| val == "true") + .unwrap_or(false); + + if !skip_migration { + // migration code to avoid break + windmill_api::migrate_db(&db).await?; + } else { + tracing::info!("SKIP_MIGRATION set, skipping db migration...") + } } + let (killpill_tx, mut killpill_rx) = tokio::sync::broadcast::channel::<()>(2); let mut monitor_killpill_rx = killpill_tx.subscribe(); let server_killpill_rx = killpill_tx.subscribe(); @@ -348,6 +424,50 @@ 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 { + tracing::error!("Failed to reload license key: {err:#}"); + } + let valid_key = *LICENSE_KEY_VALID.read().await; + if !valid_key && !server_mode { + panic!("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 num_workers > 0 { + let valid_key = *LICENSE_KEY_VALID.read().await; + if !valid_key { + tracing::warn!("License key invalid, setting num_workers to 0"); + num_workers = 0; + } + } + } + } + let worker_mode = num_workers > 0; if server_mode || worker_mode || indexer_mode { @@ -374,10 +494,21 @@ Windmill Community Edition {GIT_VERSION} initial_load(&db, killpill_tx.clone(), worker_mode, server_mode, is_agent).await; - monitor_db(&db, &base_internal_url, rsmq.clone(), server_mode, true).await; + monitor_db( + &db, + &base_internal_url, + rsmq.clone(), + server_mode, + worker_mode, + true, + killpill_tx.clone(), + ) + .await; monitor_pool(&db).await; + send_logs_to_object_store(&db, &hostname, &mode); + #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] if !worker_mode { monitor_mem().await; @@ -400,7 +531,7 @@ Windmill Community Edition {GIT_VERSION} #[cfg(feature = "tantivy")] let (index_reader, index_writer) = if should_index_jobs { - let (r, w) = windmill_indexer::indexer_ee::init_index().await?; + let (r, w) = windmill_indexer::indexer_ee::init_index(&db).await?; (Some(r), Some(w)) } else { (None, None) @@ -463,6 +594,7 @@ Windmill Community Edition {GIT_VERSION} base_internal_url.clone(), rsmq.clone(), mode.clone() == Mode::Agent, + hostname.clone(), ) .await?; tracing::info!("All workers exited."); @@ -471,8 +603,11 @@ Windmill Community Edition {GIT_VERSION} rx.recv().await?; } } - tracing::info!("Starting phase 2 of shutdown"); - killpill_phase2_tx.send(())?; + if killpill_phase2_tx.receiver_count() > 0 { + tracing::info!("Starting phase 2 of shutdown"); + killpill_phase2_tx.send(())?; + tracing::info!("Phase 2 of shutdown completed"); + } Ok(()) as anyhow::Result<()> }; @@ -487,13 +622,20 @@ Windmill Community Edition {GIT_VERSION} loop { tokio::select! { + biased; + _ = monitor_killpill_rx.recv() => { + tracing::info!("received killpill for monitor job"); + break; + }, _ = tokio::time::sleep(Duration::from_secs(30)) => { monitor_db( &db, &base_internal_url, rsmq.clone(), server_mode, - false + worker_mode, + false, + tx.clone(), ) .await; }, @@ -505,9 +647,7 @@ Windmill Community Edition {GIT_VERSION} "notify_config_change" => { match n.payload() { "server" if server_mode => { - tracing::info!("Server config change detected: {}", n.payload()); - - reload_server_config(&db).await; + 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()); @@ -538,7 +678,15 @@ Windmill Community Edition {GIT_VERSION} }, LICENSE_KEY_SETTING => { if let Err(e) = reload_license_key(&db).await { - tracing::error!(error = %e, "Could not reload license key setting"); + tracing::error!("Failed to reload license key: {e:#}"); + } + #[cfg(feature = "enterprise")] + if worker_mode { + let valid_key = *LICENSE_KEY_VALID.read().await; + if !valid_key { + tracing::error!("Invalid license key, exiting..."); + tx.send(()).expect("send"); + } } }, DEFAULT_TAGS_PER_WORKSPACE_SETTING => { @@ -551,6 +699,12 @@ Windmill Community Edition {GIT_VERSION} tracing::error!("Error loading default tag per workspace workspaces: {e:#}"); } } + SMTP_SETTING => { + reload_smtp_config(&db).await; + }, + TIMEOUT_WAIT_RESULT_SETTING => { + reload_timeout_wait_result_setting(&db).await + }, RETENTION_PERIOD_SECS_SETTING => { reload_retention_period_setting(&db).await }, @@ -641,22 +795,28 @@ Windmill Community Edition {GIT_VERSION} }, Err(e) => { tracing::error!(error = %e, "Could not receive notification, attempting to reconnect listener"); - listener = retry_listen_pg(&db).await; - continue; + tokio::select! { + biased; + _ = monitor_killpill_rx.recv() => { + tracing::info!("received killpill for monitor job"); + break; + }, + new_listener = retry_listen_pg(&db) => { + listener = new_listener; + continue; + } + } } }; - }, - _ = monitor_killpill_rx.recv() => { - println!("received killpill for monitor job"); - break; } } } }); if let Err(e) = h.await { - tracing::error!("Error waiting for monitor handle:{e:#}") + tracing::error!("Error waiting for monitor handle: {e:#}") } + tracing::info!("Monitor exited"); Ok(()) as anyhow::Result<()> }; @@ -672,14 +832,8 @@ Windmill Community Edition {GIT_VERSION} Ok(()) as anyhow::Result<()> }; - let instance_name = rd_string(8); - if mode == Mode::Server || mode == Mode::Standalone { - schedule_stats(instance_name, &db, &HTTP_CLIENT).await; - } - - #[cfg(feature = "enterprise")] - if mode == Mode::Server || mode == Mode::Standalone { - schedule_key_renewal(&HTTP_CLIENT, &db).await; + if server_mode { + schedule_stats(&db, &HTTP_CLIENT).await; } futures::try_join!( @@ -693,6 +847,8 @@ Windmill Community Edition {GIT_VERSION} } else { tracing::info!("Nothing to do, exiting."); } + send_current_log_file_to_object_store(&db, &hostname, &mode).await; + tracing::info!("Exiting connection pool"); tokio::select! { _ = db.close() => { @@ -764,6 +920,7 @@ pub async fn run_workers, agent_mode: bool, + hostname: String, ) -> anyhow::Result<()> { let mut killpill_rxs = vec![]; for _ in 0..num_workers { @@ -774,10 +931,6 @@ pub async fn run_workers (Option, Option) { + let log_dir = format!("{}/{}/", TMP_WINDMILL_LOGS_SERVICE, hostname); + let rd_dir = tokio::fs::read_dir(log_dir).await; + if let Ok(mut log_files) = rd_dir { + let mut highest_file: Option = None; + let mut second_highest_file: Option = None; + while let Ok(Some(file)) = log_files.next_entry().await { + let file_name = file + .file_name() + .to_str() + .map(|x| x.to_string()) + .unwrap_or_default(); + if file_name > highest_file.clone().unwrap_or_default() { + second_highest_file = highest_file; + highest_file = Some(file_name); + } + } + (highest_file, second_highest_file) + } else { + tracing::error!( + "Error reading log files: {TMP_WINDMILL_LOGS_SERVICE}, {:#?}", + rd_dir.unwrap_err() + ); + (None, None) + } +} + +fn get_worker_group(mode: &Mode) -> Option { + let worker_group = WORKER_GROUP.clone(); + if worker_group.is_empty() || mode == &Mode::Server || mode == &Mode::Indexer { + None + } else { + Some(worker_group) + } +} + +pub fn send_logs_to_object_store(db: &DB, hostname: &str, mode: &Mode) { + let db = db.clone(); + let hostname = hostname.to_string(); + let mode = mode.clone(); + let worker_group = get_worker_group(&mode); + tokio::spawn(async move { + let mut interval = tokio::time::interval(Duration::from_secs(10)); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + sleep_until_next_minute_start_plus_one_s().await; + loop { + interval.tick().await; + let (_, snd_highest_file) = find_two_highest_files(&hostname).await; + send_log_file_to_object_store( + &hostname, + &mode, + &worker_group, + &db, + snd_highest_file, + false, + ) + .await; + } + }); +} + +pub async fn send_current_log_file_to_object_store(db: &DB, 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; +} + +fn get_now_and_str() -> (NaiveDateTime, String) { + let ts = Utc::now().naive_utc(); + ( + ts, + ts.format(windmill_common::tracing_init::LOG_TIMESTAMP_FMT) + .to_string(), + ) +} + +async fn send_log_file_to_object_store( + hostname: &str, + mode: &Mode, + worker_group: &Option, + db: &Pool, + snd_highest_file: Option, + use_now: bool, +) { + if let Some(highest_file) = snd_highest_file { + //parse datetime frome file xxxx.yyyy-MM-dd-HH-mm + let (ts, ts_str) = if use_now { + get_now_and_str() + } else { + highest_file + .split(".") + .last() + .and_then(|x| { + NaiveDateTime::parse_from_str( + x, + windmill_common::tracing_init::LOG_TIMESTAMP_FMT, + ) + .ok() + .map(|y| (y, x.to_string())) + }) + .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; + + match exists { + Ok(Some(true)) => { + return; + } + Err(e) => { + tracing::error!("Error checking if log file exists: {:?}", e); + return; + } + _ => (), + } + + #[cfg(feature = "parquet")] + let s3_client = OBJECT_STORE_CACHE_SETTINGS.read().await.clone(); + #[cfg(feature = "parquet")] + if let Some(s3_client) = s3_client { + let path = std::path::Path::new(TMP_WINDMILL_LOGS_SERVICE) + .join(hostname) + .join(&highest_file); + + //read file as byte stream + let bytes = tokio::fs::read(&path).await; + if let Err(e) = bytes { + tracing::error!("Error reading log file: {:?}", e); + return; + } + let path = object_store::path::Path::from_url_path(format!( + "{}{hostname}/{highest_file}", + windmill_common::tracing_init::LOGS_SERVICE + )); + if let Err(e) = path { + tracing::error!("Error creating log file path: {:?}", e); + return; + } + if let Err(e) = s3_client.put(&path.unwrap(), bytes.unwrap().into()).await { + tracing::error!("Error sending logs to object store: {:?}", e); + } + } + + 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); + } + } +} + +fn read_log_counters(ts_str: String) -> (usize, usize) { + let counters = windmill_common::tracing_init::LOG_COUNTING_BY_MIN.read(); + let mut ok_lines = 0; + let mut err_lines = 0; + if let Ok(ref c) = counters { + let counter = c.get(&ts_str); + if let Some(counter) = counter { + ok_lines = counter.non_error_count; + err_lines = counter.error_count; + } else { + // println!("no counter found for {ts_str}"); + } + } else { + println!("Error reading log counters 2"); + } + (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; match value { @@ -468,6 +651,15 @@ pub async fn delete_expired_items(db: &DB) -> () { { tracing::error!("Error deleting custom concurrency key: {:?}", e); } + if let Err(e) = sqlx::query!( + "DELETE FROM log_file WHERE log_ts <= now() - ($1::bigint::text || ' s')::interval ", + job_retention_secs + ) + .execute(&mut *tx) + .await + { + tracing::error!("Error deleting log file: {:?}", e); + } } } Err(e) => { @@ -492,6 +684,15 @@ pub async fn reload_scim_token_setting(db: &DB) { .await; } +pub async fn reload_timeout_wait_result_setting(db: &DB) { + reload_option_setting_with_tracing( + db, + TIMEOUT_WAIT_RESULT_SETTING, + "TIMEOUT_WAIT_RESULT", + TIMEOUT_WAIT_RESULT.clone(), + ) + .await; +} pub async fn reload_saml_metadata_setting(db: &DB) { reload_option_setting_with_tracing( db, @@ -599,7 +800,9 @@ pub async fn reload_s3_cache_setting(db: &DB) { secret_key: None, endpoint: None, store_logs: None, + path_style: None, allow_http: None, + port: None, }) .await .ok(); @@ -635,8 +838,10 @@ pub async fn reload_request_size(db: &DB) { } } -pub async fn reload_license_key(db: &DB) -> error::Result<()> { - let q = load_value_from_global_settings(db, LICENSE_KEY_SETTING).await?; +pub async fn reload_license_key(db: &DB) -> anyhow::Result<()> { + let q = load_value_from_global_settings(db, LICENSE_KEY_SETTING) + .await + .map_err(|err| anyhow::anyhow!("Error reloading license key: {}", err.to_string()))?; let mut value = std::env::var("LICENSE_KEY") .ok() @@ -654,9 +859,7 @@ pub async fn reload_license_key(db: &DB) -> error::Result<()> { tracing::error!("Could not parse LICENSE_KEY found: {:#?}", &q); } }; - - set_license_key(value).await?; - + set_license_key(value).await; Ok(()) } @@ -795,7 +998,9 @@ pub async fn monitor_db( base_internal_url: &str, rsmq: Option, server_mode: bool, + _worker_mode: bool, initial_load: bool, + _killpill_tx: tokio::sync::broadcast::Sender<()>, ) { let zombie_jobs_f = async { if server_mode && !initial_load { @@ -816,15 +1021,14 @@ pub async fn monitor_db( let verify_license_key_f = async { #[cfg(feature = "enterprise")] - if let Err(e) = verify_license_key().await { - tracing::error!("Error verifying license key: {:?}", e); - let mut l = LICENSE_KEY_VALID.write().await; - *l = false; - } else { - let is_valid = LICENSE_KEY_VALID.read().await.clone(); - if !is_valid { - let mut l = LICENSE_KEY_VALID.write().await; - *l = true; + if !initial_load { + verify_license_key().await; + if _worker_mode { + let valid_key = *LICENSE_KEY_VALID.read().await; + if !valid_key { + tracing::error!("Invalid license key, exiting..."); + _killpill_tx.send(()).expect("send"); + } } } }; @@ -835,92 +1039,105 @@ pub async fn monitor_db( } }; + let worker_groups_alerts_f = async { + #[cfg(feature = "enterprise")] + if server_mode && !initial_load { + worker_groups_alerts(&db).await; + } + }; + + let jobs_waiting_alerts_f = async { + #[cfg(feature = "enterprise")] + if server_mode { + 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); + } + } + }; + join!( expired_items_f, zombie_jobs_f, expose_queue_metrics_f, - verify_license_key_f + verify_license_key_f, + worker_groups_alerts_f, + jobs_waiting_alerts_f, + apply_autoscaling_f, ); } pub async fn expose_queue_metrics(db: &Pool) { - let tx = db.begin().await; - if let Ok(mut tx) = tx { - let last_check = sqlx::query_scalar!( + let last_check = sqlx::query_scalar!( "SELECT created_at FROM metrics WHERE id LIKE 'queue_count_%' ORDER BY created_at DESC LIMIT 1" ) .fetch_optional(db) .await .unwrap_or(Some(chrono::Utc::now())); - let metrics_enabled = METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed); - let save_metrics = last_check - .map(|last_check| chrono::Utc::now() - last_check > chrono::Duration::seconds(25)) - .unwrap_or(true); + let metrics_enabled = METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed); + let save_metrics = last_check + .map(|last_check| chrono::Utc::now() - last_check > chrono::Duration::seconds(25)) + .unwrap_or(true); - if metrics_enabled || save_metrics { - let queue_counts = sqlx::query!( - "SELECT tag, count(*) as count FROM queue WHERE - scheduled_for <= now() - ('3 seconds')::interval AND running = false - GROUP BY tag" - ) - .fetch_all(&mut *tx) - .await - .ok() - .unwrap_or_else(|| vec![]); + if metrics_enabled || save_metrics { + let queue_counts = windmill_common::queue::get_queue_counts(db).await; - for q in queue_counts { - let count = q.count.unwrap_or(0); - let tag = q.tag; - if metrics_enabled { - let metric = (*QUEUE_COUNT).with_label_values(&[&tag]); - metric.set(count as i64); - } + for q in queue_counts { + let count = q.1; + let tag = q.0; + if metrics_enabled { + let metric = (*QUEUE_COUNT).with_label_values(&[&tag]); + metric.set(count as i64); + } - // save queue_count and delay metrics per tag - if save_metrics { + // save queue_count and delay metrics per tag + if save_metrics { + sqlx::query!( + "INSERT INTO metrics (id, value) VALUES ($1, $2)", + format!("queue_count_{}", tag), + serde_json::json!(count) + ) + .execute(db) + .await + .ok(); + if count > 0 { sqlx::query!( - "INSERT INTO metrics (id, value) VALUES ($1, $2)", - format!("queue_count_{}", tag), - serde_json::json!(count) - ) - .execute(&mut *tx) - .await - .ok(); - if count > 0 { - sqlx::query!( "INSERT INTO metrics (id, value) VALUES ($1, to_jsonb((SELECT EXTRACT(EPOCH FROM now() - scheduled_for) FROM queue WHERE tag = $2 AND running = false AND scheduled_for <= now() - ('3 seconds')::interval - ORDER BY priority DESC NULLS LAST, scheduled_for, created_at LIMIT 1)))", + ORDER BY priority DESC NULLS LAST, scheduled_for LIMIT 1)))", format!("queue_delay_{}", tag), tag - ).execute(&mut *tx).await.ok(); - } + ).execute(db).await.ok(); } } } - - // clean queue metrics older than 14 days - sqlx::query!( - "DELETE FROM metrics WHERE id LIKE 'queue_%' AND created_at < NOW() - INTERVAL '14 day'" - ) - .execute(&mut *tx) - .await - .ok(); - - tx.commit().await.ok(); } + + // clean queue metrics older than 14 days + sqlx::query!( + "DELETE FROM metrics WHERE id LIKE 'queue_%' AND created_at < NOW() - INTERVAL '14 day'" + ) + .execute(db) + .await + .ok(); } -pub async fn reload_server_config(db: &Pool) { - let config = load_server_config(&db).await; - if let Err(e) = config { - tracing::error!("Error reloading server config: {:?}", e) +pub async fn reload_smtp_config(db: &Pool) { + let smtp_config = load_smtp_config(&db).await; + if let Err(e) = smtp_config { + tracing::error!("Error reloading smtp config: {:?}", e) } else { - let mut wc = SERVER_CONFIG.write().await; - tracing::info!("Reloading server config..."); - *wc = config.unwrap() + let mut wc = SMTP_CONFIG.write().await; + tracing::info!("Reloading smtp config..."); + *wc = smtp_config.unwrap() } } @@ -1037,7 +1254,7 @@ async fn handle_zombie_jobs ) { if *RESTART_ZOMBIE_JOBS { let restarted = sqlx::query!( - "UPDATE queue SET running = false, started_at = null, logs = logs || '\nRestarted job after not receiving job''s ping for too long the ' || now() || '\n\n' + "UPDATE queue SET running = false, started_at = null WHERE last_ping < now() - ($1 || ' seconds')::interval AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'singlescriptflow') AND same_worker = false RETURNING id, workspace_id, last_ping", *ZOMBIE_JOB_TIMEOUT, @@ -1050,13 +1267,25 @@ async fn handle_zombie_jobs if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) { QUEUE_ZOMBIE_RESTART_COUNT.inc_by(restarted.len() as _); } + let base_url = BASE_URL.read().await.clone(); for r in restarted { - tracing::error!( - "Zombie job detected, restarting it: {} {} {:?}", - r.id, - r.workspace_id, - r.last_ping + let last_ping = if let Some(x) = r.last_ping { + format!("last ping at {x}") + } else { + "no last ping".to_string() + }; + let url = format!("{}/run/{}?workspace={}", base_url, r.id, r.workspace_id,); + let error_message = format!( + "Zombie job {} on {} ({}) detected, restarting it, {}", + r.id, r.workspace_id, url, last_ping ); + + let _ = sqlx::query!(" + INSERT INTO job_logs (job_id, logs) VALUES ($1,'Restarted job after not receiving job''s ping for too long the ' || now() || '\n\n') + ON CONFLICT (job_id) DO UPDATE SET logs = job_logs.logs || '\nRestarted job after not receiving job''s ping for too long the ' || now() || '\n\n' WHERE job_logs.job_id = $1", r.id) + .execute(db).await; + tracing::error!(error_message); + report_critical_error(error_message, db.clone()).await; } } @@ -1084,6 +1313,8 @@ async fn handle_zombie_jobs // since the job is unrecoverable, the same worker queue should never be sent anything let (same_worker_tx_never_used, _same_worker_rx_never_used) = 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 label = if job.permissioned_as != format!("u/{}", job.created_by) @@ -1132,6 +1363,8 @@ async fn handle_zombie_jobs rsmq.clone(), worker_name, send_result_never_used, + #[cfg(feature = "benchmark")] + &mut windmill_common::bench::BenchmarkIter::new(), ) .await; } @@ -1154,16 +1387,19 @@ async fn handle_zombie_flows( for flow in flows { let status = flow.parse_flow_status(); - if status.is_some_and(|s| { - s.modules - .get(0) - .is_some_and(|x| matches!(x, FlowStatusModule::WaitingForPriorSteps { .. })) - }) { - tracing::error!( + if !flow.same_worker + && status.is_some_and(|s| { + s.modules + .get(0) + .is_some_and(|x| matches!(x, FlowStatusModule::WaitingForPriorSteps { .. })) + }) + { + let error_message = format!( "Zombie flow detected: {} in workspace {}. It hasn't started yet, restarting it.", - flow.id, - flow.workspace_id + flow.id, flow.workspace_id ); + tracing::error!(error_message); + report_critical_error(error_message, db.clone()).await; // if the flow hasn't started and is a zombie, we can simply restart it sqlx::query!( "UPDATE queue SET running = false, started_at = null WHERE id = $1 AND canceled = false", @@ -1183,6 +1419,7 @@ async fn handle_zombie_flows( format!("Flow {id} was cancelled because it") } ); + report_critical_error(reason.clone(), db.clone()).await; cancel_zombie_flow_job(db, flow, &rsmq, reason).await?; } } diff --git a/backend/src/pg_embed.rs b/backend/src/pg_embed.rs deleted file mode 100644 index ad5529dc02..0000000000 --- a/backend/src/pg_embed.rs +++ /dev/null @@ -1,46 +0,0 @@ -use pg_embed::pg_enums::PgAuthMethod; -use pg_embed::pg_fetch::PgFetchSettings; -use pg_embed::postgres::{PgEmbed, PgSettings}; -use std::path::PathBuf; -use std::time::Duration; - -pub async fn start() -> anyhow::Result<(String, PgEmbed)> { - let pg_settings = PgSettings { - database_dir: PathBuf::from("/tmp/db"), - port: 6543, - user: "postgres".to_string(), - password: "password".to_string(), - auth_method: PgAuthMethod::Plain, - persistent: false, - timeout: Some(Duration::from_secs(15)), - migration_dir: None, - }; - - let fetch_settings = PgFetchSettings { - version: pg_embed::pg_fetch::PostgresVersion("15.3.0"), - - ..Default::default() - }; - - tracing::info!( - "Fetch settings: {:?} {:?}", - fetch_settings.operating_system, - fetch_settings.architecture - ); - - let mut pg = PgEmbed::new(pg_settings, fetch_settings).await?; - - pg.setup().await.expect("pg setup"); - - pg.start_db().await.expect("pg start db"); - - //TODO: re-enable this to make it work - // if !pg.database_exists("windmill").await.expect("db exists") { - // pg.create_database("windmill") - // .await - // .expect("pg create database"); - // } - - let uri = pg.full_db_uri("windmill"); - Ok((uri, pg)) -} diff --git a/backend/tests/worker.rs b/backend/tests/worker.rs index 66c3ee06a7..a93c6eef1d 100644 --- a/backend/tests/worker.rs +++ b/backend/tests/worker.rs @@ -75,7 +75,9 @@ async fn initialize_tracing() { use std::sync::Once; static ONCE: Once = Once::new(); - ONCE.call_once(windmill_common::tracing_init::initialize_tracing); + ONCE.call_once(|| { + let _ = windmill_common::tracing_init::initialize_tracing("test"); + }); } /// it's important this is unique between tests as there is one prometheus registry and @@ -1113,6 +1115,7 @@ async fn test_deno_flow(db: Pool) { } .into(), stop_after_if: Default::default(), + stop_after_all_iters_if: Default::default(), summary: Default::default(), suspend: Default::default(), retry: None, @@ -1123,6 +1126,7 @@ async fn test_deno_flow(db: Pool) { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }, FlowModule { id: "b".to_string(), @@ -1152,6 +1156,7 @@ async fn test_deno_flow(db: Pool) { } .into(), stop_after_if: Default::default(), + stop_after_all_iters_if: Default::default(), summary: Default::default(), suspend: Default::default(), retry: None, @@ -1162,10 +1167,12 @@ async fn test_deno_flow(db: Pool) { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }], } .into(), stop_after_if: Default::default(), + stop_after_all_iters_if: Default::default(), summary: Default::default(), suspend: Default::default(), retry: None, @@ -1176,6 +1183,7 @@ async fn test_deno_flow(db: Pool) { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }, ], same_worker: false, @@ -1270,6 +1278,7 @@ async fn test_deno_flow_same_worker(db: Pool) { concurrency_time_window_s: None, }.into(), stop_after_if: Default::default(), + stop_after_all_iters_if: Default::default(), summary: Default::default(), suspend: Default::default(), retry: None, @@ -1280,6 +1289,7 @@ async fn test_deno_flow_same_worker(db: Pool) { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }, FlowModule { id: "b".to_string(), @@ -1319,6 +1329,7 @@ async fn test_deno_flow_same_worker(db: Pool) { concurrency_time_window_s: None, }.into(), stop_after_if: Default::default(), + stop_after_all_iters_if: Default::default(), summary: Default::default(), suspend: Default::default(), retry: None, @@ -1329,6 +1340,7 @@ async fn test_deno_flow_same_worker(db: Pool) { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }, FlowModule { id: "e".to_string(), @@ -1354,6 +1366,7 @@ async fn test_deno_flow_same_worker(db: Pool) { concurrency_time_window_s: None, }.into(), stop_after_if: Default::default(), + stop_after_all_iters_if: Default::default(), summary: Default::default(), suspend: Default::default(), retry: None, @@ -1364,11 +1377,12 @@ async fn test_deno_flow_same_worker(db: Pool) { priority: None, delete_after_use: None, continue_on_error: None, - + skip_if: None, }, ], }.into(), stop_after_if: Default::default(), + stop_after_all_iters_if: Default::default(), summary: Default::default(), suspend: Default::default(), retry: None, @@ -1379,6 +1393,7 @@ async fn test_deno_flow_same_worker(db: Pool) { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }, FlowModule { id: "c".to_string(), @@ -1411,6 +1426,7 @@ async fn test_deno_flow_same_worker(db: Pool) { concurrency_time_window_s: None, }.into(), stop_after_if: Default::default(), + stop_after_all_iters_if: Default::default(), summary: Default::default(), suspend: Default::default(), retry: None, @@ -1421,6 +1437,7 @@ async fn test_deno_flow_same_worker(db: Pool) { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }, ], same_worker: true, @@ -1733,6 +1750,41 @@ func main(derp string) (string, error) { assert_eq!(result, serde_json::json!("hello world")); } +#[sqlx::test(fixtures("base"))] +async fn test_rust_job(db: Pool) { + initialize_tracing().await; + let server = ApiServer::start(db.clone()).await; + let port = server.addr.port(); + + let content = r#" +fn main(world: String) -> Result { + println!("Which world to greet today?"); + Ok(format!("Hello {}!", world)) +} + "# + .to_owned(); + + let result = RunJob::from(JobPayload::Code(RawCode { + hash: None, + content, + path: None, + lock: None, + language: ScriptLang::Rust, + custom_concurrency_key: None, + concurrent_limit: None, + concurrency_time_window_s: None, + cache_ttl: None, + dedicated_worker: None, + })) + .arg("world", json!("Hyrule")) + .run_until_complete(&db, port) + .await + .json_result() + .unwrap(); + + assert_eq!(result, serde_json::json!("Hello Hyrule!")); +} + #[sqlx::test(fixtures("base"))] async fn test_bash_job(db: Pool) { initialize_tracing().await; @@ -1867,6 +1919,109 @@ def main(): assert_eq!(result, serde_json::json!("test-workspace")); } +#[sqlx::test(fixtures("base"))] +async fn test_bun_job_datetime(db: Pool) { + initialize_tracing().await; + let server = ApiServer::start(db.clone()).await; + let port = server.addr.port(); + + let content = r#" +export async function main(a: Date) { + return typeof a; +} + "# + .to_owned(); + + let result = RunJob::from(JobPayload::Code(RawCode { + hash: None, + content, + path: None, + lock: None, + language: ScriptLang::Bun, + custom_concurrency_key: None, + concurrent_limit: None, + concurrency_time_window_s: None, + cache_ttl: None, + dedicated_worker: None, + })) + .arg("a", json!("2024-09-24T10:00:00.000Z")) + .run_until_complete(&db, port) + .await + .json_result() + .unwrap(); + + assert_eq!(result, serde_json::json!("object")); +} + +#[sqlx::test(fixtures("base"))] +async fn test_deno_job_datetime(db: Pool) { + initialize_tracing().await; + let server = ApiServer::start(db.clone()).await; + let port = server.addr.port(); + + let content = r#" +export async function main(a: Date) { + return typeof a; +} + "# + .to_owned(); + + let result = RunJob::from(JobPayload::Code(RawCode { + hash: None, + content, + path: None, + lock: None, + language: ScriptLang::Deno, + custom_concurrency_key: None, + concurrent_limit: None, + concurrency_time_window_s: None, + cache_ttl: None, + dedicated_worker: None, + })) + .arg("a", json!("2024-09-24T10:00:00.000Z")) + .run_until_complete(&db, port) + .await + .json_result() + .unwrap(); + + assert_eq!(result, serde_json::json!("object")); +} + +#[sqlx::test(fixtures("base"))] +async fn test_python_job_datetime_and_bytes(db: Pool) { + initialize_tracing().await; + let server = ApiServer::start(db.clone()).await; + let port = server.addr.port(); + + let content = r#" +from datetime import datetime +def main(a: datetime, b: bytes): + return (isinstance(a, datetime), isinstance(b, bytes)) + "# + .to_owned(); + + let result = RunJob::from(JobPayload::Code(RawCode { + hash: None, + content, + path: None, + lock: None, + language: ScriptLang::Python3, + custom_concurrency_key: None, + concurrent_limit: None, + concurrency_time_window_s: None, + cache_ttl: None, + dedicated_worker: None, + })) + .arg("a", json!("2024-09-24T10:00:00.000Z")) + .arg("b", json!("dGVzdA==")) + .run_until_complete(&db, port) + .await + .json_result() + .unwrap(); + + assert_eq!(result, serde_json::json!([true, true])); +} + #[sqlx::test(fixtures("base"))] async fn test_empty_loop_1(db: Pool) { initialize_tracing().await; @@ -2590,7 +2745,7 @@ async fn test_flow_lock_all(db: Pool) { "lock": null, "path": null, "type": "rawscript", - "content": "import * as wmill from \"https://deno.land/x/windmill@v1.50.0/mod.ts\"\n\nexport async function main() {\n return \"Hello\"\n}\n", + "content": "import * as wmill from \"https://deno.land/x/windmill@v1.50.0/mod.ts\"\n\nexport async function main() {\n return wmill\n}\n", "language": "deno", "input_transforms": {} }, @@ -2667,7 +2822,7 @@ async fn test_flow_lock_all(db: Pool) { in_test_worker(&db, listen_first_job, port).await; let modules = client - .get_flow_by_path("test-workspace", "g/all/flow_lock_all") + .get_flow_by_path("test-workspace", "g/all/flow_lock_all", None) .await .unwrap() .into_inner() @@ -2689,7 +2844,8 @@ async fn test_flow_lock_all(db: Pool) { language: windmill_api_client::types::RawScriptLanguage::Go | windmill_api_client::types::RawScriptLanguage::Python3 | windmill_api_client::types::RawScriptLanguage::Deno, lock: Some(ref lock), .. - }) if lock.len() > 0) + }) if lock.len() > 0), + "{:?}", m.value ); }); } @@ -2936,6 +3092,8 @@ async fn test_script_schedule_handlers(db: Pool) { on_recovery: Some("script/f/system/schedule_recovery_handler".to_string()), on_recovery_times: None, on_recovery_extra_args: None, + on_success: None, + on_success_extra_args: None, path: "f/system/failing_script_schedule".to_string(), script_path: "f/system/failing_script".to_string(), timezone: "UTC".to_string(), @@ -3003,6 +3161,8 @@ async fn test_script_schedule_handlers(db: Pool) { on_recovery: Some("script/f/system/schedule_recovery_handler".to_string()), on_recovery_times: None, on_recovery_extra_args: None, + on_success: None, + on_success_extra_args: None, timezone: "UTC".to_string(), schedule: format!("{} {} * * * *", then.second(), then.minute()).to_string(), ws_error_handler_muted: None, @@ -3081,6 +3241,8 @@ async fn test_flow_schedule_handlers(db: Pool) { on_recovery: Some("script/f/system/schedule_recovery_handler".to_string()), on_recovery_times: None, on_recovery_extra_args: None, + on_success: None, + on_success_extra_args: None, path: "f/system/failing_flow_schedule".to_string(), script_path: "f/system/failing_flow".to_string(), timezone: "UTC".to_string(), @@ -3149,6 +3311,8 @@ async fn test_flow_schedule_handlers(db: Pool) { on_recovery: Some("script/f/system/schedule_recovery_handler".to_string()), on_recovery_times: None, on_recovery_extra_args: None, + on_success: None, + on_success_extra_args: None, timezone: "UTC".to_string(), schedule: format!("{} {} * * * *", then.second(), then.minute()).to_string(), ws_error_handler_muted: None, @@ -3240,6 +3404,7 @@ async fn run_deployed_relative_imports( visible_to_runner_only: None, no_main_func: None, codebase: None, + has_preprocessor: None, }, ) .await @@ -3270,6 +3435,7 @@ async fn run_deployed_relative_imports( dedicated_worker: None, language, priority: None, + apply_preprocessor: false, }) .push(&db2) .await; diff --git a/backend/windmill-api/Cargo.toml b/backend/windmill-api/Cargo.toml index 8afb489378..b7c4a41aed 100644 --- a/backend/windmill-api/Cargo.toml +++ b/backend/windmill-api/Cargo.toml @@ -94,9 +94,10 @@ object_store = { workspace = true, optional = true} openidconnect = { workspace = true, optional = true} url = { workspace = true, optional = true} jsonwebtoken = { workspace = true } +matchit.workspace = true +tokio-tungstenite.workspace = true pin-project.workspace = true -crc.workspace = true http.workspace = true async-stream.workspace = true ulid.workspace = true diff --git a/backend/windmill-api/openapi-deref.json b/backend/windmill-api/openapi-deref.json index 23e8f019df..db789c2163 100644 --- a/backend/windmill-api/openapi-deref.json +++ b/backend/windmill-api/openapi-deref.json @@ -1,7 +1,7 @@ { "openapi": "3.0.3", "info": { - "version": "1.304.2", + "version": "1.409.0", "title": "Windmill API", "contact": { "name": "Windmill Team", @@ -176,6 +176,22 @@ { "$ref": "#/components/parameters/Operation" }, + { + "name": "operations", + "in": "query", + "description": "comma separated list of exact operations to include", + "schema": { + "type": "string" + } + }, + { + "name": "exclude_operations", + "in": "query", + "description": "comma separated list of operations to exclude", + "schema": { + "type": "string" + } + }, { "$ref": "#/components/parameters/ResourceName" }, @@ -501,6 +517,9 @@ "properties": { "is_super_admin": { "type": "boolean" + }, + "name": { + "type": "string" } } } @@ -660,6 +679,65 @@ } } }, + "/users/overwrite": { + "post": { + "summary": "global overwrite users (require super admin and EE)", + "operationId": "globalUsersOverwrite", + "tags": [ + "user" + ], + "requestBody": { + "description": "List of users", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExportedUser" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success message", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/users/export": { + "get": { + "summary": "global export users (require super admin and EE)", + "operationId": "globalUsersExport", + "tags": [ + "user" + ], + "responses": { + "200": { + "description": "exported users", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExportedUser" + } + } + } + } + } + } + } + }, "/w/{workspace}/users/delete/{username}": { "delete": { "summary": "delete user (require admin privilege)", @@ -1061,6 +1139,49 @@ } } }, + "/settings/test_critical_channels": { + "post": { + "summary": "test critical channels", + "operationId": "testCriticalChannels", + "tags": [ + "setting" + ], + "requestBody": { + "description": "test critical channel payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "slack_channel": { + "type": "string" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "status", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/settings/test_license_key": { "post": { "summary": "test license key", @@ -1155,6 +1276,103 @@ } } }, + "/settings/latest_key_renewal_attempt": { + "get": { + "summary": "get latest key renewal attempt", + "operationId": "getLatestKeyRenewalAttempt", + "tags": [ + "setting" + ], + "responses": { + "200": { + "description": "status", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "result": { + "type": "string" + }, + "attempted_at": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "result", + "attempted_at" + ], + "nullable": true + } + } + } + } + } + } + }, + "/settings/renew_license_key": { + "post": { + "summary": "renew license key", + "operationId": "renewLicenseKey", + "tags": [ + "setting" + ], + "parameters": [ + { + "name": "license_key", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "status", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/settings/customer_portal": { + "post": { + "summary": "create customer portal session", + "operationId": "createCustomerPortalSession", + "tags": [ + "setting" + ], + "parameters": [ + { + "name": "license_key", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "url to portal", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/saml/test_metadata": { "post": { "summary": "test metadata", @@ -1187,6 +1405,30 @@ } } }, + "/settings/list_global": { + "get": { + "summary": "list global settings", + "operationId": "listGlobalSettings", + "tags": [ + "setting" + ], + "responses": { + "200": { + "description": "list of settings", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GlobalSetting" + } + } + } + } + } + } + } + }, "/users/email": { "get": { "summary": "get current user email (if logged in)", @@ -2122,6 +2364,9 @@ "git_sync": { "$ref": "#/components/schemas/WorkspaceGitSyncSettings" }, + "deploy_ui": { + "$ref": "#/components/schemas/WorkspaceDeployUISettings" + }, "default_app": { "type": "string" }, @@ -2730,6 +2975,46 @@ } } }, + "/w/{workspace}/workspaces/edit_deploy_ui_config": { + "post": { + "summary": "edit workspace deploy ui settings", + "operationId": "editWorkspaceDeployUISettings", + "tags": [ + "workspace" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "Workspace deploy UI settings", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "deploy_ui_settings": { + "$ref": "#/components/schemas/WorkspaceDeployUISettings" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "status", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, "/w/{workspace}/workspaces/edit_default_app": { "post": { "summary": "edit default app for workspace", @@ -2934,6 +3219,9 @@ "properties": { "new_key": { "type": "string" + }, + "skip_reencrypt": { + "type": "boolean" } }, "required": [ @@ -3127,6 +3415,40 @@ } } }, + "/w/{workspace}/users/username_to_email/{username}": { + "get": { + "summary": "get email from username", + "operationId": "usernameToEmail", + "tags": [ + "user" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "username", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "email", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/users/tokens/create": { "post": { "summary": "create token", @@ -3236,6 +3558,12 @@ "schema": { "type": "boolean" } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/PerPage" } ], "responses": { @@ -3559,6 +3887,19 @@ "parameters": [ { "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "path_start", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/PerPage" } ], "responses": { @@ -3710,6 +4051,50 @@ } } }, + "/oauth/connect_slack_callback": { + "post": { + "summary": "connect slack callback instance", + "operationId": "connectSlackCallbackInstance", + "tags": [ + "oauth" + ], + "requestBody": { + "description": "code endpoint", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "state": { + "type": "string" + } + }, + "required": [ + "code", + "state" + ] + } + } + } + }, + "responses": { + "200": { + "description": "success message", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/oauth/connect_callback/{client_name}": { "post": { "summary": "connect callback", @@ -3932,7 +4317,18 @@ "oauth": { "type": "array", "items": { - "type": "string" + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "display_name": { + "type": "string" + } + }, + "required": [ + "type" + ] } }, "saml": { @@ -3962,19 +4358,50 @@ "content": { "application/json": { "schema": { - "additionalProperties": { - "type": "object", - "properties": { - "extra_params": { - "additionalProperties": { - "type": "string" - } - }, - "scopes": { - "type": "array", - "items": { - "type": "string" - } + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "/oauth/get_connect/{client}": { + "get": { + "summary": "get oauth connect", + "operationId": "getOAuthConnect", + "tags": [ + "oauth" + ], + "parameters": [ + { + "name": "client", + "description": "client name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "get", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "extra_params": { + "type": "object" + }, + "scopes": { + "type": "array", + "items": { + "type": "string" } } } @@ -4294,6 +4721,13 @@ "schema": { "type": "string" } + }, + { + "name": "path_start", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -4433,6 +4867,30 @@ } } }, + "/w/{workspace}/resources/file_resource_type_to_file_ext_map": { + "get": { + "summary": "get map from resource type to format extension", + "operationId": "fileResourceTypeToFileExtMap", + "tags": [ + "resource" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "responses": { + "200": { + "description": "map from resource type to file ext", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, "/w/{workspace}/resources/type/delete/{path}": { "delete": { "summary": "delete resource_type", @@ -5281,7 +5739,23 @@ }, { "name": "show_archived", - "description": "(default false)\nshow also the archived files.\nwhen multiple archived hash share the same path, only the ones with the latest create_at\nare \ned.\n", + "description": "(default false)\nshow only the archived files.\nwhen multiple archived hash share the same path, only the ones with the latest create_at\nare \ned.\n", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "include_without_main", + "description": "(default false)\ninclude scripts without an exported main function\n", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "include_draft_only", + "description": "(default false)\ninclude scripts that have no deployed version\n", "in": "query", "schema": { "type": "boolean" @@ -5310,6 +5784,14 @@ "schema": { "type": "boolean" } + }, + { + "name": "with_deployment_msg", + "description": "(default false)\ninclude deployment message\n", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -5735,6 +6217,13 @@ }, { "$ref": "#/components/parameters/ScriptPath" + }, + { + "name": "with_starred_info", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -5751,6 +6240,67 @@ } } }, + "/w/{workspace}/scripts/get_triggers_count/{path}": { + "get": { + "summary": "get triggers count of script", + "operationId": "getTriggersCountOfScript", + "tags": [ + "script" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "responses": { + "200": { + "description": "triggers count", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggersCount" + } + } + } + } + } + } + }, + "/w/{workspace}/scripts/list_tokens/{path}": { + "get": { + "summary": "get tokens with script scope", + "operationId": "listTokensOfScript", + "tags": [ + "script" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "responses": { + "200": { + "description": "tokens list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TruncatedToken" + } + } + } + } + } + } + } + }, "/w/{workspace}/scripts/get/draft/{path}": { "get": { "summary": "get script by path with draft", @@ -5963,6 +6513,13 @@ }, { "$ref": "#/components/parameters/ScriptHash" + }, + { + "name": "with_starred_info", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -6076,6 +6633,14 @@ "type": "integer" } }, + { + "name": "skip_preprocessor", + "description": "skip the preprocessor", + "in": "query", + "schema": { + "type": "boolean" + } + }, { "$ref": "#/components/parameters/ParentJob" }, @@ -6518,7 +7083,7 @@ }, { "name": "show_archived", - "description": "(default false)\nshow also the archived files.\nwhen multiple archived hash share the same path, only the ones with the latest create_at\nare displayed.\n", + "description": "(default false)\nshow only the archived files.\nwhen multiple archived hash share the same path, only the ones with the latest create_at\nare displayed.\n", "in": "query", "schema": { "type": "boolean" @@ -6531,6 +7096,22 @@ "schema": { "type": "boolean" } + }, + { + "name": "include_draft_only", + "description": "(default false)\ninclude items that have no deployed version\n", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "with_deployment_msg", + "description": "(default false)\ninclude deployment message\n", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -6565,6 +7146,133 @@ } } }, + "/w/{workspace}/flows/history/p/{path}": { + "get": { + "summary": "get flow history by path", + "operationId": "getFlowHistory", + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "tags": [ + "flow" + ], + "responses": { + "200": { + "description": "Flow history", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FlowVersion" + } + } + } + } + } + } + } + }, + "/w/{workspace}/flows/get/v/{version}/p/{path}": { + "get": { + "summary": "get flow version", + "operationId": "getFlowVersion", + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "type": "string", + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "number" + } + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "tags": [ + "flow" + ], + "responses": { + "200": { + "description": "flow details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Flow" + } + } + } + } + } + } + }, + "/w/{workspace}/flows/history_update/v/{version}/p/{path}": { + "post": { + "summary": "update flow history", + "operationId": "updateFlowHistory", + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "type": "string", + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "number" + } + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "requestBody": { + "description": "Flow deployment message", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "deployment_msg": { + "type": "string" + } + }, + "required": [ + "deployment_msg" + ] + } + } + } + }, + "tags": [ + "flow" + ], + "responses": { + "200": { + "description": "success", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/w/{workspace}/flows/get/{path}": { "get": { "summary": "get flow by path", @@ -6578,6 +7286,13 @@ }, { "$ref": "#/components/parameters/ScriptPath" + }, + { + "name": "with_starred_info", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -6594,6 +7309,67 @@ } } }, + "/w/{workspace}/flows/get_triggers_count/{path}": { + "get": { + "summary": "get triggers count of flow", + "operationId": "getTriggersCountOfFlow", + "tags": [ + "flow" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "responses": { + "200": { + "description": "triggers count", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggersCount" + } + } + } + } + } + } + }, + "/w/{workspace}/flows/list_tokens/{path}": { + "get": { + "summary": "get tokens with flow scope", + "operationId": "listTokensOfFlow", + "tags": [ + "flow" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/ScriptPath" + } + ], + "responses": { + "200": { + "description": "tokens list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TruncatedToken" + } + } + } + } + } + } + } + }, "/w/{workspace}/flows/toggle_workspace_error_handler/{path}": { "post": { "summary": "Toggle ON and OFF the workspace error handler for a given flow", @@ -6887,44 +7663,6 @@ } } }, - "/w/{workspace}/flows/input_history/p/{path}": { - "get": { - "summary": "list inputs for previous completed flow jobs", - "operationId": "getFlowInputHistoryByPath", - "tags": [ - "flow" - ], - "parameters": [ - { - "$ref": "#/components/parameters/WorkspaceId" - }, - { - "$ref": "#/components/parameters/ScriptPath" - }, - { - "$ref": "#/components/parameters/Page" - }, - { - "$ref": "#/components/parameters/PerPage" - } - ], - "responses": { - "200": { - "description": "input history for completed jobs with this flow path", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Input" - } - } - } - } - } - } - } - }, "/w/{workspace}/raw_apps/list": { "get": { "summary": "list all raw apps", @@ -7136,6 +7874,22 @@ "schema": { "type": "boolean" } + }, + { + "name": "include_draft_only", + "description": "(default false)\ninclude items that have no deployed version\n", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "with_deployment_msg", + "description": "(default false)\ninclude deployment message\n", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -7258,6 +8012,13 @@ }, { "$ref": "#/components/parameters/ScriptPath" + }, + { + "name": "with_starred_info", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -7756,6 +8517,9 @@ "path": { "type": "string" }, + "lock": { + "type": "string" + }, "cache_ttl": { "type": "integer" } @@ -7767,6 +8531,15 @@ }, "force_viewer_static_fields": { "type": "object" + }, + "force_viewer_one_of_fields": { + "type": "object" + }, + "force_viewer_allow_user_resources": { + "type": "array", + "items": { + "type": "string" + } } }, "required": [ @@ -7822,6 +8595,14 @@ "type": "integer" } }, + { + "name": "skip_preprocessor", + "description": "skip the preprocessor", + "in": "query", + "schema": { + "type": "boolean" + } + }, { "$ref": "#/components/parameters/ParentJob" }, @@ -7996,6 +8777,14 @@ "type": "integer" } }, + { + "name": "skip_preprocessor", + "description": "skip the preprocessor", + "in": "query", + "schema": { + "type": "boolean" + } + }, { "$ref": "#/components/parameters/ParentJob" }, @@ -8339,6 +9128,14 @@ "schema": { "type": "boolean" } + }, + { + "name": "is_not_schedule", + "description": "is not a scheduled job", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -8388,6 +9185,9 @@ "properties": { "database_length": { "type": "integer" + }, + "suspended": { + "type": "integer" } }, "required": [ @@ -8434,10 +9234,120 @@ } } }, - "/w/{workspace}/jobs/queue/cancel_all": { + "/w/{workspace}/jobs/queue/list_filtered_uuids": { + "get": { + "summary": "get the ids of all jobs matching the given filters", + "operationId": "listFilteredUuids", + "tags": [ + "job" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/OrderDesc" + }, + { + "$ref": "#/components/parameters/CreatedBy" + }, + { + "$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/Success" + }, + { + "$ref": "#/components/parameters/ScheduledForBeforeNow" + }, + { + "$ref": "#/components/parameters/JobKinds" + }, + { + "$ref": "#/components/parameters/Suspended" + }, + { + "$ref": "#/components/parameters/Running" + }, + { + "$ref": "#/components/parameters/ArgsFilter" + }, + { + "$ref": "#/components/parameters/ResultFilter" + }, + { + "$ref": "#/components/parameters/Tag" + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/PerPage" + }, + { + "name": "concurrency_key", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "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/cancel_selection": { "post": { - "summary": "cancel all jobs", - "operationId": "cancelAll", + "summary": "cancel jobs based on the given uuids", + "operationId": "cancelSelection", "tags": [ "job" ], @@ -8446,6 +9356,20 @@ "$ref": "#/components/parameters/WorkspaceId" } ], + "requestBody": { + "description": "uuids of the jobs to cancel", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, "responses": { "200": { "description": "uuids of canceled jobs", @@ -8480,6 +9404,9 @@ { "$ref": "#/components/parameters/CreatedBy" }, + { + "$ref": "#/components/parameters/Label" + }, { "$ref": "#/components/parameters/ParentJob" }, @@ -8545,6 +9472,14 @@ "schema": { "type": "boolean" } + }, + { + "name": "is_not_schedule", + "description": "is not a scheduled job", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -8578,6 +9513,9 @@ { "$ref": "#/components/parameters/CreatedBy" }, + { + "$ref": "#/components/parameters/Label" + }, { "$ref": "#/components/parameters/ParentJob" }, @@ -8599,6 +9537,12 @@ { "$ref": "#/components/parameters/StartedAfter" }, + { + "$ref": "#/components/parameters/CreatedBefore" + }, + { + "$ref": "#/components/parameters/CreatedAfter" + }, { "$ref": "#/components/parameters/CreatedOrStartedBefore" }, @@ -8611,9 +9555,15 @@ { "$ref": "#/components/parameters/CreatedOrStartedAfter" }, + { + "$ref": "#/components/parameters/CreatedOrStartedAfterCompletedJob" + }, { "$ref": "#/components/parameters/JobKinds" }, + { + "$ref": "#/components/parameters/Suspended" + }, { "$ref": "#/components/parameters/ArgsFilter" }, @@ -8668,6 +9618,14 @@ "schema": { "type": "boolean" } + }, + { + "name": "is_not_schedule", + "description": "is not a scheduled job", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -8708,6 +9666,62 @@ } } }, + "/jobs/completed/count_by_tag": { + "get": { + "summary": "Count jobs by tag", + "operationId": "countJobsByTag", + "tags": [ + "job" + ], + "parameters": [ + { + "name": "horizon_secs", + "in": "query", + "description": "Past Time horizon in seconds (when to start the count = now - horizon) (default is 3600)", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "workspace_id", + "in": "query", + "description": "Specific workspace ID to filter results (optional)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Job counts by tag", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tag": { + "type": "string" + }, + "count": { + "type": "integer" + } + }, + "required": [ + "tag", + "count" + ] + } + } + } + } + } + } + } + }, "/w/{workspace}/jobs_u/get/{id}": { "get": { "summary": "get job", @@ -8802,6 +9816,33 @@ } } }, + "/w/{workspace}/jobs_u/get_args/{id}": { + "get": { + "summary": "get job args", + "operationId": "getJobArgs", + "tags": [ + "job" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/JobId" + } + ], + "responses": { + "200": { + "description": "job args", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, "/w/{workspace}/jobs_u/getupdate/{id}": { "get": { "summary": "get job updates", @@ -8829,6 +9870,13 @@ "schema": { "type": "integer" } + }, + { + "name": "get_progress", + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -8854,6 +9902,9 @@ "mem_peak": { "type": "integer" }, + "progress": { + "type": "integer" + }, "flow_status": { "$ref": "#/components/schemas/WorkflowStatusRecord" } @@ -8865,6 +9916,38 @@ } } }, + "/w/{workspace}/jobs_u/get_log_file/{path}": { + "get": { + "summary": "get log file from object store", + "operationId": "getLogFileFromStore", + "tags": [ + "job" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "job log", + "content": { + "text/plain": { + "type": "string" + } + } + } + } + } + }, "/w/{workspace}/jobs_u/get_flow_debug_info/{id}": { "get": { "summary": "get flow debug info", @@ -8934,6 +10017,34 @@ }, { "$ref": "#/components/parameters/JobId" + }, + { + "name": "suspended_job", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "resume_id", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "secret", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "approver", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -9027,7 +10138,7 @@ }, "/w/{workspace}/jobs_u/queue/cancel/{id}": { "post": { - "summary": "cancel queued job", + "summary": "cancel queued or running job", "operationId": "cancelQueuedJob", "tags": [ "job" @@ -9982,6 +11093,13 @@ "schema": { "type": "boolean" } + }, + { + "name": "path_start", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -10060,7 +11178,8 @@ "type": "string", "enum": [ "error", - "recovery" + "recovery", + "success" ] }, "override_existing": { @@ -10097,6 +11216,311 @@ } } }, + "/w/{workspace}/http_triggers/create": { + "post": { + "summary": "create http trigger", + "operationId": "createHttpTrigger", + "tags": [ + "http_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "new http trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewHttpTrigger" + } + } + } + }, + "responses": { + "201": { + "description": "http trigger created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/http_triggers/update/{path}": { + "post": { + "summary": "update http trigger", + "operationId": "updateHttpTrigger", + "tags": [ + "http_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "requestBody": { + "description": "updated trigger", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditHttpTrigger" + } + } + } + }, + "responses": { + "200": { + "description": "http trigger updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/http_triggers/delete/{path}": { + "delete": { + "summary": "delete http trigger", + "operationId": "deleteHttpTrigger", + "tags": [ + "http_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "http trigger deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/http_triggers/get/{path}": { + "get": { + "summary": "get http trigger", + "operationId": "getHttpTrigger", + "tags": [ + "http_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "http trigger deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpTrigger" + } + } + } + } + } + } + }, + "/w/{workspace}/http_triggers/list": { + "get": { + "summary": "list http triggers", + "operationId": "listHttpTriggers", + "tags": [ + "http_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": "http trigger list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HttpTrigger" + } + } + } + } + } + } + } + }, + "/w/{workspace}/http_triggers/exists/{path}": { + "get": { + "summary": "does http trigger exists", + "operationId": "existsHttpTrigger", + "tags": [ + "http_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "http trigger exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/http_triggers/route_exists": { + "post": { + "summary": "does route exists", + "operationId": "existsRoute", + "tags": [ + "http_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "requestBody": { + "description": "route exists request", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "route_path": { + "type": "string" + }, + "http_method": { + "type": "string", + "enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + } + }, + "required": [ + "kind", + "route_path", + "http_method" + ] + } + } + } + }, + "responses": { + "200": { + "description": "route exists", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/w/{workspace}/http_triggers/used": { + "get": { + "summary": "whether http triggers are used", + "operationId": "used", + "tags": [ + "http_trigger" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + } + ], + "responses": { + "200": { + "description": "whether http triggers are used", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, "/groups/list": { "get": { "summary": "list instance groups", @@ -10351,6 +11775,65 @@ } } }, + "/groups/export": { + "get": { + "summary": "export instance groups", + "operationId": "exportInstanceGroups", + "tags": [ + "group" + ], + "responses": { + "200": { + "description": "exported instance groups", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExportedInstanceGroup" + } + } + } + } + } + } + } + }, + "/groups/overwrite": { + "post": { + "summary": "overwrite instance groups", + "operationId": "overwriteInstanceGroups", + "tags": [ + "group" + ], + "requestBody": { + "description": "overwrite instance groups", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExportedInstanceGroup" + } + } + } + } + }, + "responses": { + "200": { + "description": "success message", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/w/{workspace}/groups/list": { "get": { "summary": "list groups", @@ -10759,6 +12242,9 @@ "name": { "type": "string" }, + "summary": { + "type": "string" + }, "owners": { "type": "array", "items": { @@ -10815,6 +12301,9 @@ "schema": { "type": "object", "properties": { + "summary": { + "type": "string" + }, "owners": { "type": "array", "items": { @@ -11131,6 +12620,57 @@ } } }, + "/workers/queue_metrics": { + "get": { + "summary": "get queue metrics", + "operationId": "getQueueMetrics", + "tags": [ + "worker" + ], + "responses": { + "200": { + "description": "metrics", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "value": { + "type": "number" + } + }, + "required": [ + "created_at", + "value" + ] + } + } + }, + "required": [ + "id", + "values" + ] + } + } + } + } + } + } + } + }, "/configs/list_worker_groups": { "get": { "summary": "list worker groups", @@ -11248,6 +12788,30 @@ } } }, + "/configs/list": { + "get": { + "summary": "list configs", + "operationId": "listConfigs", + "tags": [ + "config" + ], + "responses": { + "200": { + "description": "list of configs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Config" + } + } + } + } + } + } + } + }, "/w/{workspace}/acls/get/{kind}/{path}": { "get": { "summary": "get granular acls", @@ -11277,7 +12841,8 @@ "flow", "folder", "app", - "raw_app" + "raw_app", + "http_trigger" ] } } @@ -11328,7 +12893,8 @@ "flow", "folder", "app", - "raw_app" + "raw_app", + "http_trigger" ] } } @@ -11398,7 +12964,8 @@ "flow", "folder", "app", - "raw_app" + "raw_app", + "http_trigger" ] } } @@ -11633,6 +13200,52 @@ } } }, + "/w/{workspace}/inputs/{jobOrInputId}/args": { + "get": { + "summary": "Get args from history or saved input", + "operationId": "getArgsFromHistoryOrSavedInput", + "tags": [ + "input" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "jobOrInputId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "input", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "allow_large", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "args", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, "/w/{workspace}/inputs/list": { "get": { "summary": "List saved Inputs for a Runnable", @@ -12097,7 +13710,7 @@ }, "/w/{workspace}/job_helpers/test_connection": { "get": { - "summary": "Test connection to the workspace datasets storage", + "summary": "Test connection to the workspace object storage", "operationId": "datasetStorageTestConnection", "tags": [ "helpers" @@ -12105,6 +13718,13 @@ "parameters": [ { "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -12121,7 +13741,7 @@ }, "/w/{workspace}/job_helpers/list_stored_files": { "get": { - "summary": "List the file keys available in the workspace files storage (S3)", + "summary": "List the file keys available in a workspace object storage", "operationId": "listStoredFiles", "tags": [ "helpers" @@ -12151,6 +13771,13 @@ "schema": { "type": "string" } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -12202,6 +13829,13 @@ "schema": { "type": "string" } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -12278,6 +13912,13 @@ "schema": { "type": "integer" } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -12349,6 +13990,13 @@ "schema": { "type": "string" } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -12363,6 +14011,144 @@ } } }, + "/w/{workspace}/job_helpers/load_table_count/{path}": { + "get": { + "summary": "Load the table row count", + "operationId": "loadTableRowCount", + "tags": [ + "helpers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + }, + { + "name": "search_col", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "search_term", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Table count", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "count": { + "type": "number" + } + } + } + } + } + } + } + } + }, + "/w/{workspace}/job_helpers/load_csv_preview/{path}": { + "get": { + "summary": "Load a preview of a csv file", + "operationId": "loadCsvPreview", + "tags": [ + "helpers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/Path" + }, + { + "name": "offset", + "in": "query", + "schema": { + "type": "number" + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "number" + } + }, + { + "name": "sort_col", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sort_desc", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "search_col", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "search_term", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "csv_separator", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Csv Preview", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, "/w/{workspace}/job_helpers/delete_s3_file": { "delete": { "summary": "Permanently delete file from S3", @@ -12381,6 +14167,13 @@ "schema": { "type": "string" } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -12421,6 +14214,13 @@ "schema": { "type": "string" } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -12477,6 +14277,13 @@ "schema": { "type": "string" } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } } ], "requestBody": { @@ -12547,6 +14354,13 @@ "schema": { "type": "string" } + }, + { + "name": "storage", + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -12564,6 +14378,56 @@ } } }, + "/w/{workspace}/job_helpers/download_s3_parquet_file_as_csv": { + "get": { + "summary": "Download file to S3 bucket", + "operationId": "fileDownloadParquetAsCsv", + "tags": [ + "helpers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "file_key", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "s3_resource_path", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "resource_type", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The downloaded file", + "content": { + "text/csv": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/w/{workspace}/job_metrics/get/{id}": { "post": { "summary": "get job metrics", @@ -12637,6 +14501,182 @@ } } }, + "/w/{workspace}/job_metrics/set_progress/{id}": { + "post": { + "summary": "set job metrics", + "operationId": "setJobProgress", + "tags": [ + "metrics" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/JobId" + } + ], + "requestBody": { + "description": "parameters for statistics retrieval", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "percent": { + "type": "integer" + }, + "flow_job_id": { + "type": "string", + "format": "uuid" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Job progress updated", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, + "/w/{workspace}/job_metrics/get_progress/{id}": { + "get": { + "summary": "get job progress", + "operationId": "getJobProgress", + "tags": [ + "metrics" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/JobId" + } + ], + "responses": { + "200": { + "description": "job progress between 0 and 99", + "content": { + "application/json": { + "schema": { + "type": "integer" + } + } + } + } + } + } + }, + "/service_logs/list_files": { + "get": { + "summary": "list log files ordered by timestamp", + "operationId": "listLogFiles", + "tags": [ + "service_logs" + ], + "parameters": [ + { + "$ref": "#/components/parameters/Before" + }, + { + "$ref": "#/components/parameters/After" + }, + { + "name": "with_error", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "time", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "hostname": { + "type": "string" + }, + "mode": { + "type": "string" + }, + "worker_group": { + "type": "string" + }, + "log_ts": { + "type": "string", + "format": "date-time" + }, + "file_path": { + "type": "string" + }, + "ok_lines": { + "type": "integer" + }, + "err_lines": { + "type": "integer" + }, + "json_fmt": { + "type": "boolean" + } + }, + "required": [ + "hostname", + "mode", + "log_ts", + "file_path", + "json_fmt" + ] + } + } + } + } + } + } + } + }, + "/service_logs/get_log_file/{path}": { + "get": { + "summary": "get log file by path", + "operationId": "getLogFile", + "tags": [ + "service_logs" + ], + "parameters": [ + { + "$ref": "#/components/parameters/Path" + } + ], + "responses": { + "200": { + "description": "log stream", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, "/concurrency_groups/list": { "get": { "summary": "List all concurrency groups", @@ -12661,7 +14701,7 @@ } } }, - "/concurrency_groups/{concurrency_id}": { + "/concurrency_groups/prune/{concurrency_id}": { "delete": { "summary": "Delete concurrency group", "operationId": "deleteConcurrencyGroup", @@ -12687,6 +14727,238 @@ } } } + }, + "/concurrency_groups/{id}/key": { + "get": { + "summary": "Get the concurrency key for a job that has concurrency limits enabled", + "operationId": "getConcurrencyKey", + "tags": [ + "concurrencyGroups" + ], + "parameters": [ + { + "$ref": "#/components/parameters/JobId" + } + ], + "responses": { + "200": { + "description": "concurrency key for given job", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/w/{workspace}/concurrency_groups/list_jobs": { + "get": { + "summary": "Get intervals of job runtime concurrency", + "operationId": "listExtendedJobs", + "tags": [ + "concurrencyGroups", + "job" + ], + "parameters": [ + { + "name": "concurrency_key", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "row_limit", + "in": "query", + "required": false, + "schema": { + "type": "number" + } + }, + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "$ref": "#/components/parameters/CreatedBy" + }, + { + "$ref": "#/components/parameters/Label" + }, + { + "$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/CreatedOrStartedBefore" + }, + { + "$ref": "#/components/parameters/Running" + }, + { + "$ref": "#/components/parameters/ScheduledForBeforeNow" + }, + { + "$ref": "#/components/parameters/CreatedOrStartedAfter" + }, + { + "$ref": "#/components/parameters/CreatedOrStartedAfterCompletedJob" + }, + { + "$ref": "#/components/parameters/JobKinds" + }, + { + "$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": "time", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExtendedJobs" + } + } + } + } + } + } + }, + "/srch/w/{workspace}/index/search/job": { + "get": { + "summary": "Search through jobs with a string query", + "operationId": "searchJobsIndex", + "tags": [ + "indexSearch" + ], + "parameters": [ + { + "$ref": "#/components/parameters/WorkspaceId" + }, + { + "name": "search_query", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "search results", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "query_parse_errors": { + "description": "a list of the terms that couldn't be parsed (and thus ignored)", + "type": "array", + "items": { + "type": "object", + "properties": { + "dancer": { + "type": "string" + } + } + } + }, + "hits": { + "description": "the jobs that matched the query", + "type": "array", + "items": { + "$ref": "#/components/schemas/JobSearchHit" + } + } + } + } + } + } + } + } + } } }, "components": { @@ -12839,6 +15111,14 @@ "type": "string" } }, + "Label": { + "name": "label", + "description": "mask to filter exact matching job's label (job labels are completed jobs with as a result an object containing a string in the array at key 'wm_labels')", + "in": "query", + "schema": { + "type": "string" + } + }, "ParentJob": { "name": "parent_job", "description": "The parent job that is at the origin and responsible for the execution of this script if any", @@ -12929,6 +15209,24 @@ "type": "string" } }, + "CreatedBefore": { + "name": "created_before", + "description": "filter on created before (inclusive) timestamp", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + "CreatedAfter": { + "name": "created_after", + "description": "filter on created after (exclusive) timestamp", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, "StartedBefore": { "name": "started_before", "description": "filter on started before (inclusive) timestamp", @@ -12947,6 +15245,15 @@ "format": "date-time" } }, + "Before": { + "name": "before", + "description": "filter on started before (inclusive) timestamp", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, "CreatedOrStartedAfter": { "name": "created_or_started_after", "description": "filter on created_at for non non started job and started_at otherwise after (exclusive) timestamp", @@ -12956,6 +15263,15 @@ "format": "date-time" } }, + "CreatedOrStartedAfterCompletedJob": { + "name": "created_or_started_after_completed_jobs", + "description": "filter on created_at for non non started job and started_at otherwise after (exclusive) timestamp but only for the completed jobs", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, "CreatedOrStartedBefore": { "name": "created_or_started_before", "description": "filter on created_at for non non started job and started_at otherwise before (inclusive) timestamp", @@ -13030,15 +15346,6 @@ "format": "date-time" } }, - "Before": { - "name": "before", - "description": "filter on created before (exclusive) timestamp", - "in": "query", - "schema": { - "type": "string", - "format": "date-time" - } - }, "Username": { "name": "username", "description": "filter on exact username of user", @@ -13198,7 +15505,10 @@ "mssql", "graphql", "nativets", - "bun" + "bun", + "php", + "rust", + "ansible" ] }, "kind": { @@ -13235,6 +15545,9 @@ "concurrency_time_window_s": { "type": "integer" }, + "concurrency_key": { + "type": "string" + }, "cache_ttl": { "type": "number" }, @@ -13258,6 +15571,15 @@ }, "visible_to_runner_only": { "type": "boolean" + }, + "no_main_func": { + "type": "boolean" + }, + "codebase": { + "type": "string" + }, + "has_preprocessor": { + "type": "boolean" } }, "required": [ @@ -13274,7 +15596,9 @@ "extra_perms", "language", "kind", - "starred" + "starred", + "no_main_func", + "has_preprocessor" ] }, "NewScript": { @@ -13319,7 +15643,10 @@ "mssql", "graphql", "nativets", - "bun" + "bun", + "php", + "rust", + "ansible" ] }, "kind": { @@ -13379,6 +15706,15 @@ }, "visible_to_runner_only": { "type": "boolean" + }, + "no_main_func": { + "type": "boolean" + }, + "codebase": { + "type": "string" + }, + "has_preprocessor": { + "type": "boolean" } }, "required": [ @@ -13437,9 +15773,6 @@ "name": { "type": "string" }, - "args": { - "type": "object" - }, "created_by": { "type": "string" }, @@ -13613,7 +15946,10 @@ "mssql", "graphql", "nativets", - "bun" + "bun", + "php", + "rust", + "ansible" ] }, "email": { @@ -13630,6 +15966,15 @@ }, "priority": { "type": "integer" + }, + "self_wait_time_ms": { + "type": "number" + }, + "aggregate_wait_time_ms": { + "type": "number" + }, + "suspend": { + "type": "number" } }, "required": [ @@ -13750,7 +16095,10 @@ "mssql", "graphql", "nativets", - "bun" + "bun", + "php", + "rust", + "ansible" ] }, "is_skipped": { @@ -13770,6 +16118,18 @@ }, "priority": { "type": "integer" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "self_wait_time_ms": { + "type": "number" + }, + "aggregate_wait_time_ms": { + "type": "number" } }, "required": [ @@ -13789,29 +16149,58 @@ "tag" ] }, + "ObscuredJob": { + "type": "object", + "properties": { + "typ": { + "type": "string" + }, + "started_at": { + "type": "string", + "format": "date-time" + }, + "duration_ms": { + "type": "number" + } + } + }, "Job": { - "allOf": [ + "oneOf": [ { - "oneOf": [ + "allOf": [ { "$ref": "#/components/schemas/CompletedJob" }, { - "$ref": "#/components/schemas/QueuedJob" + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "CompletedJob" + ] + } + } } ] }, { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "CompletedJob", - "QueuedJob" - ] + "allOf": [ + { + "$ref": "#/components/schemas/QueuedJob" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "QueuedJob" + ] + } + } } - } + ] } ], "discriminator": { @@ -13940,6 +16329,9 @@ "items": { "type": "string" } + }, + "email": { + "type": "string" } }, "required": [ @@ -13963,6 +16355,9 @@ "items": { "type": "string" } + }, + "workspace_id": { + "type": "string" } } }, @@ -13978,6 +16373,9 @@ }, "impersonate_email": { "type": "string" + }, + "workspace_id": { + "type": "string" } }, "required": [ @@ -14025,6 +16423,10 @@ }, "is_refreshed": { "type": "boolean" + }, + "expires_at": { + "type": "string", + "format": "date-time" } }, "required": [ @@ -14077,6 +16479,10 @@ }, "is_oauth": { "type": "boolean" + }, + "expires_at": { + "type": "string", + "format": "date-time" } }, "required": [ @@ -14396,6 +16802,14 @@ "typ" ] } + }, + "no_main_func": { + "type": "boolean", + "nullable": true + }, + "has_preprocessor": { + "type": "boolean", + "nullable": true } }, "required": [ @@ -14403,7 +16817,9 @@ "start_kwargs", "args", "type", - "error" + "error", + "no_main_func", + "has_preprocessor" ] }, "Preview": { @@ -14433,7 +16849,10 @@ "mssql", "graphql", "nativets", - "bun" + "bun", + "php", + "rust", + "ansible" ] }, "tag": { @@ -14550,6 +16969,13 @@ "additionalProperties": { "type": "boolean" } + }, + "created_by": { + "type": "string" + }, + "edited_at": { + "type": "string", + "format": "date-time" } }, "required": [ @@ -14597,6 +17023,13 @@ }, "account": { "type": "number" + }, + "created_by": { + "type": "string" + }, + "edited_at": { + "type": "string", + "format": "date-time" } }, "required": [ @@ -14619,6 +17052,16 @@ "schema": {}, "description": { "type": "string" + }, + "created_by": { + "type": "string" + }, + "edited_at": { + "type": "string", + "format": "date-time" + }, + "format_extension": { + "type": "string" } }, "required": [ @@ -14698,6 +17141,12 @@ "on_recovery_extra_args": { "$ref": "#/components/schemas/ScriptArgs" }, + "on_success": { + "type": "string" + }, + "on_success_extra_args": { + "$ref": "#/components/schemas/ScriptArgs" + }, "ws_error_handler_muted": { "type": "boolean" }, @@ -14712,6 +17161,10 @@ }, "tag": { "type": "string" + }, + "paused_until": { + "type": "string", + "format": "date-time" } }, "required": [ @@ -14806,6 +17259,12 @@ "on_recovery_extra_args": { "$ref": "#/components/schemas/ScriptArgs" }, + "on_success": { + "type": "string" + }, + "on_success_extra_args": { + "$ref": "#/components/schemas/ScriptArgs" + }, "ws_error_handler_muted": { "type": "boolean" }, @@ -14820,6 +17279,10 @@ }, "tag": { "type": "string" + }, + "paused_until": { + "type": "string", + "format": "date-time" } }, "required": [ @@ -14864,6 +17327,12 @@ "on_recovery_extra_args": { "$ref": "#/components/schemas/ScriptArgs" }, + "on_success": { + "type": "string" + }, + "on_success_extra_args": { + "$ref": "#/components/schemas/ScriptArgs" + }, "ws_error_handler_muted": { "type": "boolean" }, @@ -14878,6 +17347,10 @@ }, "tag": { "type": "string" + }, + "paused_until": { + "type": "string", + "format": "date-time" } }, "required": [ @@ -14888,6 +17361,181 @@ "args" ] }, + "HttpTrigger": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "edited_by": { + "type": "string" + }, + "edited_at": { + "type": "string", + "format": "date-time" + }, + "script_path": { + "type": "string" + }, + "route_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "extra_perms": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, + "email": { + "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "http_method": { + "type": "string", + "enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + }, + "is_async": { + "type": "boolean" + }, + "requires_auth": { + "type": "boolean" + } + }, + "required": [ + "path", + "edited_by", + "edited_at", + "script_path", + "route_path", + "extra_perms", + "is_flow", + "email", + "workspace_id", + "is_async", + "requires_auth", + "http_method" + ] + }, + "NewHttpTrigger": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "route_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "http_method": { + "type": "string", + "enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + }, + "is_async": { + "type": "boolean" + }, + "requires_auth": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "route_path", + "is_flow", + "is_async", + "requires_auth", + "http_method" + ] + }, + "EditHttpTrigger": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "script_path": { + "type": "string" + }, + "route_path": { + "type": "string" + }, + "is_flow": { + "type": "boolean" + }, + "http_method": { + "type": "string", + "enum": [ + "get", + "post", + "put", + "delete", + "patch" + ] + }, + "is_async": { + "type": "boolean" + }, + "requires_auth": { + "type": "boolean" + } + }, + "required": [ + "path", + "script_path", + "is_flow", + "kind", + "is_async", + "requires_auth", + "http_method" + ] + }, + "TriggersCount": { + "type": "object", + "properties": { + "primary_schedule": { + "type": "object", + "properties": { + "schedule": { + "type": "string" + } + } + }, + "schedule_count": { + "type": "number" + }, + "http_routes_count": { + "type": "number" + }, + "webhook_count": { + "type": "number" + }, + "email_count": { + "type": "number" + } + } + }, "Group": { "type": "object", "properties": { @@ -14951,6 +17599,16 @@ "additionalProperties": { "type": "boolean" } + }, + "summary": { + "type": "string" + }, + "created_by": { + "type": "string" + }, + "edited_at": { + "type": "string", + "format": "date-time" } }, "required": [ @@ -14992,6 +17650,36 @@ }, "wm_version": { "type": "string" + }, + "last_job_id": { + "type": "string" + }, + "last_job_workspace_id": { + "type": "string" + }, + "occupancy_rate": { + "type": "number" + }, + "occupancy_rate_15s": { + "type": "number" + }, + "occupancy_rate_5m": { + "type": "number" + }, + "occupancy_rate_30m": { + "type": "number" + }, + "memory": { + "type": "number" + }, + "vcpus": { + "type": "number" + }, + "memory_usage": { + "type": "number" + }, + "wm_memory_usage": { + "type": "number" } }, "required": [ @@ -15148,6 +17836,12 @@ } ] }, + "ExtraPerms": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, "FlowMetadata": { "type": "object", "properties": { @@ -15168,10 +17862,7 @@ "type": "boolean" }, "extra_perms": { - "type": "object" - }, - "additionalProperties": { - "type": "boolean" + "$ref": "#/components/schemas/ExtraPerms" }, "starred": { "type": "boolean" @@ -15291,6 +17982,12 @@ "type": "object" } }, + "triggerables_v2": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, "execution_mode": { "type": "string", "enum": [ @@ -15424,7 +18121,9 @@ "type": "string", "format": "date-time" }, - "value": {}, + "value": { + "type": "object" + }, "policy": { "$ref": "#/components/schemas/Policy" }, @@ -15487,6 +18186,25 @@ "version" ] }, + "FlowVersion": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "deployment_msg": { + "type": "string" + } + }, + "required": [ + "id", + "created_at" + ] + }, "SlackToken": { "type": "object", "properties": { @@ -15581,6 +18299,32 @@ }, "public_resource": { "type": "boolean" + }, + "secondary_storage": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "S3Storage", + "AzureBlobStorage", + "AzureWorkloadIdentity", + "S3AwsOidc" + ] + }, + "s3_resource_path": { + "type": "string" + }, + "azure_blob_resource_path": { + "type": "string" + }, + "public_resource": { + "type": "boolean" + } + } + } } } }, @@ -15709,6 +18453,31 @@ } } }, + "WorkspaceDeployUISettings": { + "type": "object", + "properties": { + "include_path": { + "type": "array", + "items": { + "type": "string" + } + }, + "include_type": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "script", + "flow", + "app", + "resource", + "variable", + "secret" + ] + } + } + } + }, "WorkspaceDefaultScripts": { "type": "object", "properties": { @@ -15873,7 +18642,10 @@ "mssql", "graphql", "nativets", - "bun" + "bun", + "php", + "rust", + "ansible" ] } }, @@ -15886,21 +18658,144 @@ "ConcurrencyGroup": { "type": "object", "properties": { - "concurrency_id": { + "concurrency_key": { "type": "string" }, - "job_uuids": { + "total_running": { + "type": "number" + } + }, + "required": [ + "concurrency_key", + "total_running" + ] + }, + "ExtendedJobs": { + "type": "object", + "properties": { + "jobs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Job" + } + }, + "obscured_jobs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ObscuredJob" + } + }, + "omitted_obscured_jobs": { + "description": "Obscured jobs omitted for security because of too specific filtering", + "type": "boolean" + } + }, + "required": [ + "jobs", + "obscured_jobs" + ] + }, + "ExportedUser": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "password_hash": { + "type": "string" + }, + "super_admin": { + "type": "boolean" + }, + "verified": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "company": { + "type": "string" + }, + "first_time_user": { + "type": "boolean" + }, + "username": { + "type": "string" + } + }, + "required": [ + "email", + "super_admin", + "verified", + "first_time_user" + ] + }, + "GlobalSetting": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "object" + } + }, + "required": [ + "name", + "value" + ] + }, + "Config": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "config": { + "type": "object" + } + }, + "required": [ + "name" + ] + }, + "ExportedInstanceGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "emails": { "type": "array", "items": { "type": "string" } + }, + "id": { + "type": "string" + }, + "scim_display_name": { + "type": "string" + }, + "external_id": { + "type": "string" } }, "required": [ - "concurrency_id", - "job_uuids" + "name" ] }, + "JobSearchHit": { + "type": "object", + "properties": { + "dancer": { + "type": "string" + } + } + }, "StaticTransform": { "type": "object", "properties": { @@ -15979,7 +18874,8 @@ "snowflake", "mssql", "graphql", - "nativets" + "nativets", + "php" ] }, "path": { @@ -16002,6 +18898,9 @@ }, "concurrency_time_window_s": { "type": "number" + }, + "custom_concurrency_key": { + "type": "string" } }, "required": [ @@ -16031,6 +18930,9 @@ "enum": [ "script" ] + }, + "tag_override": { + "type": "string" } }, "required": [ @@ -16087,6 +18989,31 @@ "expr" ] }, + "stop_after_all_iters_if": { + "type": "object", + "properties": { + "skip_if_stopped": { + "type": "boolean" + }, + "expr": { + "type": "string" + } + }, + "required": [ + "expr" + ] + }, + "skip_if": { + "type": "object", + "properties": { + "expr": { + "type": "string" + } + }, + "required": [ + "expr" + ] + }, "sleep": { "$ref": "#/components/schemas/InputTransform" }, @@ -16139,6 +19066,9 @@ }, "hide_cancel": { "type": "boolean" + }, + "continue_on_disapprove_timeout": { + "type": "boolean" } } }, @@ -16419,12 +19349,18 @@ "failure_module": { "$ref": "#/components/schemas/FlowModule" }, + "preprocessor_module": { + "$ref": "#/components/schemas/FlowModule" + }, "same_worker": { "type": "boolean" }, "concurrent_limit": { "type": "number" }, + "concurrency_key": { + "type": "string" + }, "concurrency_time_window_s": { "type": "number" }, @@ -16490,6 +19426,9 @@ "count": { "type": "integer" }, + "progress": { + "type": "integer" + }, "iterator": { "type": "object", "properties": { @@ -16509,6 +19448,12 @@ "type": "string" } }, + "flow_jobs_success": { + "type": "array", + "items": { + "type": "boolean" + } + }, "branch_chosen": { "type": "object", "properties": { @@ -16559,6 +19504,16 @@ "approver" ] } + }, + "failed_retries": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "skipped": { + "type": "boolean" } }, "required": [ @@ -16580,6 +19535,13 @@ "user_states": { "additionalProperties": true }, + "preprocessor_module": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStatusModule" + } + ] + }, "failure_module": { "allOf": [ { diff --git a/backend/windmill-api/openapi-deref.yaml b/backend/windmill-api/openapi-deref.yaml index 9654b10550..e2a0b00a85 100644 --- a/backend/windmill-api/openapi-deref.yaml +++ b/backend/windmill-api/openapi-deref.yaml @@ -1,6 +1,6 @@ openapi: 3.0.3 info: - version: 1.269.0 + version: 1.409.0 title: Windmill API contact: name: Windmill Team @@ -87,7 +87,7 @@ paths: - name: id in: path required: true - schema: &ref_24 + schema: &ref_28 type: integer responses: '200': @@ -221,44 +221,54 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: &ref_3 + schema: &ref_5 type: integer - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: &ref_4 + schema: &ref_6 type: integer - name: before - description: filter on created before (exclusive) timestamp + description: filter on started before (inclusive) timestamp in: query - schema: &ref_102 + schema: &ref_109 type: string format: date-time - name: after description: filter on created after (exclusive) timestamp in: query - schema: &ref_101 + schema: &ref_110 type: string format: date-time - name: username description: filter on exact username of user in: query - schema: &ref_103 + schema: &ref_119 type: string - name: operation description: filter on exact or prefix name of operation in: query - schema: &ref_104 + schema: &ref_120 + type: string + - name: operations + in: query + description: comma separated list of exact operations to include + schema: + type: string + - name: exclude_operations + in: query + description: comma separated list of operations to exclude + schema: type: string - name: resource description: filter on exact or prefix name of resource in: query - schema: &ref_105 + schema: &ref_121 type: string - name: action_kind description: filter on type of operation in: query - schema: &ref_106 + schema: &ref_122 type: string enum: - Create @@ -290,12 +300,12 @@ paths: application/json: schema: type: object - properties: &ref_119 + properties: &ref_136 email: type: string password: type: string - required: &ref_120 + required: &ref_137 - email - password responses: @@ -332,10 +342,10 @@ paths: text/plain: schema: type: string - /w/{workspace}/users/add: - post: - summary: create user (require admin privilege) - operationId: createUser + /w/{workspace}/users/{username}: + get: + summary: get user (require admin privilege) + operationId: getUser tags: - user - admin @@ -344,31 +354,56 @@ paths: in: path required: true schema: *ref_0 - requestBody: - description: new user - required: true - content: - application/json: - schema: - type: object - properties: &ref_121 - email: - type: string - username: - type: string - is_admin: - type: boolean - required: &ref_122 - - email - - username - - is_admin + - name: username + in: path + required: true + schema: + type: string responses: - '201': + '200': description: user created content: - text/plain: + application/json: schema: - type: string + type: object + properties: &ref_10 + email: + type: string + username: + type: string + is_admin: + type: boolean + is_super_admin: + type: boolean + created_at: + type: string + format: date-time + operator: + type: boolean + disabled: + type: boolean + groups: + type: array + items: + type: string + folders: + type: array + items: + type: string + folders_owners: + type: array + items: + type: string + required: &ref_11 + - email + - username + - is_admin + - is_super_admin + - created_at + - operator + - disabled + - folders + - folders_owners /w/{workspace}/users/update/{username}: post: summary: update user (require admin privilege) @@ -393,7 +428,7 @@ paths: application/json: schema: type: object - properties: &ref_123 + properties: &ref_138 is_admin: type: boolean operator: @@ -421,7 +456,7 @@ paths: - name: path in: path required: true - schema: &ref_17 + schema: &ref_21 type: string responses: '200': @@ -512,6 +547,8 @@ paths: properties: is_super_admin: type: boolean + name: + type: string responses: '200': description: user updated @@ -519,6 +556,74 @@ paths: text/plain: schema: type: string + /users/username_info/{email}: + get: + summary: global username info (require super admin) + operationId: globalUsernameInfo + tags: + - user + parameters: + - name: email + in: path + required: true + schema: + type: string + responses: + '200': + description: user renamed + content: + application/json: + schema: + type: object + properties: + username: + type: string + workspace_usernames: + type: array + items: + type: object + properties: + workspace_id: + type: string + username: + type: string + required: + - workspace_id + - username + required: + - username + - workspace_usernames + /users/rename/{email}: + post: + summary: global rename user (require super admin) + operationId: globalUserRename + tags: + - user + parameters: + - name: email + in: path + required: true + schema: + type: string + requestBody: + description: new username + required: true + content: + application/json: + schema: + type: object + properties: + new_username: + type: string + required: + - new_username + responses: + '200': + description: user renamed + content: + text/plain: + schema: + type: string /users/delete/{email}: delete: summary: global delete user (require super admin) @@ -538,6 +643,67 @@ paths: text/plain: schema: type: string + /users/overwrite: + post: + summary: global overwrite users (require super admin and EE) + operationId: globalUsersOverwrite + tags: + - user + requestBody: + description: List of users + required: true + content: + application/json: + schema: + type: array + items: + type: object + properties: &ref_3 + email: + type: string + password_hash: + type: string + super_admin: + type: boolean + verified: + type: boolean + name: + type: string + company: + type: string + first_time_user: + type: boolean + username: + type: string + required: &ref_4 + - email + - super_admin + - verified + - first_time_user + responses: + '200': + description: Success message + content: + text/plain: + schema: + type: string + /users/export: + get: + summary: global export users (require super admin and EE) + operationId: globalUsersExport + tags: + - user + responses: + '200': + description: exported users + content: + application/json: + schema: + type: array + items: + type: object + properties: *ref_3 + required: *ref_4 /w/{workspace}/users/delete/{username}: delete: summary: delete user (require admin privilege) @@ -577,7 +743,7 @@ paths: type: array items: type: object - properties: &ref_5 + properties: &ref_7 id: type: string name: @@ -586,7 +752,7 @@ paths: type: string domain: type: string - required: &ref_6 + required: &ref_8 - id - name - owner @@ -616,7 +782,7 @@ paths: application/json: schema: type: object - properties: &ref_151 + properties: &ref_172 email: type: string workspaces: @@ -634,7 +800,7 @@ paths: - id - name - username - required: &ref_152 + required: &ref_173 - email - workspaces /workspaces/list_as_superadmin: @@ -647,11 +813,11 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 responses: '200': description: workspaces @@ -661,8 +827,8 @@ paths: type: array items: type: object - properties: *ref_5 - required: *ref_6 + properties: *ref_7 + required: *ref_8 /workspaces/create: post: summary: create workspace @@ -676,17 +842,16 @@ paths: application/json: schema: type: object - properties: &ref_153 + properties: &ref_174 id: type: string name: type: string username: type: string - required: &ref_154 + required: &ref_175 - id - name - - username responses: '201': description: token created @@ -756,7 +921,7 @@ paths: - name: key in: path required: true - schema: &ref_7 + schema: &ref_9 type: string responses: '200': @@ -773,7 +938,7 @@ paths: - name: key in: path required: true - schema: *ref_7 + schema: *ref_9 requestBody: description: value set required: true @@ -850,6 +1015,33 @@ paths: text/plain: schema: type: string + /settings/test_critical_channels: + post: + summary: test critical channels + operationId: testCriticalChannels + tags: + - setting + requestBody: + description: test critical channel payload + required: true + content: + application/json: + schema: + type: array + items: + type: object + properties: + email: + type: string + slack_channel: + type: string + responses: + '200': + description: status + content: + text/plain: + schema: + type: string /settings/test_license_key: post: summary: test license key @@ -875,6 +1067,27 @@ paths: text/plain: schema: type: string + /settings/test_object_storage_config: + post: + summary: test object storage config + operationId: testObjectStorageConfig + tags: + - setting + requestBody: + description: test object storage config + required: true + content: + application/json: + schema: + type: object + additionalProperties: true + responses: + '200': + description: status + content: + text/plain: + schema: + type: string /settings/send_stats: post: summary: send stats @@ -888,6 +1101,110 @@ paths: text/plain: schema: type: string + /settings/latest_key_renewal_attempt: + get: + summary: get latest key renewal attempt + operationId: getLatestKeyRenewalAttempt + tags: + - setting + responses: + '200': + description: status + content: + application/json: + schema: + type: object + properties: + result: + type: string + attempted_at: + type: string + format: date-time + required: + - result + - attempted_at + nullable: true + /settings/renew_license_key: + post: + summary: renew license key + operationId: renewLicenseKey + tags: + - setting + parameters: + - name: license_key + in: query + required: false + schema: + type: string + responses: + '200': + description: status + content: + text/plain: + schema: + type: string + /settings/customer_portal: + post: + summary: create customer portal session + operationId: createCustomerPortalSession + tags: + - setting + parameters: + - name: license_key + in: query + required: false + schema: + type: string + responses: + '200': + description: url to portal + content: + text/plain: + schema: + type: string + /saml/test_metadata: + post: + summary: test metadata + operationId: testMetadata + tags: + - setting + requestBody: + description: test metadata + required: true + content: + application/json: + schema: + type: string + responses: + '200': + description: status + content: + text/plain: + schema: + type: string + /settings/list_global: + get: + summary: list global settings + operationId: listGlobalSettings + tags: + - setting + responses: + '200': + description: list of settings + content: + application/json: + schema: + type: array + items: + type: object + properties: &ref_214 + name: + type: string + value: + type: object + required: &ref_215 + - name + - value /users/email: get: summary: get current user email (if logged in) @@ -1026,7 +1343,7 @@ paths: application/json: schema: type: object - properties: &ref_10 + properties: &ref_12 email: type: string login_type: @@ -1042,7 +1359,9 @@ paths: type: string company: type: string - required: &ref_11 + username: + type: string + required: &ref_13 - email - login_type - super_admin @@ -1062,7 +1381,7 @@ paths: type: array items: type: object - properties: &ref_12 + properties: &ref_14 workspace_id: type: string email: @@ -1071,7 +1390,7 @@ paths: type: boolean operator: type: boolean - required: &ref_13 + required: &ref_15 - workspace_id - email - is_admin @@ -1094,49 +1413,8 @@ paths: application/json: schema: type: object - properties: &ref_8 - email: - type: string - username: - type: string - is_admin: - type: boolean - is_super_admin: - type: boolean - created_at: - type: string - format: date-time - operator: - type: boolean - disabled: - type: boolean - groups: - type: array - items: - type: string - folders: - type: array - items: - type: string - folders_owners: - type: array - items: - type: string - usage: - type: object - properties: &ref_118 - executions: - type: number - required: &ref_9 - - email - - username - - is_admin - - is_super_admin - - created_at - - operator - - disabled - - folders - - folders_owners + properties: *ref_10 + required: *ref_11 /users/accept_invite: post: summary: accept invite to workspace @@ -1157,7 +1435,6 @@ paths: type: string required: - workspace_id - - username responses: '200': description: status @@ -1257,7 +1534,6 @@ paths: - email - is_admin - operator - - username responses: '200': description: status @@ -1373,6 +1649,82 @@ paths: text/plain: schema: type: string + /w/{workspace}/workspaces/get_workspace_name: + get: + summary: get workspace name + operationId: getWorkspaceName + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: status + content: + text/plain: + schema: + type: string + /w/{workspace}/workspaces/change_workspace_name: + post: + summary: change workspace name + operationId: changeWorkspaceName + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + content: + application/json: + schema: + type: object + properties: + new_name: + type: string + required: + - username + responses: + '200': + description: status + content: + text/plain: + schema: + type: string + /w/{workspace}/workspaces/change_workspace_id: + post: + summary: change workspace id + operationId: changeWorkspaceId + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + content: + application/json: + schema: + type: object + properties: + new_id: + type: string + new_name: + type: string + required: + - username + responses: + '200': + description: status + content: + text/plain: + schema: + type: string /w/{workspace}/users/whois/{username}: get: summary: whois @@ -1396,8 +1748,8 @@ paths: application/json: schema: type: object - properties: *ref_8 - required: *ref_9 + properties: *ref_10 + required: *ref_11 /users/exists/{email}: get: summary: exists email @@ -1427,11 +1779,11 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 responses: '200': description: user @@ -1441,8 +1793,8 @@ paths: type: array items: type: object - properties: *ref_10 - required: *ref_11 + properties: *ref_12 + required: *ref_13 /w/{workspace}/workspaces/list_pending_invites: get: summary: list pending invites for a workspace @@ -1463,8 +1815,8 @@ paths: type: array items: type: object - properties: *ref_12 - required: *ref_13 + properties: *ref_14 + required: *ref_15 /w/{workspace}/workspaces/get_settings: get: summary: get settings @@ -1500,6 +1852,8 @@ paths: type: boolean plan: type: string + automatic_billing: + type: boolean customer_id: type: string webhook: @@ -1514,26 +1868,46 @@ paths: type: string error_handler_extra_args: type: object - additionalProperties: &ref_14 {} + additionalProperties: &ref_16 {} error_handler_muted_on_cancel: type: boolean large_file_storage: type: object - properties: &ref_15 + properties: &ref_17 type: type: string enum: - S3Storage - AzureBlobStorage + - AzureWorkloadIdentity + - S3AwsOidc s3_resource_path: type: string azure_blob_resource_path: type: string public_resource: type: boolean + secondary_storage: + type: object + additionalProperties: + type: object + properties: + type: + type: string + enum: + - S3Storage + - AzureBlobStorage + - AzureWorkloadIdentity + - S3AwsOidc + s3_resource_path: + type: string + azure_blob_resource_path: + type: string + public_resource: + type: boolean git_sync: type: object - properties: &ref_16 + properties: &ref_18 include_path: type: array items: @@ -1552,24 +1926,78 @@ paths: - secret - resourcetype - schedule + - user + - group repositories: type: array items: type: object - properties: &ref_174 + properties: &ref_198 script_path: type: string git_repo_resource_path: type: string use_individual_branch: type: boolean - required: &ref_175 + group_by_folder: + type: boolean + exclude_types_override: + type: array + items: + type: string + enum: + - script + - flow + - app + - folder + - resource + - variable + - secret + - resourcetype + - schedule + - user + - group + required: &ref_199 - script_path - git_repo_resource_path + deploy_ui: + type: object + properties: &ref_19 + include_path: + type: array + items: + type: string + include_type: + type: array + items: + type: string + enum: + - script + - flow + - app + - resource + - variable + - secret default_app: type: string + default_scripts: + type: object + properties: &ref_20 + order: + type: array + items: + type: string + hidden: + type: array + items: + type: string + default_script_content: + additionalProperties: + type: string required: - code_completion_enabled + - automatic_billing + - error_handler_muted_on_cancel /w/{workspace}/workspaces/get_deploy_to: get: summary: get deploy to @@ -1634,8 +2062,43 @@ paths: type: number seats: type: number + automatic_billing: + type: boolean required: - premium + - automatic_billing + /w/{workspace}/workspaces/set_automatic_billing: + post: + summary: set automatic billing + operationId: setAutomaticBilling + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + 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/edit_slack_command: post: summary: edit slack command @@ -1867,7 +2330,7 @@ paths: type: string error_handler_extra_args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 error_handler_muted_on_cancel: type: boolean responses: @@ -1898,7 +2361,7 @@ paths: properties: large_file_storage: type: object - properties: *ref_15 + properties: *ref_17 responses: '200': description: status @@ -1926,7 +2389,35 @@ paths: properties: git_sync_settings: type: object - properties: *ref_16 + properties: *ref_18 + responses: + '200': + description: status + content: + application/json: + schema: {} + /w/{workspace}/workspaces/edit_deploy_ui_config: + post: + summary: edit workspace deploy ui settings + operationId: editWorkspaceDeployUISettings + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: Workspace deploy UI settings + required: true + content: + application/json: + schema: + type: object + properties: + deploy_ui_settings: + type: object + properties: *ref_19 responses: '200': description: status @@ -1961,6 +2452,81 @@ paths: text/plain: schema: type: string + /w/{workspace}/workspaces/default_scripts: + post: + summary: edit default scripts for workspace + operationId: editDefaultScripts + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: Workspace default app + content: + application/json: + schema: + type: object + properties: *ref_20 + responses: + '200': + description: status + content: + text/plain: + schema: + type: string + get: + summary: get default scripts for workspace + operationId: get default scripts + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: status + content: + application/json: + schema: + type: object + properties: *ref_20 + /w/{workspace}/workspaces/set_environment_variable: + post: + summary: set environment variable + operationId: setEnvironmentVariable + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: Workspace default app + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + value: + type: string + required: + - name + responses: + '200': + description: status + content: + text/plain: + schema: + type: string /w/{workspace}/workspaces/encryption_key: get: summary: retrieves the encryption key for this workspace @@ -2004,6 +2570,8 @@ paths: properties: new_key: type: string + skip_reencrypt: + type: boolean required: - new_key responses: @@ -2052,7 +2620,25 @@ paths: application/json: schema: type: object - properties: *ref_15 + properties: *ref_17 + /w/{workspace}/workspaces/usage: + get: + summary: get usage + operationId: getWorkspaceUsage + tags: + - workspace + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: usage + content: + text/plain: + schema: + type: number /w/{workspace}/users/list: get: summary: list users @@ -2073,8 +2659,33 @@ paths: type: array items: type: object - properties: *ref_8 - required: *ref_9 + properties: *ref_10 + required: *ref_11 + /w/{workspace}/users/list_usage: + get: + summary: list users usage + operationId: listUsersUsage + tags: + - user + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: user + content: + application/json: + schema: + type: array + items: + type: object + properties: &ref_135 + email: + type: string + executions: + type: number /w/{workspace}/users/list_usernames: get: summary: list usernames @@ -2095,6 +2706,29 @@ paths: type: array items: type: string + /w/{workspace}/users/username_to_email/{username}: + get: + summary: get email from username + operationId: usernameToEmail + tags: + - user + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: username + in: path + required: true + schema: + type: string + responses: + '200': + description: email + content: + text/plain: + schema: + type: string /users/tokens/create: post: summary: create token @@ -2108,7 +2742,7 @@ paths: application/json: schema: type: object - properties: &ref_126 + properties: &ref_139 label: type: string expiration: @@ -2118,6 +2752,8 @@ paths: type: array items: type: string + workspace_id: + type: string responses: '201': description: token created @@ -2138,7 +2774,7 @@ paths: application/json: schema: type: object - properties: &ref_127 + properties: &ref_140 label: type: string expiration: @@ -2146,7 +2782,9 @@ paths: format: date-time impersonate_email: type: string - required: &ref_128 + workspace_id: + type: string + required: &ref_141 - impersonate_email responses: '201': @@ -2185,6 +2823,14 @@ paths: in: query schema: type: boolean + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 responses: '200': description: truncated token @@ -2194,7 +2840,7 @@ paths: type: array items: type: object - properties: &ref_124 + properties: &ref_38 label: type: string expiration: @@ -2212,7 +2858,9 @@ paths: type: array items: type: string - required: &ref_125 + email: + type: string + required: &ref_39 - token_prefix - created_at - last_used_at @@ -2261,7 +2909,7 @@ paths: application/json: schema: type: object - properties: &ref_131 + properties: &ref_144 path: type: string value: @@ -2274,7 +2922,10 @@ paths: type: integer is_oauth: type: boolean - required: &ref_132 + expires_at: + type: string + format: date-time + required: &ref_145 - path - value - is_secret @@ -2325,7 +2976,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: variable deleted @@ -2347,7 +2998,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 - name: already_encrypted in: query schema: @@ -2359,7 +3010,7 @@ paths: application/json: schema: type: object - properties: &ref_133 + properties: &ref_146 path: type: string value: @@ -2389,7 +3040,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 - name: decrypt_secret description: | ask to decrypt secret if this variable is secret @@ -2411,7 +3062,7 @@ paths: application/json: schema: type: object - properties: &ref_18 + properties: &ref_22 workspace_id: type: string path: @@ -2438,7 +3089,10 @@ paths: type: boolean is_refreshed: type: boolean - required: &ref_19 + expires_at: + type: string + format: date-time + required: &ref_23 - workspace_id - path - is_secret @@ -2457,7 +3111,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: variable @@ -2479,7 +3133,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: variable @@ -2498,6 +3152,18 @@ paths: in: path required: true schema: *ref_0 + - name: path_start + in: query + schema: + type: string + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 responses: '200': description: variable list @@ -2507,8 +3173,8 @@ paths: type: array items: type: object - properties: *ref_18 - required: *ref_19 + properties: *ref_22 + required: *ref_23 /w/{workspace}/variables/list_contextual: get: summary: list contextual variables @@ -2529,17 +3195,20 @@ paths: type: array items: type: object - properties: &ref_129 + properties: &ref_142 name: type: string value: type: string description: type: string - required: &ref_130 + is_custom: + type: boolean + required: &ref_143 - name - value - description + - is_custom /oauth/login_callback/{client_name}: post: security: [] @@ -2551,7 +3220,7 @@ paths: - name: client_name in: path required: true - schema: &ref_20 + schema: &ref_24 type: string requestBody: description: Partially filled script @@ -2614,6 +3283,34 @@ paths: text/plain: schema: type: string + /oauth/connect_slack_callback: + post: + summary: connect slack callback instance + operationId: connectSlackCallbackInstance + tags: + - oauth + requestBody: + description: code endpoint + required: true + content: + application/json: + schema: + type: object + properties: + code: + type: string + state: + type: string + required: + - code + - state + responses: + '200': + description: success message + content: + text/plain: + schema: + type: string /oauth/connect_callback/{client_name}: post: summary: connect callback @@ -2624,7 +3321,7 @@ paths: - name: client_name in: path required: true - schema: *ref_20 + schema: *ref_24 requestBody: description: code endpoint required: true @@ -2647,7 +3344,7 @@ paths: application/json: schema: type: object - properties: &ref_167 + properties: &ref_191 access_token: type: string expires_in: @@ -2658,7 +3355,7 @@ paths: type: array items: type: string - required: &ref_168 + required: &ref_192 - access_token /w/{workspace}/oauth/create_account: post: @@ -2709,7 +3406,7 @@ paths: - name: id in: path required: true - schema: &ref_21 + schema: &ref_25 type: integer requestBody: description: variable path @@ -2744,7 +3441,7 @@ paths: - name: id in: path required: true - schema: *ref_21 + schema: *ref_25 responses: '200': description: disconnected client @@ -2787,7 +3484,14 @@ paths: oauth: type: array items: - type: string + type: object + properties: + type: + type: string + display_name: + type: string + required: + - type saml: type: string required: @@ -2804,16 +3508,36 @@ paths: content: application/json: schema: - additionalProperties: - type: object - properties: - extra_params: - additionalProperties: - type: string - scopes: - type: array - items: - type: string + type: array + items: + type: string + /oauth/get_connect/{client}: + get: + summary: get oauth connect + operationId: getOAuthConnect + tags: + - oauth + parameters: + - name: client + description: client name + in: path + required: true + schema: + type: string + responses: + '200': + description: get + content: + application/json: + schema: + type: object + properties: + extra_params: + type: object + scopes: + type: array + items: + type: string /w/{workspace}/resources/create: post: summary: create resource @@ -2836,7 +3560,7 @@ paths: application/json: schema: type: object - properties: &ref_136 + properties: &ref_153 path: type: string value: {} @@ -2844,7 +3568,7 @@ paths: type: string resource_type: type: string - required: &ref_137 + required: &ref_154 - path - value - resource_type @@ -2869,7 +3593,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: resource deleted @@ -2891,7 +3615,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 requestBody: description: updated resource required: true @@ -2899,7 +3623,7 @@ paths: application/json: schema: type: object - properties: &ref_138 + properties: &ref_155 path: type: string description: @@ -2926,7 +3650,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 requestBody: description: updated resource required: true @@ -2957,7 +3681,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: resource @@ -2965,7 +3689,7 @@ paths: application/json: schema: type: object - properties: &ref_139 + properties: &ref_156 workspace_id: type: string path: @@ -2981,7 +3705,12 @@ paths: type: object additionalProperties: type: boolean - required: &ref_140 + created_by: + type: string + edited_at: + type: string + format: date-time + required: &ref_157 - path - resource_type - is_oauth @@ -2999,7 +3728,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 - name: job_id description: job id in: query @@ -3026,7 +3755,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: resource value @@ -3047,7 +3776,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: does resource exists @@ -3069,11 +3798,11 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 - name: resource_type description: resource_types to list from, separated by ',', in: query @@ -3084,6 +3813,10 @@ paths: in: query schema: type: string + - name: path_start + in: query + schema: + type: string responses: '200': description: resource list @@ -3093,7 +3826,7 @@ paths: type: array items: type: object - properties: &ref_141 + properties: &ref_158 workspace_id: type: string path: @@ -3119,7 +3852,12 @@ paths: type: boolean account: type: number - required: &ref_142 + created_by: + type: string + edited_at: + type: string + format: date-time + required: &ref_159 - path - resource_type - is_oauth @@ -3166,7 +3904,7 @@ paths: - name: name in: path required: true - schema: &ref_80 + schema: &ref_92 type: string responses: '200': @@ -3203,7 +3941,7 @@ paths: application/json: schema: type: object - properties: &ref_22 + properties: &ref_26 workspace_id: type: string name: @@ -3211,7 +3949,14 @@ paths: schema: {} description: type: string - required: &ref_23 + created_by: + type: string + edited_at: + type: string + format: date-time + format_extension: + type: string + required: &ref_27 - name responses: '201': @@ -3220,6 +3965,23 @@ paths: text/plain: schema: type: string + /w/{workspace}/resources/file_resource_type_to_file_ext_map: + get: + summary: get map from resource type to format extension + operationId: fileResourceTypeToFileExtMap + tags: + - resource + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: map from resource type to file ext + content: + application/json: + schema: {} /w/{workspace}/resources/type/delete/{path}: delete: summary: delete resource_type @@ -3234,7 +3996,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: resource_type deleted @@ -3256,7 +4018,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 requestBody: description: updated resource_type required: true @@ -3264,7 +4026,7 @@ paths: application/json: schema: type: object - properties: &ref_143 + properties: &ref_160 schema: {} description: type: string @@ -3289,7 +4051,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: resource_type deleted @@ -3297,8 +4059,8 @@ paths: application/json: schema: type: object - properties: *ref_22 - required: *ref_23 + properties: *ref_26 + required: *ref_27 /w/{workspace}/resources/type/exists/{path}: get: summary: does resource_type exists @@ -3313,7 +4075,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: does resource_type exist @@ -3341,8 +4103,8 @@ paths: type: array items: type: object - properties: *ref_22 - required: *ref_23 + properties: *ref_26 + required: *ref_27 /w/{workspace}/resources/type/listnames: get: summary: list resource_types names @@ -3481,7 +4243,7 @@ paths: - name: id in: path required: true - schema: *ref_24 + schema: *ref_28 responses: '200': description: flow @@ -3492,51 +4254,51 @@ paths: properties: flow: type: object - properties: &ref_43 + properties: &ref_50 summary: type: string description: type: string value: type: object - properties: &ref_50 + properties: &ref_58 modules: type: array items: type: object - properties: &ref_27 + properties: &ref_31 id: type: string value: - oneOf: &ref_206 + oneOf: &ref_239 - type: object - properties: &ref_192 + properties: &ref_223 input_transforms: type: object additionalProperties: - oneOf: &ref_25 + oneOf: &ref_29 - type: object - properties: &ref_188 + properties: &ref_219 value: {} type: type: string enum: - javascript - required: &ref_189 + required: &ref_220 - expr - type - type: object - properties: &ref_190 + properties: &ref_221 expr: type: string type: type: string enum: - javascript - required: &ref_191 + required: &ref_222 - expr - type - discriminator: &ref_26 + discriminator: &ref_30 propertyName: type mapping: static: '#/components/schemas/StaticTransform' @@ -3559,6 +4321,7 @@ paths: - mssql - graphql - nativets + - php path: type: string lock: @@ -3573,18 +4336,20 @@ paths: type: number concurrency_time_window_s: type: number - required: &ref_193 + custom_concurrency_key: + type: string + required: &ref_224 - type - content - language - input_transforms - type: object - properties: &ref_194 + properties: &ref_225 input_transforms: type: object additionalProperties: - oneOf: *ref_25 - discriminator: *ref_26 + oneOf: *ref_29 + discriminator: *ref_30 path: type: string hash: @@ -3593,40 +4358,42 @@ paths: type: string enum: - script - required: &ref_195 + tag_override: + type: string + required: &ref_226 - type - path - input_transforms - type: object - properties: &ref_196 + properties: &ref_227 input_transforms: type: object additionalProperties: - oneOf: *ref_25 - discriminator: *ref_26 + oneOf: *ref_29 + discriminator: *ref_30 path: type: string type: type: string enum: - flow - required: &ref_197 + required: &ref_228 - type - path - input_transforms - type: object - properties: &ref_198 + properties: &ref_229 modules: type: array items: type: object - properties: *ref_27 - required: &ref_28 + properties: *ref_31 + required: &ref_32 - value - id iterator: - oneOf: *ref_25 - discriminator: *ref_26 + oneOf: *ref_29 + discriminator: *ref_30 skip_failures: type: boolean type: @@ -3637,13 +4404,35 @@ paths: type: boolean parallelism: type: integer - required: &ref_199 + required: &ref_230 - modules - iterator - skip_failures - type - type: object - properties: &ref_200 + properties: &ref_231 + modules: + type: array + items: + type: object + properties: *ref_31 + required: *ref_32 + skip_failures: + type: boolean + type: + type: string + enum: + - forloopflow + parallel: + type: boolean + parallelism: + type: integer + required: &ref_232 + - modules + - skip_failures + - type + - type: object + properties: &ref_233 branches: type: array items: @@ -3657,8 +4446,8 @@ paths: type: array items: type: object - properties: *ref_27 - required: *ref_28 + properties: *ref_31 + required: *ref_32 required: - modules - expr @@ -3666,20 +4455,20 @@ paths: type: array items: type: object - properties: *ref_27 - required: *ref_28 + properties: *ref_31 + required: *ref_32 required: - modules type: type: string enum: - branchone - required: &ref_201 + required: &ref_234 - branches - default - type - type: object - properties: &ref_202 + properties: &ref_235 branches: type: array items: @@ -3693,8 +4482,8 @@ paths: type: array items: type: object - properties: *ref_27 - required: *ref_28 + properties: *ref_31 + required: *ref_32 required: - modules - expr @@ -3704,26 +4493,27 @@ paths: - branchall parallel: type: boolean - required: &ref_203 + required: &ref_236 - branches - type - type: object - properties: &ref_204 + properties: &ref_237 type: type: string enum: - identity flow: type: boolean - required: &ref_205 + required: &ref_238 - type - discriminator: &ref_207 + discriminator: &ref_240 propertyName: type mapping: rawscript: '#/components/schemas/RawScript' script: '#/components/schemas/PathScript' flow: '#/components/schemas/PathFlow' forloopflow: '#/components/schemas/ForloopFlow' + whileloopflow: '#/components/schemas/WhileloopFlow' branchone: '#/components/schemas/BranchOne' branchall: '#/components/schemas/BranchAll' identity: '#/components/schemas/Identity' @@ -3736,9 +4526,25 @@ paths: type: string required: - expr + stop_after_all_iters_if: + type: object + properties: + skip_if_stopped: + type: boolean + expr: + type: string + required: + - expr + skip_if: + type: object + properties: + expr: + type: string + required: + - expr sleep: - oneOf: *ref_25 - discriminator: *ref_26 + oneOf: *ref_29 + discriminator: *ref_30 cache_ttl: type: number timeout: @@ -3768,15 +4574,21 @@ paths: user_auth_required: type: boolean user_groups_required: - oneOf: *ref_25 - discriminator: *ref_26 + oneOf: *ref_29 + discriminator: *ref_30 self_approval_disabled: type: boolean + hide_cancel: + type: boolean + continue_on_disapprove_timeout: + type: boolean priority: type: number + continue_on_error: + type: boolean retry: type: object - properties: &ref_77 + properties: &ref_87 constant: type: object properties: @@ -3797,15 +4609,21 @@ paths: type: integer minimum: 0 maximum: 100 - required: *ref_28 + required: *ref_32 failure_module: type: object - properties: *ref_27 - required: *ref_28 + properties: *ref_31 + required: *ref_32 + preprocessor_module: + type: object + properties: *ref_31 + required: *ref_32 same_worker: type: boolean concurrent_limit: type: number + concurrency_key: + type: string concurrency_time_window_s: type: number skip_expr: @@ -3816,11 +4634,11 @@ paths: type: number early_return: type: string - required: &ref_51 + required: &ref_59 - modules schema: type: object - required: &ref_44 + required: &ref_51 - summary - value /apps/hub/list: @@ -3873,7 +4691,7 @@ paths: - name: id in: path required: true - schema: *ref_24 + schema: *ref_28 responses: '200': description: app @@ -3903,7 +4721,7 @@ paths: - name: path in: path required: true - schema: &ref_29 + schema: &ref_33 type: string responses: '200': @@ -3922,7 +4740,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: script details @@ -3993,7 +4811,7 @@ paths: type: number kind: name: kind - schema: &ref_30 + schema: &ref_34 type: string enum: - script @@ -4066,7 +4884,7 @@ paths: type: string kind: name: kind - schema: *ref_30 + schema: *ref_34 score: type: number required: @@ -4119,20 +4937,20 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 - name: order_desc description: order by desc order (default true) in: query - schema: &ref_41 + schema: &ref_48 type: boolean - name: created_by description: mask to filter exact matching user creator in: query - schema: &ref_42 + schema: &ref_49 type: string - name: path_start description: mask to filter matching starting path @@ -4182,7 +5000,7 @@ paths: description: > (default false) - show also the archived files. + show only the archived files. when multiple archived hash share the same path, only the ones with the latest create_at @@ -4193,6 +5011,20 @@ paths: in: query schema: type: boolean + - name: include_without_main + description: | + (default false) + include scripts without an exported main function + in: query + schema: + type: boolean + - name: include_draft_only + description: | + (default false) + include scripts that have no deployed version + in: query + schema: + type: boolean - name: is_template description: | (default regardless) @@ -4216,6 +5048,13 @@ paths: in: query schema: type: boolean + - name: with_deployment_msg + description: | + (default false) + include deployment message + in: query + schema: + type: boolean responses: '200': description: All scripts @@ -4225,7 +5064,7 @@ paths: type: array items: type: object - properties: &ref_31 + properties: &ref_35 workspace_id: type: string hash: @@ -4282,6 +5121,9 @@ paths: - graphql - nativets - bun + - php + - rust + - ansible kind: type: string enum: @@ -4306,6 +5148,8 @@ paths: type: integer concurrency_time_window_s: type: integer + concurrency_key: + type: string cache_ttl: type: number dedicated_worker: @@ -4320,7 +5164,15 @@ paths: type: integer delete_after_use: type: boolean - required: &ref_32 + visible_to_runner_only: + type: boolean + no_main_func: + type: boolean + codebase: + type: string + has_preprocessor: + type: boolean + required: &ref_36 - hash - path - summary @@ -4335,6 +5187,8 @@ paths: - language - kind - starred + - no_main_func + - has_preprocessor /w/{workspace}/scripts/list_paths: get: summary: list all scripts paths @@ -4416,7 +5270,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: draft deleted @@ -4442,7 +5296,7 @@ paths: application/json: schema: type: object - properties: &ref_34 + properties: &ref_40 path: type: string parent_hash: @@ -4475,6 +5329,9 @@ paths: - graphql - nativets - bun + - php + - rust + - ansible kind: type: string enum: @@ -4513,7 +5370,15 @@ paths: type: string concurrency_key: type: string - required: &ref_35 + visible_to_runner_only: + type: boolean + no_main_func: + type: boolean + codebase: + type: string + has_preprocessor: + type: boolean + required: &ref_41 - path - summary - description @@ -4540,7 +5405,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 requestBody: description: Workspace error handler enabled required: true @@ -4617,7 +5482,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: script archived @@ -4639,7 +5504,7 @@ paths: - name: hash in: path required: true - schema: &ref_33 + schema: &ref_37 type: string responses: '200': @@ -4648,8 +5513,8 @@ paths: application/json: schema: type: object - properties: *ref_31 - required: *ref_32 + properties: *ref_35 + required: *ref_36 /w/{workspace}/scripts/delete/h/{hash}: post: summary: delete script by hash (erase content but keep hash, require admin) @@ -4664,7 +5529,7 @@ paths: - name: hash in: path required: true - schema: *ref_33 + schema: *ref_37 responses: '200': description: script details @@ -4672,8 +5537,8 @@ paths: application/json: schema: type: object - properties: *ref_31 - required: *ref_32 + properties: *ref_35 + required: *ref_36 /w/{workspace}/scripts/delete/p/{path}: post: summary: delete all scripts at a given path (require admin) @@ -4688,7 +5553,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: script path @@ -4710,7 +5575,11 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 + - name: with_starred_info + in: query + schema: + type: boolean responses: '200': description: script details @@ -4718,8 +5587,70 @@ paths: application/json: schema: type: object - properties: *ref_31 - required: *ref_32 + properties: *ref_35 + required: *ref_36 + /w/{workspace}/scripts/get_triggers_count/{path}: + get: + summary: get triggers count of script + operationId: getTriggersCountOfScript + tags: + - script + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_33 + responses: + '200': + description: triggers count + content: + application/json: + schema: + type: object + properties: &ref_53 + primary_schedule: + type: object + properties: + schedule: + type: string + schedule_count: + type: number + http_routes_count: + type: number + webhook_count: + type: number + email_count: + type: number + /w/{workspace}/scripts/list_tokens/{path}: + get: + summary: get tokens with script scope + operationId: listTokensOfScript + tags: + - script + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_33 + responses: + '200': + description: tokens list + content: + application/json: + schema: + type: array + items: + type: object + properties: *ref_38 + required: *ref_39 /w/{workspace}/scripts/get/draft/{path}: get: summary: get script by path with draft @@ -4734,23 +5665,23 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: script details content: application/json: schema: - allOf: &ref_110 + allOf: &ref_126 - type: object - properties: *ref_34 - required: *ref_35 + properties: *ref_40 + required: *ref_41 - type: object properties: draft: type: object - properties: *ref_34 - required: *ref_35 + properties: *ref_40 + required: *ref_41 hash: type: string required: @@ -4769,7 +5700,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: script history @@ -4779,12 +5710,12 @@ paths: type: array items: type: object - properties: &ref_111 + properties: &ref_127 script_hash: type: string deployment_msg: type: string - required: &ref_112 + required: &ref_128 - script_hash /w/{workspace}/scripts/history_update/h/{hash}/p/{path}: post: @@ -4800,11 +5731,11 @@ paths: - name: hash in: path required: true - schema: *ref_33 + schema: *ref_37 - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 requestBody: description: Script deployment message required: true @@ -4836,7 +5767,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: script content @@ -4860,12 +5791,12 @@ paths: - name: token in: path required: true - schema: &ref_96 + schema: &ref_115 type: string - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: script content @@ -4887,7 +5818,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: does it exists @@ -4909,7 +5840,11 @@ paths: - name: hash in: path required: true - schema: *ref_33 + schema: *ref_37 + - name: with_starred_info + in: query + schema: + type: boolean responses: '200': description: script details @@ -4917,8 +5852,8 @@ paths: application/json: schema: type: object - properties: *ref_31 - required: *ref_32 + properties: *ref_35 + required: *ref_36 /w/{workspace}/scripts/raw/h/{path}: get: summary: raw script by hash @@ -4933,7 +5868,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: script content @@ -4955,7 +5890,7 @@ paths: - name: hash in: path required: true - schema: *ref_33 + schema: *ref_37 responses: '200': description: script details @@ -4982,7 +5917,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 - name: scheduled_for description: when to schedule this job (leave empty for immediate run) in: query @@ -4994,18 +5929,30 @@ paths: in: query schema: type: integer + - name: skip_preprocessor + description: skip the preprocessor + in: query + schema: + type: boolean - name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: &ref_36 + schema: &ref_42 type: string format: uuid - name: tag description: Override the tag to use in: query - schema: &ref_38 + schema: &ref_44 + type: string + - name: cache_ttl + description: >- + Override the cache time to live (in seconds). Can not be used to + disable caching, only override with a new cache ttl + in: query + schema: &ref_45 type: string - name: job_id description: >- @@ -5014,7 +5961,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: &ref_37 + schema: &ref_43 type: string format: uuid - name: invisible_to_owner @@ -5029,7 +5976,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 responses: '201': description: job created @@ -5052,13 +5999,13 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 - name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -5066,7 +6013,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -5075,14 +6022,14 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: &ref_39 + schema: &ref_46 type: string - name: queue_limit description: > The maximum size of the queue for which the request would get rejected if that job would push it above that limit in: query - schema: &ref_40 + schema: &ref_47 type: string requestBody: description: script args @@ -5091,7 +6038,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 responses: '200': description: job result @@ -5112,17 +6059,23 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 - name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 - name: tag description: Override the tag to use in: query - schema: *ref_38 + schema: *ref_44 + - name: cache_ttl + description: >- + Override the cache time to live (in seconds). Can not be used to + disable caching, only override with a new cache ttl + in: query + schema: *ref_45 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -5130,7 +6083,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -5139,13 +6092,13 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 - name: queue_limit description: > The maximum size of the queue for which the request would get rejected if that job would push it above that limit in: query - schema: *ref_40 + schema: *ref_47 requestBody: description: script args required: true @@ -5153,7 +6106,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 responses: '200': description: job result @@ -5173,17 +6126,23 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 - name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 - name: tag description: Override the tag to use in: query - schema: *ref_38 + schema: *ref_44 + - name: cache_ttl + description: >- + Override the cache time to live (in seconds). Can not be used to + disable caching, only override with a new cache ttl + in: query + schema: *ref_45 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -5191,7 +6150,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -5200,13 +6159,13 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 - name: queue_limit description: > The maximum size of the queue for which the request would get rejected if that job would push it above that limit in: query - schema: *ref_40 + schema: *ref_47 - name: payload description: > The base64 encoded payload that has been encoded as a JSON. e.g how @@ -5214,7 +6173,7 @@ paths: `encodeURIComponent(btoa(JSON.stringify({a: 2})))` in: query - schema: &ref_76 + schema: &ref_86 type: string responses: '200': @@ -5236,7 +6195,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -5245,13 +6204,13 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 - name: queue_limit description: > The maximum size of the queue for which the request would get rejected if that job would push it above that limit in: query - schema: *ref_40 + schema: *ref_47 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -5259,7 +6218,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 requestBody: description: script args required: true @@ -5267,7 +6226,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 responses: '200': description: job result @@ -5288,7 +6247,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -5297,13 +6256,13 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 - name: queue_limit description: > The maximum size of the queue for which the request would get rejected if that job would push it above that limit in: query - schema: *ref_40 + schema: *ref_47 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -5311,7 +6270,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 requestBody: description: script args required: true @@ -5319,7 +6278,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 responses: '200': description: job result @@ -5414,19 +6373,19 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 - name: order_desc description: order by desc order (default true) in: query - schema: *ref_41 + schema: *ref_48 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_42 + schema: *ref_49 - name: path_start description: mask to filter matching starting path in: query @@ -5441,7 +6400,7 @@ paths: description: > (default false) - show also the archived files. + show only the archived files. when multiple archived hash share the same path, only the ones with the latest create_at @@ -5457,6 +6416,20 @@ paths: in: query schema: type: boolean + - name: include_draft_only + description: | + (default false) + include items that have no deployed version + in: query + schema: + type: boolean + - name: with_deployment_msg + description: | + (default false) + include deployment message + in: query + schema: + type: boolean responses: '200': description: All flow @@ -5466,12 +6439,12 @@ paths: type: array items: allOf: - - allOf: &ref_45 + - allOf: &ref_52 - type: object - properties: *ref_43 - required: *ref_44 + properties: *ref_50 + required: *ref_51 - type: object - properties: &ref_155 + properties: &ref_177 workspace_id: type: string path: @@ -5485,8 +6458,8 @@ paths: type: boolean extra_perms: type: object - additionalProperties: - type: boolean + additionalProperties: &ref_176 + type: boolean starred: type: boolean draft_only: @@ -5501,7 +6474,9 @@ paths: type: boolean timeout: type: number - required: &ref_156 + visible_to_runner_only: + type: boolean + required: &ref_178 - path - edited_by - edited_at @@ -5513,6 +6488,109 @@ paths: type: boolean draft_only: type: boolean + /w/{workspace}/flows/history/p/{path}: + get: + summary: get flow history by path + operationId: getFlowHistory + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_33 + tags: + - flow + responses: + '200': + description: Flow history + content: + application/json: + schema: + type: array + items: + type: object + properties: &ref_189 + id: + type: integer + created_at: + type: string + format: date-time + deployment_msg: + type: string + required: &ref_190 + - id + - created_at + /w/{workspace}/flows/get/v/{version}/p/{path}: + get: + summary: get flow version + operationId: getFlowVersion + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - type: string + name: version + in: path + required: true + schema: + type: number + - name: path + in: path + required: true + schema: *ref_33 + tags: + - flow + responses: + '200': + description: flow details + content: + application/json: + schema: + allOf: *ref_52 + /w/{workspace}/flows/history_update/v/{version}/p/{path}: + post: + summary: update flow history + operationId: updateFlowHistory + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - type: string + name: version + in: path + required: true + schema: + type: number + - name: path + in: path + required: true + schema: *ref_33 + requestBody: + description: Flow deployment message + required: true + content: + application/json: + schema: + type: object + properties: + deployment_msg: + type: string + required: + - deployment_msg + tags: + - flow + responses: + '200': + description: success + content: + text/plain: + schema: + type: string /w/{workspace}/flows/get/{path}: get: summary: get flow by path @@ -5527,14 +6605,67 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 + - name: with_starred_info + in: query + schema: + type: boolean responses: '200': description: flow details content: application/json: schema: - allOf: *ref_45 + allOf: *ref_52 + /w/{workspace}/flows/get_triggers_count/{path}: + get: + summary: get triggers count of flow + operationId: getTriggersCountOfFlow + tags: + - flow + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_33 + responses: + '200': + description: triggers count + content: + application/json: + schema: + type: object + properties: *ref_53 + /w/{workspace}/flows/list_tokens/{path}: + get: + summary: get tokens with flow scope + operationId: listTokensOfFlow + tags: + - flow + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_33 + responses: + '200': + description: tokens list + content: + application/json: + schema: + type: array + items: + type: object + properties: *ref_38 + required: *ref_39 /w/{workspace}/flows/toggle_workspace_error_handler/{path}: post: summary: Toggle ON and OFF the workspace error handler for a given flow @@ -5549,7 +6680,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 requestBody: description: Workspace error handler enabled required: true @@ -5581,7 +6712,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: flow details with draft @@ -5589,11 +6720,11 @@ paths: application/json: schema: allOf: - - allOf: *ref_45 + - allOf: *ref_52 - type: object properties: draft: - allOf: *ref_45 + allOf: *ref_52 /w/{workspace}/flows/exists/{path}: get: summary: exists flow by path @@ -5608,7 +6739,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: flow details @@ -5634,10 +6765,10 @@ paths: application/json: schema: allOf: - - allOf: &ref_46 + - allOf: &ref_54 - type: object - properties: *ref_43 - required: *ref_44 + properties: *ref_50 + required: *ref_51 - type: object properties: path: @@ -5652,6 +6783,8 @@ paths: type: boolean timeout: type: number + visible_to_runner_only: + type: boolean required: - path - type: object @@ -5681,7 +6814,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 requestBody: description: Partially filled flow required: true @@ -5689,7 +6822,7 @@ paths: application/json: schema: allOf: - - allOf: *ref_46 + - allOf: *ref_54 - type: object properties: deployment_message: @@ -5715,7 +6848,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 requestBody: description: archiveFlow required: true @@ -5747,7 +6880,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: flow delete @@ -5755,61 +6888,6 @@ paths: text/plain: schema: type: string - /w/{workspace}/flows/input_history/p/{path}: - get: - summary: list inputs for previous completed flow jobs - operationId: getFlowInputHistoryByPath - tags: - - flow - parameters: - - name: workspace - in: path - required: true - schema: *ref_0 - - name: path - in: path - required: true - schema: *ref_29 - - name: page - description: which page to return (start at 1, default 1) - in: query - schema: *ref_3 - - name: per_page - description: number of items to return for a given page (default 30, max 100) - in: query - schema: *ref_4 - responses: - '200': - description: input history for completed jobs with this flow path - content: - application/json: - schema: - type: array - items: - type: object - properties: &ref_87 - id: - type: string - name: - type: string - args: - type: object - created_by: - type: string - created_at: - type: string - format: date-time - is_public: - type: boolean - success: - type: boolean - required: &ref_88 - - id - - name - - args - - created_by - - created_at - - is_public /w/{workspace}/raw_apps/list: get: summary: list all raw apps @@ -5824,19 +6902,19 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 - name: order_desc description: order by desc order (default true) in: query - schema: *ref_41 + schema: *ref_48 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_42 + schema: *ref_49 - name: path_start description: mask to filter matching starting path in: query @@ -5863,7 +6941,7 @@ paths: type: array items: type: object - properties: &ref_162 + properties: &ref_184 workspace_id: type: string path: @@ -5881,7 +6959,7 @@ paths: edited_at: type: string format: date-time - required: &ref_163 + required: &ref_185 - workspace_id - path - summary @@ -5902,7 +6980,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: app exists @@ -5924,12 +7002,12 @@ paths: - name: version in: path required: true - schema: &ref_95 + schema: &ref_114 type: number - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: app details @@ -5978,19 +7056,19 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 - name: order_desc description: order by desc order (default true) in: query - schema: *ref_41 + schema: *ref_48 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_42 + schema: *ref_49 - name: path_start description: mask to filter matching starting path in: query @@ -6008,6 +7086,20 @@ paths: in: query schema: type: boolean + - name: include_draft_only + description: | + (default false) + include items that have no deployed version + in: query + schema: + type: boolean + - name: with_deployment_msg + description: | + (default false) + include deployment message + in: query + schema: + type: boolean responses: '200': description: All apps @@ -6017,7 +7109,7 @@ paths: type: array items: type: object - properties: &ref_160 + properties: &ref_182 id: type: integer workspace_id: @@ -6043,7 +7135,7 @@ paths: - viewer - publisher - anonymous - required: &ref_161 + required: &ref_183 - id - workspace_id - path @@ -6078,11 +7170,15 @@ paths: type: string policy: type: object - properties: &ref_47 + properties: &ref_55 triggerables: type: object additionalProperties: type: object + triggerables_v2: + type: object + additionalProperties: + type: object execution_mode: type: string enum: @@ -6123,7 +7219,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: app exists @@ -6145,7 +7241,11 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 + - name: with_starred_info + in: query + schema: + type: boolean responses: '200': description: app details @@ -6153,7 +7253,7 @@ paths: application/json: schema: type: object - properties: &ref_48 + properties: &ref_56 id: type: integer workspace_id: @@ -6171,10 +7271,11 @@ paths: created_at: type: string format: date-time - value: {} + value: + type: object policy: type: object - properties: *ref_47 + properties: *ref_55 execution_mode: type: string enum: @@ -6185,7 +7286,7 @@ paths: type: object additionalProperties: type: boolean - required: &ref_49 + required: &ref_57 - id - workspace_id - path @@ -6211,17 +7312,17 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: app details with draft content: application/json: schema: - allOf: &ref_164 + allOf: &ref_186 - type: object - properties: *ref_48 - required: *ref_49 + properties: *ref_56 + required: *ref_57 - type: object properties: draft_only: @@ -6241,7 +7342,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 responses: '200': description: app history @@ -6251,12 +7352,12 @@ paths: type: array items: type: object - properties: &ref_165 + properties: &ref_187 version: type: integer deployment_msg: type: string - required: &ref_166 + required: &ref_188 - version /w/{workspace}/apps/history_update/a/{id}/v/{version}: post: @@ -6272,11 +7373,11 @@ paths: - name: id in: path required: true - schema: *ref_24 + schema: *ref_28 - name: version in: path required: true - schema: &ref_97 + schema: &ref_116 type: integer requestBody: description: App deployment message @@ -6309,7 +7410,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: app details @@ -6317,8 +7418,8 @@ paths: application/json: schema: type: object - properties: *ref_48 - required: *ref_49 + properties: *ref_56 + required: *ref_57 /w/{workspace}/apps_u/public_resource/{path}: get: summary: get public resource @@ -6333,7 +7434,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: resource value @@ -6354,7 +7455,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: app secret @@ -6376,7 +7477,7 @@ paths: - name: id in: path required: true - schema: *ref_24 + schema: *ref_28 responses: '200': description: app details @@ -6384,8 +7485,8 @@ paths: application/json: schema: type: object - properties: *ref_48 - required: *ref_49 + properties: *ref_56 + required: *ref_57 /w/{workspace}/raw_apps/create: post: summary: create raw app @@ -6436,7 +7537,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 requestBody: description: updateraw app required: true @@ -6472,7 +7573,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: app deleted @@ -6494,7 +7595,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: app deleted @@ -6516,7 +7617,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 requestBody: description: update app required: true @@ -6532,7 +7633,7 @@ paths: value: {} policy: type: object - properties: *ref_47 + properties: *ref_55 deployment_message: type: string responses: @@ -6556,7 +7657,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 requestBody: description: update app required: true @@ -6579,6 +7680,8 @@ paths: type: string path: type: string + lock: + type: string cache_ttl: type: integer required: @@ -6586,6 +7689,12 @@ paths: - language force_viewer_static_fields: type: object + force_viewer_one_of_fields: + type: object + force_viewer_allow_user_resources: + type: array + items: + type: string required: - args - component @@ -6610,7 +7719,7 @@ paths: - name: path in: path required: true - schema: *ref_29 + schema: *ref_33 - name: scheduled_for description: when to schedule this job (leave empty for immediate run) in: query @@ -6622,16 +7731,21 @@ paths: in: query schema: type: integer + - name: skip_preprocessor + description: skip the preprocessor + in: query + schema: + type: boolean - name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 - name: tag description: Override the tag to use in: query - schema: *ref_38 + schema: *ref_44 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -6639,7 +7753,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -6648,7 +7762,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 - name: invisible_to_owner description: make the run invisible to the the flow owner (default false) in: query @@ -6661,7 +7775,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 responses: '201': description: job created @@ -6684,7 +7798,7 @@ paths: - name: id in: path required: true - schema: &ref_73 + schema: &ref_83 type: string format: uuid - name: step_id @@ -6717,11 +7831,11 @@ paths: The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 - name: tag description: Override the tag to use in: query - schema: *ref_38 + schema: *ref_44 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -6729,7 +7843,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -6738,7 +7852,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 - name: invisible_to_owner description: make the run invisible to the the flow owner (default false) in: query @@ -6751,7 +7865,7 @@ paths: application/json: schema: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 responses: '201': description: job created @@ -6774,7 +7888,7 @@ paths: - name: hash in: path required: true - schema: *ref_33 + schema: *ref_37 - name: scheduled_for description: when to schedule this job (leave empty for immediate run) in: query @@ -6786,16 +7900,27 @@ paths: in: query schema: type: integer + - name: skip_preprocessor + description: skip the preprocessor + in: query + schema: + type: boolean - name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 - name: tag description: Override the tag to use in: query - schema: *ref_38 + schema: *ref_44 + - name: cache_ttl + description: >- + Override the cache time to live (in seconds). Can not be used to + disable caching, only override with a new cache ttl + in: query + schema: *ref_45 - name: job_id description: >- The job id to assign to the created job. if missing, job is chosen @@ -6803,7 +7928,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 - name: include_header description: > List of headers's keys (separated with ',') whove value are added to @@ -6812,7 +7937,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 - name: invisible_to_owner description: make the run invisible to the the script owner (default false) in: query @@ -6852,7 +7977,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 - name: invisible_to_owner description: make the run invisible to the the script owner (default false) in: query @@ -6865,7 +7990,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 requestBody: description: preview required: true @@ -6873,14 +7998,14 @@ paths: application/json: schema: type: object - properties: &ref_134 + properties: &ref_147 content: type: string path: type: string args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 language: type: string enum: @@ -6897,6 +8022,9 @@ paths: - graphql - nativets - bun + - php + - rust + - ansible tag: type: string kind: @@ -6909,7 +8037,49 @@ paths: type: boolean lock: type: string - required: &ref_135 + required: &ref_148 + - args + responses: + '201': + description: job created + content: + text/plain: + schema: + type: string + format: uuid + /w/{workspace}/jobs/workflow_as_code/{job_id}/{entrypoint}: + post: + summary: run code-workflow task + operationId: runCodeWorkflowTask + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: job_id + in: path + required: true + schema: + type: string + - name: entrypoint + in: path + required: true + schema: + type: string + requestBody: + description: preview + required: true + content: + application/json: + schema: + type: object + properties: &ref_149 + args: + type: object + additionalProperties: *ref_16 + required: &ref_150 - args responses: '201': @@ -6942,7 +8112,7 @@ paths: type: array items: type: object - properties: &ref_184 + properties: &ref_208 raw_code: type: string path: @@ -6963,7 +8133,10 @@ paths: - graphql - nativets - bun - required: &ref_185 + - php + - rust + - ansible + required: &ref_209 - raw_code - path - language @@ -7003,7 +8176,7 @@ paths: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 - name: invisible_to_owner description: make the run invisible to the the script owner (default false) in: query @@ -7016,7 +8189,7 @@ paths: queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 requestBody: description: preview required: true @@ -7024,21 +8197,21 @@ paths: application/json: schema: type: object - properties: &ref_157 + properties: &ref_179 value: type: object - properties: *ref_50 - required: *ref_51 + properties: *ref_58 + required: *ref_59 path: type: string args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 tag: type: string restarted_from: type: object - properties: &ref_159 + properties: &ref_181 flow_job_id: type: string format: uuid @@ -7046,7 +8219,7 @@ paths: type: string branch_or_iteration_n: type: integer - required: &ref_158 + required: &ref_180 - value - content - args @@ -7072,95 +8245,103 @@ paths: - name: order_desc description: order by desc order (default true) in: query - schema: *ref_41 + schema: *ref_48 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_42 + schema: *ref_49 - name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 - name: script_path_exact description: mask to filter exact matching path in: query - schema: &ref_54 + schema: &ref_62 type: string - name: script_path_start description: mask to filter matching starting path in: query - schema: &ref_55 + schema: &ref_63 type: string - name: schedule_path description: mask to filter by schedule path in: query - schema: &ref_56 + schema: &ref_64 type: string - name: script_hash description: mask to filter exact matching path in: query - schema: &ref_57 + schema: &ref_65 type: string - name: started_before description: filter on started before (inclusive) timestamp in: query - schema: &ref_58 + schema: &ref_66 type: string format: date-time - name: started_after description: filter on started after (exclusive) timestamp in: query - schema: &ref_59 + schema: &ref_67 type: string format: date-time - name: success description: filter on successful jobs in: query - schema: &ref_60 + schema: &ref_68 type: boolean - name: scheduled_for_before_now description: filter on jobs scheduled_for before now (hence waitinf for a worker) in: query - schema: &ref_68 + schema: &ref_69 type: boolean - name: job_kinds description: >- filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: &ref_61 + schema: &ref_70 type: string - name: suspended description: filter on suspended jobs in: query - schema: &ref_100 + schema: &ref_71 type: boolean - name: running description: filter on running jobs in: query - schema: &ref_67 + schema: &ref_72 type: boolean - name: args description: >- filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: &ref_62 + schema: &ref_73 type: string - name: result description: >- filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: &ref_63 + schema: &ref_74 type: string - name: tag description: filter on jobs with a given tag/worker group in: query - schema: &ref_64 + schema: &ref_75 type: string + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 - name: all_workspaces description: >- get jobs from all workspaces (only valid if request come from the @@ -7168,6 +8349,11 @@ paths: in: query schema: type: boolean + - name: is_not_schedule + description: is not a scheduled job + in: query + schema: + type: boolean responses: '200': description: All queued jobs @@ -7177,7 +8363,7 @@ paths: type: array items: type: object - properties: &ref_71 + properties: &ref_81 workspace_id: type: string id: @@ -7205,7 +8391,7 @@ paths: type: string args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 logs: type: string raw_code: @@ -7244,14 +8430,14 @@ paths: by extension its DT_TOKEN. flow_status: type: object - properties: &ref_65 + properties: &ref_76 step: type: integer modules: type: array items: type: object - properties: &ref_52 + properties: &ref_60 type: type: string enum: @@ -7268,6 +8454,8 @@ paths: format: uuid count: type: integer + progress: + type: integer iterator: type: object properties: @@ -7281,6 +8469,10 @@ paths: type: array items: type: string + flow_jobs_success: + type: array + items: + type: boolean branch_chosen: type: object properties: @@ -7315,13 +8507,27 @@ paths: required: - resume_id - approver - required: &ref_53 + failed_retries: + type: array + items: + type: string + format: uuid + skipped: + type: boolean + required: &ref_61 - type + user_states: + additionalProperties: true + preprocessor_module: + allOf: + - type: object + properties: *ref_60 + required: *ref_61 failure_module: allOf: - type: object - properties: *ref_52 - required: *ref_53 + properties: *ref_60 + required: *ref_61 - type: object properties: parent_module: @@ -7336,14 +8542,14 @@ paths: items: type: string format: uuid - required: &ref_66 + required: &ref_77 - step - modules - failure_module raw_flow: type: object - properties: *ref_50 - required: *ref_51 + properties: *ref_58 + required: *ref_59 is_flow_step: type: boolean language: @@ -7362,6 +8568,9 @@ paths: - graphql - nativets - bun + - php + - rust + - ansible email: type: string visible_to_owner: @@ -7372,7 +8581,13 @@ paths: type: string priority: type: integer - required: &ref_72 + self_wait_time_ms: + type: number + aggregate_wait_time_ms: + type: number + suspend: + type: number + required: &ref_82 - id - running - canceled @@ -7410,6 +8625,8 @@ paths: properties: database_length: type: integer + suspended: + type: integer required: - database_length /w/{workspace}/jobs/completed/count: @@ -7435,10 +8652,10 @@ paths: type: integer required: - database_length - /w/{workspace}/jobs/queue/cancel_all: - post: - summary: cancel all jobs - operationId: cancelAll + /w/{workspace}/jobs/queue/list_filtered_uuids: + get: + summary: get the ids of all jobs matching the given filters + operationId: listFilteredUuids tags: - job parameters: @@ -7446,6 +8663,136 @@ paths: in: path required: true schema: *ref_0 + - name: order_desc + description: order by desc order (default true) + in: query + schema: *ref_48 + - name: created_by + description: mask to filter exact matching user creator + in: query + schema: *ref_49 + - name: parent_job + description: >- + The parent job that is at the origin and responsible for the + execution of this script if any + in: query + schema: *ref_42 + - name: script_path_exact + description: mask to filter exact matching path + in: query + schema: *ref_62 + - name: script_path_start + description: mask to filter matching starting path + in: query + schema: *ref_63 + - name: schedule_path + description: mask to filter by schedule path + in: query + schema: *ref_64 + - name: script_hash + description: mask to filter exact matching path + in: query + schema: *ref_65 + - name: started_before + description: filter on started before (inclusive) timestamp + in: query + schema: *ref_66 + - name: started_after + description: filter on started after (exclusive) timestamp + in: query + schema: *ref_67 + - name: success + description: filter on successful jobs + in: query + schema: *ref_68 + - name: scheduled_for_before_now + description: filter on jobs scheduled_for before now (hence waitinf for a worker) + in: query + schema: *ref_69 + - name: job_kinds + description: >- + filter on job kind (values 'preview', 'script', 'dependencies', + 'flow') separated by, + in: query + schema: *ref_70 + - name: suspended + description: filter on suspended jobs + in: query + schema: *ref_71 + - name: running + description: filter on running jobs + in: query + schema: *ref_72 + - name: args + description: >- + filter on jobs containing those args as a json subset (@> in + postgres) + in: query + schema: *ref_73 + - name: result + description: >- + filter on jobs containing those result as a json subset (@> in + postgres) + in: query + schema: *ref_74 + - name: tag + description: filter on jobs with a given tag/worker group + in: query + schema: *ref_75 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - name: concurrency_key + in: query + required: false + schema: + type: string + - 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/cancel_selection: + post: + summary: cancel jobs based on the given uuids + operationId: cancelSelection + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: uuids of the jobs to cancel + required: true + content: + application/json: + schema: + type: array + items: + type: string responses: '200': description: uuids of canceled jobs @@ -7469,67 +8816,83 @@ paths: - name: order_desc description: order by desc order (default true) in: query - schema: *ref_41 + schema: *ref_48 - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_42 + schema: *ref_49 + - name: label + description: >- + mask to filter exact matching job's label (job labels are completed + jobs with as a result an object containing a string in the array at + key 'wm_labels') + in: query + schema: &ref_78 + type: string - name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 - name: script_path_exact description: mask to filter exact matching path in: query - schema: *ref_54 + schema: *ref_62 - name: script_path_start description: mask to filter matching starting path in: query - schema: *ref_55 + schema: *ref_63 - name: schedule_path description: mask to filter by schedule path in: query - schema: *ref_56 + schema: *ref_64 - name: script_hash description: mask to filter exact matching path in: query - schema: *ref_57 + schema: *ref_65 - name: started_before description: filter on started before (inclusive) timestamp in: query - schema: *ref_58 + schema: *ref_66 - name: started_after description: filter on started after (exclusive) timestamp in: query - schema: *ref_59 + schema: *ref_67 - name: success description: filter on successful jobs in: query - schema: *ref_60 + schema: *ref_68 - name: job_kinds description: >- filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: *ref_61 + schema: *ref_70 - name: args description: >- filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: *ref_62 + schema: *ref_73 - name: result description: >- filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: *ref_63 + schema: *ref_74 - name: tag description: filter on jobs with a given tag/worker group in: query - schema: *ref_64 + schema: *ref_75 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 - name: is_skipped description: is the job skipped in: query @@ -7540,6 +8903,16 @@ paths: in: query schema: type: boolean + - name: has_null_parent + description: has null parent + in: query + schema: + type: boolean + - name: is_not_schedule + description: is not a scheduled job + in: query + schema: + type: boolean responses: '200': description: All completed jobs @@ -7549,7 +8922,7 @@ paths: type: array items: type: object - properties: &ref_69 + properties: &ref_79 workspace_id: type: string id: @@ -7576,7 +8949,7 @@ paths: type: string args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 result: {} logs: type: string @@ -7615,12 +8988,12 @@ paths: by extension its DT_TOKEN. flow_status: type: object - properties: *ref_65 - required: *ref_66 + properties: *ref_76 + required: *ref_77 raw_flow: type: object - properties: *ref_50 - required: *ref_51 + properties: *ref_58 + required: *ref_59 is_flow_step: type: boolean language: @@ -7639,6 +9012,9 @@ paths: - graphql - nativets - bun + - php + - rust + - ansible is_skipped: type: boolean email: @@ -7651,7 +9027,15 @@ paths: type: string priority: type: integer - required: &ref_70 + labels: + type: array + items: + type: string + self_wait_time_ms: + type: number + aggregate_wait_time_ms: + type: number + required: &ref_80 - id - created_by - duration_ms @@ -7680,59 +9064,87 @@ paths: - name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_42 + schema: *ref_49 + - name: label + description: >- + mask to filter exact matching job's label (job labels are completed + jobs with as a result an object containing a string in the array at + key 'wm_labels') + in: query + schema: *ref_78 - name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 - name: script_path_exact description: mask to filter exact matching path in: query - schema: *ref_54 + schema: *ref_62 - name: script_path_start description: mask to filter matching starting path in: query - schema: *ref_55 + schema: *ref_63 - name: schedule_path description: mask to filter by schedule path in: query - schema: *ref_56 + schema: *ref_64 - name: script_hash description: mask to filter exact matching path in: query - schema: *ref_57 + schema: *ref_65 - name: started_before description: filter on started before (inclusive) timestamp in: query - schema: *ref_58 + schema: *ref_66 - name: started_after description: filter on started after (exclusive) timestamp in: query - schema: *ref_59 + schema: *ref_67 + - name: created_before + description: filter on created before (inclusive) timestamp + in: query + schema: &ref_117 + type: string + format: date-time + - name: created_after + description: filter on created after (exclusive) timestamp + in: query + schema: &ref_118 + type: string + format: date-time - name: created_or_started_before description: >- filter on created_at for non non started job and started_at otherwise before (inclusive) timestamp in: query - schema: &ref_99 + schema: &ref_111 type: string format: date-time - name: running description: filter on running jobs in: query - schema: *ref_67 + schema: *ref_72 - name: scheduled_for_before_now description: filter on jobs scheduled_for before now (hence waitinf for a worker) in: query - schema: *ref_68 + schema: *ref_69 - name: created_or_started_after description: >- filter on created_at for non non started job and started_at otherwise after (exclusive) timestamp in: query - schema: &ref_98 + schema: &ref_112 + type: string + format: date-time + - name: created_or_started_after_completed_jobs + description: >- + filter on created_at for non non started job and started_at + otherwise after (exclusive) timestamp but only for the completed + jobs + in: query + schema: &ref_113 type: string format: date-time - name: job_kinds @@ -7740,23 +9152,35 @@ paths: filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: *ref_61 + schema: *ref_70 + - name: suspended + description: filter on suspended jobs + in: query + schema: *ref_71 - name: args description: >- filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: *ref_62 + schema: *ref_73 - name: tag description: filter on jobs with a given tag/worker group in: query - schema: *ref_64 + schema: *ref_75 - name: result description: >- filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: *ref_63 + schema: *ref_74 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 - name: is_skipped description: is the job skipped in: query @@ -7767,6 +9191,11 @@ paths: 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 @@ -7779,6 +9208,11 @@ paths: in: query schema: type: boolean + - name: is_not_schedule + description: is not a scheduled job + in: query + schema: + type: boolean responses: '200': description: All jobs @@ -7787,22 +9221,28 @@ paths: schema: type: array items: - allOf: &ref_74 - - oneOf: + oneOf: &ref_84 + - allOf: - type: object - properties: *ref_69 - required: *ref_70 + properties: *ref_79 + required: *ref_80 - type: object - properties: *ref_71 - required: *ref_72 - - type: object - properties: - type: - type: string - enum: - - CompletedJob - - QueuedJob - discriminator: &ref_75 + properties: + type: + type: string + enum: + - CompletedJob + - allOf: + - type: object + properties: *ref_81 + required: *ref_82 + - type: object + properties: + type: + type: string + enum: + - QueuedJob + discriminator: &ref_85 propertyName: type /jobs/db_clock: get: @@ -7817,6 +9257,44 @@ paths: application/json: schema: type: integer + /jobs/completed/count_by_tag: + get: + summary: Count jobs by tag + operationId: countJobsByTag + tags: + - job + parameters: + - name: horizon_secs + in: query + description: >- + Past Time horizon in seconds (when to start the count = now - + horizon) (default is 3600) + required: false + schema: + type: integer + - name: workspace_id + in: query + description: Specific workspace ID to filter results (optional) + required: false + schema: + type: string + responses: + '200': + description: Job counts by tag + content: + application/json: + schema: + type: array + items: + type: object + properties: + tag: + type: string + count: + type: integer + required: + - tag + - count /w/{workspace}/jobs_u/get/{id}: get: summary: get job @@ -7831,15 +9309,19 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 + - name: no_logs + in: query + schema: + type: boolean responses: '200': description: job details content: application/json: schema: - allOf: *ref_74 - discriminator: *ref_75 + oneOf: *ref_84 + discriminator: *ref_85 /w/{workspace}/jobs_u/get_root_job_id/{id}: get: summary: get root job id @@ -7854,7 +9336,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 responses: '200': description: get root job id @@ -7876,7 +9358,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 responses: '200': description: job details @@ -7884,6 +9366,27 @@ paths: text/plain: schema: type: string + /w/{workspace}/jobs_u/get_args/{id}: + get: + summary: get job args + operationId: getJobArgs + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: id + in: path + required: true + schema: *ref_83 + responses: + '200': + description: job args + content: + application/json: + schema: {} /w/{workspace}/jobs_u/getupdate/{id}: get: summary: get job updates @@ -7898,7 +9401,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 - name: running in: query schema: @@ -7907,6 +9410,10 @@ paths: in: query schema: type: integer + - name: get_progress + in: query + schema: + type: boolean responses: '200': description: job details @@ -7921,8 +9428,49 @@ paths: type: boolean new_logs: type: string + log_offset: + type: integer mem_peak: type: integer + progress: + type: integer + flow_status: + type: object + additionalProperties: &ref_151 + type: object + properties: &ref_152 + scheduled_for: + type: string + format: date-time + started_at: + type: string + format: date-time + duration_ms: + type: number + name: + type: string + /w/{workspace}/jobs_u/get_log_file/{path}: + get: + summary: get log file from object store + operationId: getLogFileFromStore + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: + type: string + responses: + '200': + description: job log + content: + text/plain: + type: string /w/{workspace}/jobs_u/get_flow_debug_info/{id}: get: summary: get flow debug info @@ -7937,7 +9485,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 responses: '200': description: flow debug info details @@ -7958,7 +9506,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 responses: '200': description: job details @@ -7966,8 +9514,8 @@ paths: application/json: schema: type: object - properties: *ref_69 - required: *ref_70 + properties: *ref_79 + required: *ref_80 /w/{workspace}/jobs_u/completed/get_result/{id}: get: summary: get completed job result @@ -7982,7 +9530,23 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 + - name: suspended_job + in: query + schema: + type: string + - name: resume_id + in: query + schema: + type: integer + - name: secret + in: query + schema: + type: string + - name: approver + in: query + schema: + type: string responses: '200': description: result @@ -8003,10 +9567,10 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 - name: get_started in: query - schema: &ref_108 + schema: &ref_124 type: boolean responses: '200': @@ -8040,7 +9604,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 responses: '200': description: job details @@ -8048,11 +9612,11 @@ paths: application/json: schema: type: object - properties: *ref_69 - required: *ref_70 + properties: *ref_79 + required: *ref_80 /w/{workspace}/jobs_u/queue/cancel/{id}: post: - summary: cancel queued job + summary: cancel queued or running job operationId: cancelQueuedJob tags: - job @@ -8064,7 +9628,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 requestBody: description: reason required: true @@ -8096,7 +9660,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 requestBody: description: reason required: true @@ -8128,7 +9692,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 requestBody: description: reason required: true @@ -8160,7 +9724,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 - name: resume_id in: path required: true @@ -8191,7 +9755,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 - name: resume_id in: path required: true @@ -8233,7 +9797,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 - name: payload description: > The base64 encoded payload that has been encoded as a JSON. e.g how @@ -8241,7 +9805,7 @@ paths: `encodeURIComponent(btoa(JSON.stringify({a: 2})))` in: query - schema: *ref_76 + schema: *ref_86 - name: resume_id in: path required: true @@ -8276,7 +9840,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 - name: resume_id in: path required: true @@ -8304,6 +9868,64 @@ paths: text/plain: schema: type: string + /w/{workspace}/jobs/flow/user_states/{id}/{key}: + post: + summary: set flow user state at a given key + operationId: setFlowUserState + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: id + in: path + required: true + schema: *ref_83 + - name: key + in: path + required: true + schema: + type: string + requestBody: + description: new value + required: true + content: + application/json: + schema: {} + responses: + '200': + description: flow user state updated + content: + text/plain: + schema: + type: string + get: + summary: get flow user state at a given key + operationId: getFlowUserState + tags: + - job + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: id + in: path + required: true + schema: *ref_83 + - name: key + in: path + required: true + schema: + type: string + responses: + '200': + description: flow user state updated + content: + application/json: + schema: {} /w/{workspace}/jobs/flow/resume/{id}: post: summary: resume a job for a suspended flow as an owner @@ -8318,7 +9940,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 requestBody: required: true content: @@ -8346,7 +9968,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 - name: resume_id in: path required: true @@ -8381,7 +10003,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 - name: resume_id in: path required: true @@ -8423,7 +10045,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 - name: resume_id in: path required: true @@ -8447,8 +10069,8 @@ paths: type: object properties: job: - allOf: *ref_74 - discriminator: *ref_75 + oneOf: *ref_84 + discriminator: *ref_85 approvers: type: array items: @@ -8513,7 +10135,7 @@ paths: application/json: schema: type: object - properties: &ref_145 + properties: &ref_162 path: type: string schedule: @@ -8526,7 +10148,7 @@ paths: type: boolean args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 enabled: type: boolean on_failure: @@ -8537,26 +10159,34 @@ paths: type: boolean on_failure_extra_args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 on_recovery: type: string on_recovery_times: type: number on_recovery_extra_args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 + on_success: + type: string + on_success_extra_args: + type: object + additionalProperties: *ref_16 ws_error_handler_muted: type: boolean retry: type: object - properties: *ref_77 + properties: *ref_87 no_flow_overlap: type: boolean summary: type: string tag: type: string - required: &ref_146 + paused_until: + type: string + format: date-time + required: &ref_163 - path - schedule - timezone @@ -8584,7 +10214,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 requestBody: description: updated schedule required: true @@ -8592,14 +10222,14 @@ paths: application/json: schema: type: object - properties: &ref_147 + properties: &ref_164 schedule: type: string timezone: type: string args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 on_failure: type: string on_failure_times: @@ -8608,26 +10238,34 @@ paths: type: boolean on_failure_extra_args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 on_recovery: type: string on_recovery_times: type: number on_recovery_extra_args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 + on_success: + type: string + on_success_extra_args: + type: object + additionalProperties: *ref_16 ws_error_handler_muted: type: boolean retry: type: object - properties: *ref_77 + properties: *ref_87 no_flow_overlap: type: boolean summary: type: string tag: type: string - required: &ref_148 + paused_until: + type: string + format: date-time + required: &ref_165 - schedule - timezone - script_path @@ -8654,7 +10292,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 requestBody: description: updated schedule enable required: true @@ -8688,7 +10326,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: schedule deleted @@ -8710,7 +10348,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: schedule deleted @@ -8718,7 +10356,7 @@ paths: application/json: schema: type: object - properties: &ref_78 + properties: &ref_88 path: type: string edited_by: @@ -8738,7 +10376,7 @@ paths: type: boolean args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 extra_perms: type: object additionalProperties: @@ -8755,26 +10393,34 @@ paths: type: boolean on_failure_extra_args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 on_recovery: type: string on_recovery_times: type: number on_recovery_extra_args: type: object - additionalProperties: *ref_14 + additionalProperties: *ref_16 + on_success: + type: string + on_success_extra_args: + type: object + additionalProperties: *ref_16 ws_error_handler_muted: type: boolean retry: type: object - properties: *ref_77 + properties: *ref_87 summary: type: string no_flow_overlap: type: boolean tag: type: string - required: &ref_79 + paused_until: + type: string + format: date-time + required: &ref_89 - path - edited_by - edited_at @@ -8799,7 +10445,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: schedule exists @@ -8821,11 +10467,17 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 + - name: args + description: >- + filter on jobs containing those args as a json subset (@> in + postgres) + in: query + schema: *ref_73 - name: path description: filter by path in: query @@ -8835,6 +10487,10 @@ paths: in: query schema: type: boolean + - name: path_start + in: query + schema: + type: string responses: '200': description: schedule list @@ -8844,8 +10500,8 @@ paths: type: array items: type: object - properties: *ref_78 - required: *ref_79 + properties: *ref_88 + required: *ref_89 /w/{workspace}/schedules/list_with_jobs: get: summary: list schedules with last 20 jobs @@ -8860,11 +10516,11 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 responses: '200': description: schedule list @@ -8873,10 +10529,10 @@ paths: schema: type: array items: - allOf: &ref_144 + allOf: &ref_161 - type: object - properties: *ref_78 - required: *ref_79 + properties: *ref_88 + required: *ref_89 - type: object properties: jobs: @@ -8918,6 +10574,7 @@ paths: enum: - error - recovery + - success override_existing: type: boolean path: @@ -8936,6 +10593,332 @@ paths: responses: '201': description: default error handler set + /w/{workspace}/http_triggers/create: + post: + summary: create http trigger + operationId: createHttpTrigger + tags: + - http_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: new http trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_166 + path: + type: string + script_path: + type: string + route_path: + type: string + is_flow: + type: boolean + http_method: + type: string + enum: + - get + - post + - put + - delete + - patch + is_async: + type: boolean + requires_auth: + type: boolean + required: &ref_167 + - path + - script_path + - route_path + - is_flow + - is_async + - requires_auth + - http_method + responses: + '201': + description: http trigger created + content: + text/plain: + schema: + type: string + /w/{workspace}/http_triggers/update/{path}: + post: + summary: update http trigger + operationId: updateHttpTrigger + tags: + - http_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_21 + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + type: object + properties: &ref_168 + path: + type: string + script_path: + type: string + route_path: + type: string + is_flow: + type: boolean + http_method: + type: string + enum: + - get + - post + - put + - delete + - patch + is_async: + type: boolean + requires_auth: + type: boolean + required: &ref_169 + - path + - script_path + - is_flow + - kind + - is_async + - requires_auth + - http_method + responses: + '200': + description: http trigger updated + content: + text/plain: + schema: + type: string + /w/{workspace}/http_triggers/delete/{path}: + delete: + summary: delete http trigger + operationId: deleteHttpTrigger + tags: + - http_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_21 + responses: + '200': + description: http trigger deleted + content: + text/plain: + schema: + type: string + /w/{workspace}/http_triggers/get/{path}: + get: + summary: get http trigger + operationId: getHttpTrigger + tags: + - http_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_21 + responses: + '200': + description: http trigger deleted + content: + application/json: + schema: + type: object + properties: &ref_90 + path: + type: string + edited_by: + type: string + edited_at: + type: string + format: date-time + script_path: + type: string + route_path: + type: string + is_flow: + type: boolean + extra_perms: + type: object + additionalProperties: + type: boolean + email: + type: string + workspace_id: + type: string + http_method: + type: string + enum: + - get + - post + - put + - delete + - patch + is_async: + type: boolean + requires_auth: + type: boolean + required: &ref_91 + - path + - edited_by + - edited_at + - script_path + - route_path + - extra_perms + - is_flow + - email + - workspace_id + - is_async + - requires_auth + - http_method + /w/{workspace}/http_triggers/list: + get: + summary: list http triggers + operationId: listHttpTriggers + tags: + - http_trigger + parameters: + - required: true + name: workspace + in: path + schema: *ref_0 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - name: path + description: filter by path + in: query + schema: + type: string + - name: is_flow + in: query + schema: + type: boolean + - name: path_start + in: query + schema: + type: string + responses: + '200': + description: http trigger list + content: + application/json: + schema: + type: array + items: + type: object + properties: *ref_90 + required: *ref_91 + /w/{workspace}/http_triggers/exists/{path}: + get: + summary: does http trigger exists + operationId: existsHttpTrigger + tags: + - http_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_21 + responses: + '200': + description: http trigger exists + content: + application/json: + schema: + type: boolean + /w/{workspace}/http_triggers/route_exists: + post: + summary: does route exists + operationId: existsRoute + tags: + - http_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + requestBody: + description: route exists request + required: true + content: + application/json: + schema: + type: object + properties: + route_path: + type: string + http_method: + type: string + enum: + - get + - post + - put + - delete + - patch + required: + - kind + - route_path + - http_method + responses: + '200': + description: route exists + content: + application/json: + schema: + type: boolean + /w/{workspace}/http_triggers/used: + get: + summary: whether http triggers are used + operationId: used + tags: + - http_trigger + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + responses: + '200': + description: whether http triggers are used + content: + application/json: + schema: + type: boolean /groups/list: get: summary: list instance groups @@ -8951,7 +10934,7 @@ paths: type: array items: type: object - properties: &ref_81 + properties: &ref_93 name: type: string summary: @@ -8960,7 +10943,7 @@ paths: type: array items: type: string - required: &ref_82 + required: &ref_94 - name /groups/get/{name}: get: @@ -8972,7 +10955,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 responses: '200': description: instance group @@ -8980,8 +10963,8 @@ paths: application/json: schema: type: object - properties: *ref_81 - required: *ref_82 + properties: *ref_93 + required: *ref_94 /groups/create: post: summary: create instance group @@ -9019,7 +11002,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: update instance group required: true @@ -9049,7 +11032,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 responses: '200': description: instance group deleted @@ -9067,7 +11050,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: user to add to instance group required: true @@ -9097,7 +11080,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: user to remove from instance group required: true @@ -9117,6 +11100,62 @@ paths: text/plain: schema: type: string + /groups/export: + get: + summary: export instance groups + operationId: exportInstanceGroups + tags: + - group + responses: + '200': + description: exported instance groups + content: + application/json: + schema: + type: array + items: + type: object + properties: &ref_95 + name: + type: string + summary: + type: string + emails: + type: array + items: + type: string + id: + type: string + scim_display_name: + type: string + external_id: + type: string + required: &ref_96 + - name + /groups/overwrite: + post: + summary: overwrite instance groups + operationId: overwriteInstanceGroups + tags: + - group + requestBody: + description: overwrite instance groups + required: true + content: + application/json: + schema: + type: array + items: + type: object + properties: *ref_95 + required: *ref_96 + responses: + '200': + description: success message + content: + text/plain: + schema: + type: string /w/{workspace}/groups/list: get: summary: list groups @@ -9131,11 +11170,11 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 responses: '200': description: group list @@ -9145,7 +11184,7 @@ paths: type: array items: type: object - properties: &ref_83 + properties: &ref_97 name: type: string summary: @@ -9158,7 +11197,7 @@ paths: type: object additionalProperties: type: boolean - required: &ref_84 + required: &ref_98 - name /w/{workspace}/groups/listnames: get: @@ -9231,7 +11270,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: updated group required: true @@ -9263,7 +11302,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 responses: '200': description: group deleted @@ -9285,7 +11324,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 responses: '200': description: group @@ -9293,8 +11332,8 @@ paths: application/json: schema: type: object - properties: *ref_83 - required: *ref_84 + properties: *ref_97 + required: *ref_98 /w/{workspace}/groups/adduser/{name}: post: summary: add user to group @@ -9309,7 +11348,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: added user to group required: true @@ -9341,7 +11380,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: added user to group required: true @@ -9373,11 +11412,11 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 responses: '200': description: folder list @@ -9387,7 +11426,7 @@ paths: type: array items: type: object - properties: &ref_85 + properties: &ref_99 name: type: string owners: @@ -9398,7 +11437,14 @@ paths: type: object additionalProperties: type: boolean - required: &ref_86 + summary: + type: string + created_by: + type: string + edited_at: + type: string + format: date-time + required: &ref_100 - name - owners - extra_perms @@ -9448,6 +11494,8 @@ paths: properties: name: type: string + summary: + type: string owners: type: array items: @@ -9478,7 +11526,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: update folder required: true @@ -9487,6 +11535,8 @@ paths: schema: type: object properties: + summary: + type: string owners: type: array items: @@ -9515,7 +11565,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 responses: '200': description: folder deleted @@ -9537,7 +11587,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 responses: '200': description: folder @@ -9545,8 +11595,8 @@ paths: application/json: schema: type: object - properties: *ref_85 - required: *ref_86 + properties: *ref_99 + required: *ref_100 /w/{workspace}/folders/getusage/{name}: get: summary: get folder usage @@ -9561,7 +11611,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 responses: '200': description: folder @@ -9603,7 +11653,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: owner user to folder required: true @@ -9614,6 +11664,8 @@ paths: properties: owner: type: string + required: + - owner responses: '200': description: owner added to folder @@ -9635,7 +11687,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: added owner to folder required: true @@ -9646,6 +11698,10 @@ paths: properties: owner: type: string + write: + type: boolean + required: + - owner responses: '200': description: owner removed from folder @@ -9663,11 +11719,11 @@ paths: - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 - name: ping_since in: query required: false @@ -9685,7 +11741,7 @@ paths: type: array items: type: object - properties: &ref_149 + properties: &ref_170 worker: type: string worker_instance: @@ -9707,7 +11763,27 @@ paths: type: string wm_version: type: string - required: &ref_150 + last_job_id: + type: string + last_job_workspace_id: + type: string + occupancy_rate: + type: number + occupancy_rate_15s: + type: number + occupancy_rate_5m: + type: number + occupancy_rate_30m: + type: number + memory: + type: number + vcpus: + type: number + memory_usage: + type: number + wm_memory_usage: + type: number + required: &ref_171 - worker - worker_instance - ping_at @@ -9735,6 +11811,39 @@ paths: application/json: schema: type: boolean + /workers/queue_metrics: + get: + summary: get queue metrics + operationId: getQueueMetrics + tags: + - worker + responses: + '200': + description: metrics + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: string + values: + type: array + items: + type: object + properties: + created_at: + type: string + value: + type: number + required: + - created_at + - value + required: + - id + - values /configs/list_worker_groups: get: summary: list worker groups @@ -9767,7 +11876,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 responses: '200': description: a config @@ -9784,7 +11893,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 requestBody: description: worker group required: true @@ -9807,7 +11916,7 @@ paths: - name: name in: path required: true - schema: *ref_80 + schema: *ref_92 responses: '200': description: Delete config @@ -9815,6 +11924,28 @@ paths: text/plain: schema: type: string + /configs/list: + get: + summary: list configs + operationId: listConfigs + tags: + - config + responses: + '200': + description: list of configs + content: + application/json: + schema: + type: array + items: + type: object + properties: &ref_216 + name: + type: string + config: + type: object + required: &ref_217 + - name /w/{workspace}/acls/get/{kind}/{path}: get: summary: get granular acls @@ -9829,7 +11960,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 - name: kind in: path required: true @@ -9845,6 +11976,7 @@ paths: - folder - app - raw_app + - http_trigger responses: '200': description: acls @@ -9868,7 +12000,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 - name: kind in: path required: true @@ -9884,6 +12016,7 @@ paths: - folder - app - raw_app + - http_trigger requestBody: description: acl to add required: true @@ -9919,7 +12052,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 - name: kind in: path required: true @@ -9935,6 +12068,7 @@ paths: - folder - app - raw_app + - http_trigger requestBody: description: acl to add required: true @@ -9968,7 +12102,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '204': description: flow preview captured @@ -9986,7 +12120,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '201': description: flow preview capture created @@ -10003,7 +12137,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 responses: '200': description: captured flow preview @@ -10083,24 +12217,24 @@ paths: schema: *ref_0 - name: runnable_id in: query - schema: &ref_89 + schema: &ref_101 type: string - name: runnable_type in: query - schema: &ref_90 + schema: &ref_102 type: string - enum: &ref_117 + enum: &ref_133 - ScriptHash - ScriptPath - FlowPath - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 responses: '200': description: Input history for completed jobs @@ -10110,8 +12244,57 @@ paths: type: array items: type: object - properties: *ref_87 - required: *ref_88 + properties: &ref_103 + id: + type: string + name: + type: string + created_by: + type: string + created_at: + type: string + format: date-time + is_public: + type: boolean + success: + type: boolean + required: &ref_104 + - id + - name + - args + - created_by + - created_at + - is_public + /w/{workspace}/inputs/{jobOrInputId}/args: + get: + summary: Get args from history or saved input + operationId: getArgsFromHistoryOrSavedInput + tags: + - input + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: jobOrInputId + in: path + required: true + schema: + type: string + - name: input + in: query + schema: + type: boolean + - name: allow_large + in: query + schema: + type: boolean + responses: + '200': + description: args + content: + application/json: + schema: {} /w/{workspace}/inputs/list: get: summary: List saved Inputs for a Runnable @@ -10125,18 +12308,18 @@ paths: schema: *ref_0 - name: runnable_id in: query - schema: *ref_89 + schema: *ref_101 - name: runnable_type in: query - schema: *ref_90 + schema: *ref_102 - name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 - name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 responses: '200': description: Saved Inputs for a Runnable @@ -10146,8 +12329,8 @@ paths: type: array items: type: object - properties: *ref_87 - required: *ref_88 + properties: *ref_103 + required: *ref_104 /w/{workspace}/inputs/create: post: summary: Create an Input for future use in a script or flow @@ -10161,10 +12344,10 @@ paths: schema: *ref_0 - name: runnable_id in: query - schema: *ref_89 + schema: *ref_101 - name: runnable_type in: query - schema: *ref_90 + schema: *ref_102 requestBody: description: Input required: true @@ -10172,12 +12355,12 @@ paths: application/json: schema: type: object - properties: &ref_113 + properties: &ref_129 name: type: string args: type: object - required: &ref_114 + required: &ref_130 - name - args - created_by @@ -10207,14 +12390,14 @@ paths: application/json: schema: type: object - properties: &ref_115 + properties: &ref_131 id: type: string name: type: string is_public: type: boolean - required: &ref_116 + required: &ref_132 - id - name - is_public @@ -10240,7 +12423,7 @@ paths: - name: input in: path required: true - schema: &ref_107 + schema: &ref_123 type: string responses: '200': @@ -10273,7 +12456,7 @@ paths: properties: s3_resource: type: object - properties: &ref_91 + properties: &ref_105 bucket: type: string region: @@ -10288,7 +12471,7 @@ paths: type: string pathStyle: type: boolean - required: &ref_92 + required: &ref_106 - bucket - region - endPoint @@ -10364,8 +12547,8 @@ paths: properties: s3_resource: type: object - properties: *ref_91 - required: *ref_92 + properties: *ref_105 + required: *ref_106 responses: '200': description: Connection settings @@ -10386,10 +12569,10 @@ paths: type: boolean client_kwargs: type: object - properties: &ref_93 + properties: &ref_107 region_name: type: string - required: &ref_94 + required: &ref_108 - region_name required: - endpoint_url @@ -10444,8 +12627,8 @@ paths: type: boolean client_kwargs: type: object - properties: *ref_93 - required: *ref_94 + properties: *ref_107 + required: *ref_108 required: - endpoint_url - use_ssl @@ -10503,11 +12686,11 @@ paths: application/json: schema: type: object - properties: *ref_91 - required: *ref_92 + properties: *ref_105 + required: *ref_106 /w/{workspace}/job_helpers/test_connection: get: - summary: Test connection to the workspace datasets storage + summary: Test connection to the workspace object storage operationId: datasetStorageTestConnection tags: - helpers @@ -10516,6 +12699,10 @@ paths: in: path required: true schema: *ref_0 + - name: storage + in: query + schema: + type: string responses: '200': description: Connection settings @@ -10524,7 +12711,7 @@ paths: schema: {} /w/{workspace}/job_helpers/list_stored_files: get: - summary: List the file keys available in the workspace files storage (S3) + summary: List the file keys available in a workspace object storage operationId: listStoredFiles tags: - helpers @@ -10546,6 +12733,10 @@ paths: in: query schema: type: string + - name: storage + in: query + schema: + type: string responses: '200': description: List of file keys @@ -10560,10 +12751,10 @@ paths: type: array items: type: object - properties: &ref_169 + properties: &ref_193 s3: type: string - required: &ref_170 + required: &ref_194 - s3 restricted_access: type: boolean @@ -10585,6 +12776,10 @@ paths: required: true schema: type: string + - name: storage + in: query + schema: + type: string responses: '200': description: FileMetadata @@ -10592,7 +12787,7 @@ paths: application/json: schema: type: object - properties: &ref_171 + properties: &ref_195 mime_type: type: string size_in_bytes: @@ -10645,6 +12840,10 @@ paths: in: query schema: type: integer + - name: storage + in: query + schema: + type: string responses: '200': description: FilePreview @@ -10652,7 +12851,7 @@ paths: application/json: schema: type: object - properties: &ref_172 + properties: &ref_196 msg: type: string content: @@ -10664,7 +12863,7 @@ paths: - Csv - Parquet - Unknown - required: &ref_173 + required: &ref_197 - content_type /w/{workspace}/job_helpers/load_parquet_preview/{path}: get: @@ -10680,7 +12879,7 @@ paths: - name: path in: path required: true - schema: *ref_17 + schema: *ref_21 - name: offset in: query schema: @@ -10705,12 +12904,106 @@ paths: in: query schema: type: string + - name: storage + in: query + schema: + type: string responses: '200': description: Parquet Preview content: application/json: schema: {} + /w/{workspace}/job_helpers/load_table_count/{path}: + get: + summary: Load the table row count + operationId: loadTableRowCount + tags: + - helpers + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_21 + - name: search_col + in: query + schema: + type: string + - name: search_term + in: query + schema: + type: string + - name: storage + in: query + schema: + type: string + responses: + '200': + description: Table count + content: + application/json: + schema: + type: object + properties: + count: + type: number + /w/{workspace}/job_helpers/load_csv_preview/{path}: + get: + summary: Load a preview of a csv file + operationId: loadCsvPreview + tags: + - helpers + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: path + in: path + required: true + schema: *ref_21 + - name: offset + in: query + schema: + type: number + - name: limit + in: query + schema: + type: number + - name: sort_col + in: query + schema: + type: string + - name: sort_desc + in: query + schema: + type: boolean + - name: search_col + in: query + schema: + type: string + - name: search_term + in: query + schema: + type: string + - name: storage + in: query + schema: + type: string + - name: csv_separator + in: query + schema: + type: string + responses: + '200': + description: Csv Preview + content: + application/json: + schema: {} /w/{workspace}/job_helpers/delete_s3_file: delete: summary: Permanently delete file from S3 @@ -10727,6 +13020,10 @@ paths: required: true schema: type: string + - name: storage + in: query + schema: + type: string responses: '200': description: Confirmation @@ -10754,6 +13051,10 @@ paths: required: true schema: type: string + - name: storage + in: query + schema: + type: string responses: '200': description: Confirmation @@ -10791,6 +13092,10 @@ paths: required: false schema: type: string + - name: storage + in: query + schema: + type: string requestBody: description: File content required: true @@ -10837,6 +13142,10 @@ paths: required: false schema: type: string + - name: storage + in: query + schema: + type: string responses: '200': description: Chunk of the downloaded file @@ -10845,6 +13154,39 @@ paths: schema: type: string format: binary + /w/{workspace}/job_helpers/download_s3_parquet_file_as_csv: + get: + summary: Download file to S3 bucket + operationId: fileDownloadParquetAsCsv + tags: + - helpers + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: file_key + in: query + required: true + schema: + type: string + - name: s3_resource_path + in: query + required: false + schema: + type: string + - name: resource_type + in: query + required: false + schema: + type: string + responses: + '200': + description: The downloaded file + content: + text/csv: + schema: + type: string /w/{workspace}/job_metrics/get/{id}: post: summary: get job metrics @@ -10859,7 +13201,7 @@ paths: - name: id in: path required: true - schema: *ref_73 + schema: *ref_83 requestBody: description: parameters for statistics retrieval required: true @@ -10888,48 +13230,175 @@ paths: type: array items: type: object - properties: &ref_176 + properties: &ref_200 id: type: string name: type: string - required: &ref_177 + required: &ref_201 - id scalar_metrics: type: array items: type: object - properties: &ref_178 + properties: &ref_202 metric_id: type: string value: type: number - required: &ref_179 + required: &ref_203 - id - value timeseries_metrics: type: array items: type: object - properties: &ref_180 + properties: &ref_204 metric_id: type: string values: type: array items: type: object - properties: &ref_182 + properties: &ref_206 timestamp: type: string format: date-time value: type: number - required: &ref_183 + required: &ref_207 - timestamp - value - required: &ref_181 + required: &ref_205 - id - values + /w/{workspace}/job_metrics/set_progress/{id}: + post: + summary: set job metrics + operationId: setJobProgress + tags: + - metrics + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: id + in: path + required: true + schema: *ref_83 + requestBody: + description: parameters for statistics retrieval + required: true + content: + application/json: + schema: + type: object + properties: + percent: + type: integer + flow_job_id: + type: string + format: uuid + responses: + '200': + description: Job progress updated + content: + application/json: + schema: {} + /w/{workspace}/job_metrics/get_progress/{id}: + get: + summary: get job progress + operationId: getJobProgress + tags: + - metrics + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: id + in: path + required: true + schema: *ref_83 + responses: + '200': + description: job progress between 0 and 99 + content: + application/json: + schema: + type: integer + /service_logs/list_files: + get: + summary: list log files ordered by timestamp + operationId: listLogFiles + tags: + - service_logs + parameters: + - name: before + description: filter on started before (inclusive) timestamp + in: query + schema: *ref_109 + - name: after + description: filter on created after (exclusive) timestamp + in: query + schema: *ref_110 + - name: with_error + in: query + required: false + schema: + type: boolean + responses: + '200': + description: time + content: + application/json: + schema: + type: array + items: + type: object + properties: + hostname: + type: string + mode: + type: string + worker_group: + type: string + log_ts: + type: string + format: date-time + file_path: + type: string + ok_lines: + type: integer + err_lines: + type: integer + json_fmt: + type: boolean + required: + - hostname + - mode + - log_ts + - file_path + - json_fmt + /service_logs/get_log_file/{path}: + get: + summary: get log file by path + operationId: getLogFile + tags: + - service_logs + parameters: + - name: path + in: path + required: true + schema: *ref_21 + responses: + '200': + description: log stream + content: + text/plain: + schema: + type: string /concurrency_groups/list: get: summary: List all concurrency groups @@ -10945,17 +13414,15 @@ paths: type: array items: type: object - properties: &ref_186 - concurrency_id: + properties: &ref_210 + concurrency_key: type: string - job_uuids: - type: array - items: - type: string - required: &ref_187 - - concurrency_id - - job_uuids - /concurrency_groups/{concurrency_id}: + total_running: + type: number + required: &ref_211 + - concurrency_key + - total_running + /concurrency_groups/prune/{concurrency_id}: delete: summary: Delete concurrency group operationId: deleteConcurrencyGroup @@ -10965,7 +13432,7 @@ paths: - name: concurrency_id in: path required: true - schema: &ref_109 + schema: &ref_125 type: string responses: '200': @@ -10975,6 +13442,251 @@ paths: schema: type: object properties: {} + /concurrency_groups/{id}/key: + get: + summary: Get the concurrency key for a job that has concurrency limits enabled + operationId: getConcurrencyKey + tags: + - concurrencyGroups + parameters: + - name: id + in: path + required: true + schema: *ref_83 + responses: + '200': + description: concurrency key for given job + content: + application/json: + schema: + type: string + /w/{workspace}/concurrency_groups/list_jobs: + get: + summary: Get intervals of job runtime concurrency + operationId: listExtendedJobs + tags: + - concurrencyGroups + - job + parameters: + - name: concurrency_key + in: query + required: false + schema: + type: string + - name: row_limit + in: query + required: false + schema: + type: number + - name: workspace + in: path + required: true + schema: *ref_0 + - name: created_by + description: mask to filter exact matching user creator + in: query + schema: *ref_49 + - name: label + description: >- + mask to filter exact matching job's label (job labels are completed + jobs with as a result an object containing a string in the array at + key 'wm_labels') + in: query + schema: *ref_78 + - name: parent_job + description: >- + The parent job that is at the origin and responsible for the + execution of this script if any + in: query + schema: *ref_42 + - name: script_path_exact + description: mask to filter exact matching path + in: query + schema: *ref_62 + - name: script_path_start + description: mask to filter matching starting path + in: query + schema: *ref_63 + - name: schedule_path + description: mask to filter by schedule path + in: query + schema: *ref_64 + - name: script_hash + description: mask to filter exact matching path + in: query + schema: *ref_65 + - name: started_before + description: filter on started before (inclusive) timestamp + in: query + schema: *ref_66 + - name: started_after + description: filter on started after (exclusive) timestamp + in: query + schema: *ref_67 + - name: created_or_started_before + description: >- + filter on created_at for non non started job and started_at + otherwise before (inclusive) timestamp + in: query + schema: *ref_111 + - name: running + description: filter on running jobs + in: query + schema: *ref_72 + - name: scheduled_for_before_now + description: filter on jobs scheduled_for before now (hence waitinf for a worker) + in: query + schema: *ref_69 + - name: created_or_started_after + description: >- + filter on created_at for non non started job and started_at + otherwise after (exclusive) timestamp + in: query + schema: *ref_112 + - name: created_or_started_after_completed_jobs + description: >- + filter on created_at for non non started job and started_at + otherwise after (exclusive) timestamp but only for the completed + jobs + in: query + schema: *ref_113 + - name: job_kinds + description: >- + filter on job kind (values 'preview', 'script', 'dependencies', + 'flow') separated by, + in: query + schema: *ref_70 + - name: args + description: >- + filter on jobs containing those args as a json subset (@> in + postgres) + in: query + schema: *ref_73 + - name: tag + description: filter on jobs with a given tag/worker group + in: query + schema: *ref_75 + - name: result + description: >- + filter on jobs containing those result as a json subset (@> in + postgres) + in: query + schema: *ref_74 + - name: page + description: which page to return (start at 1, default 1) + in: query + schema: *ref_5 + - name: per_page + description: number of items to return for a given page (default 30, max 100) + in: query + schema: *ref_6 + - name: is_skipped + description: is the job skipped + in: query + schema: + type: boolean + - name: is_flow_step + description: is the job a flow step + in: query + schema: + type: boolean + - name: has_null_parent + description: has null parent + in: query + schema: + type: boolean + - name: success + description: filter on successful jobs + in: query + schema: + type: boolean + - name: all_workspaces + description: >- + get jobs from all workspaces (only valid if request come from the + `admins` workspace) + in: query + schema: + type: boolean + - name: is_not_schedule + description: is not a scheduled job + in: query + schema: + type: boolean + responses: + '200': + description: time + content: + application/json: + schema: + type: object + properties: &ref_212 + jobs: + type: array + items: + oneOf: *ref_84 + discriminator: *ref_85 + obscured_jobs: + type: array + items: + type: object + properties: &ref_134 + typ: + type: string + started_at: + type: string + format: date-time + duration_ms: + type: number + omitted_obscured_jobs: + description: >- + Obscured jobs omitted for security because of too specific + filtering + type: boolean + required: &ref_213 + - jobs + - obscured_jobs + /srch/w/{workspace}/index/search/job: + get: + summary: Search through jobs with a string query + operationId: searchJobsIndex + tags: + - indexSearch + parameters: + - name: workspace + in: path + required: true + schema: *ref_0 + - name: search_query + in: query + required: true + schema: + type: string + responses: + '200': + description: search results + content: + application/json: + schema: + type: object + properties: + query_parse_errors: + description: >- + a list of the terms that couldn't be parsed (and thus + ignored) + type: array + items: + type: object + properties: + dancer: + type: string + hits: + description: the jobs that matched the query + type: array + items: + type: object + properties: &ref_218 + dancer: + type: string components: securitySchemes: bearerAuth: @@ -10989,7 +13701,7 @@ components: name: key in: path required: true - schema: *ref_7 + schema: *ref_9 WorkspaceId: name: workspace in: path @@ -10999,89 +13711,104 @@ components: name: version in: path required: true - schema: *ref_95 + schema: *ref_114 Token: name: token in: path required: true - schema: *ref_96 + schema: *ref_115 AccountId: name: id in: path required: true - schema: *ref_21 + schema: *ref_25 ClientName: name: client_name in: path required: true - schema: *ref_20 + schema: *ref_24 ScriptPath: name: path in: path required: true - schema: *ref_29 + schema: *ref_33 ScriptHash: name: hash in: path required: true - schema: *ref_33 + schema: *ref_37 JobId: name: id in: path required: true - schema: *ref_73 + schema: *ref_83 Path: name: path in: path required: true - schema: *ref_17 + schema: *ref_21 PathId: name: id in: path required: true - schema: *ref_24 + schema: *ref_28 PathVersion: name: version in: path required: true - schema: *ref_97 + schema: *ref_116 Name: name: name in: path required: true - schema: *ref_80 + schema: *ref_92 Page: name: page description: which page to return (start at 1, default 1) in: query - schema: *ref_3 + schema: *ref_5 PerPage: name: per_page description: number of items to return for a given page (default 30, max 100) in: query - schema: *ref_4 + schema: *ref_6 OrderDesc: name: order_desc description: order by desc order (default true) in: query - schema: *ref_41 + schema: *ref_48 CreatedBy: name: created_by description: mask to filter exact matching user creator in: query - schema: *ref_42 + schema: *ref_49 + Label: + name: label + description: >- + mask to filter exact matching job's label (job labels are completed jobs + with as a result an object containing a string in the array at key + 'wm_labels') + in: query + schema: *ref_78 ParentJob: name: parent_job description: >- The parent job that is at the origin and responsible for the execution of this script if any in: query - schema: *ref_36 + schema: *ref_42 WorkerTag: name: tag description: Override the tag to use in: query - schema: *ref_38 + schema: *ref_44 + CacheTtl: + name: cache_ttl + description: >- + Override the cache time to live (in seconds). Can not be used to disable + caching, only override with a new cache ttl + in: query + schema: *ref_45 NewJobId: name: job_id description: >- @@ -11089,7 +13816,7 @@ components: randomly using the ULID scheme. If a job id already exists in the queue or as a completed job, the request to create one will fail (Bad Request) in: query - schema: *ref_37 + schema: *ref_43 IncludeHeader: name: include_header description: > @@ -11099,14 +13826,14 @@ components: Header's key lowercased and '-'' replaced to '_' such that 'Content-Type' becomes the 'content_type' arg key in: query - schema: *ref_39 + schema: *ref_46 QueueLimit: name: queue_limit description: > The maximum size of the queue for which the request would get rejected if that job would push it above that limit in: query - schema: *ref_40 + schema: *ref_47 Payload: name: payload description: > @@ -11115,233 +13842,249 @@ components: `encodeURIComponent(btoa(JSON.stringify({a: 2})))` in: query - schema: *ref_76 + schema: *ref_86 ScriptStartPath: name: script_path_start description: mask to filter matching starting path in: query - schema: *ref_55 + schema: *ref_63 SchedulePath: name: schedule_path description: mask to filter by schedule path in: query - schema: *ref_56 + schema: *ref_64 ScriptExactPath: name: script_path_exact description: mask to filter exact matching path in: query - schema: *ref_54 + schema: *ref_62 ScriptExactHash: name: script_hash description: mask to filter exact matching path in: query - schema: *ref_57 + schema: *ref_65 + CreatedBefore: + name: created_before + description: filter on created before (inclusive) timestamp + in: query + schema: *ref_117 + CreatedAfter: + name: created_after + description: filter on created after (exclusive) timestamp + in: query + schema: *ref_118 StartedBefore: name: started_before description: filter on started before (inclusive) timestamp in: query - schema: *ref_58 + schema: *ref_66 StartedAfter: name: started_after description: filter on started after (exclusive) timestamp in: query - schema: *ref_59 + schema: *ref_67 + Before: + name: before + description: filter on started before (inclusive) timestamp + in: query + schema: *ref_109 CreatedOrStartedAfter: name: created_or_started_after description: >- filter on created_at for non non started job and started_at otherwise after (exclusive) timestamp in: query - schema: *ref_98 + schema: *ref_112 + CreatedOrStartedAfterCompletedJob: + name: created_or_started_after_completed_jobs + description: >- + filter on created_at for non non started job and started_at otherwise + after (exclusive) timestamp but only for the completed jobs + in: query + schema: *ref_113 CreatedOrStartedBefore: name: created_or_started_before description: >- filter on created_at for non non started job and started_at otherwise before (inclusive) timestamp in: query - schema: *ref_99 + schema: *ref_111 Success: name: success description: filter on successful jobs in: query - schema: *ref_60 + schema: *ref_68 ScheduledForBeforeNow: name: scheduled_for_before_now description: filter on jobs scheduled_for before now (hence waitinf for a worker) in: query - schema: *ref_68 + schema: *ref_69 Suspended: name: suspended description: filter on suspended jobs in: query - schema: *ref_100 + schema: *ref_71 Running: name: running description: filter on running jobs in: query - schema: *ref_67 + schema: *ref_72 ArgsFilter: name: args description: filter on jobs containing those args as a json subset (@> in postgres) in: query - schema: *ref_62 + schema: *ref_73 Tag: name: tag description: filter on jobs with a given tag/worker group in: query - schema: *ref_64 + schema: *ref_75 ResultFilter: name: result description: filter on jobs containing those result as a json subset (@> in postgres) in: query - schema: *ref_63 + schema: *ref_74 After: name: after description: filter on created after (exclusive) timestamp in: query - schema: *ref_101 - Before: - name: before - description: filter on created before (exclusive) timestamp - in: query - schema: *ref_102 + schema: *ref_110 Username: name: username description: filter on exact username of user in: query - schema: *ref_103 + schema: *ref_119 Operation: name: operation description: filter on exact or prefix name of operation in: query - schema: *ref_104 + schema: *ref_120 ResourceName: name: resource description: filter on exact or prefix name of resource in: query - schema: *ref_105 + schema: *ref_121 ActionKind: name: action_kind description: filter on type of operation in: query - schema: *ref_106 + schema: *ref_122 JobKinds: name: job_kinds description: >- filter on job kind (values 'preview', 'script', 'dependencies', 'flow') separated by, in: query - schema: *ref_61 + schema: *ref_70 RunnableId: name: runnable_id in: query - schema: *ref_89 + schema: *ref_101 RunnableTypeQuery: name: runnable_type in: query - schema: *ref_90 + schema: *ref_102 InputId: name: input in: path required: true - schema: *ref_107 + schema: *ref_123 GetStarted: name: get_started in: query - schema: *ref_108 + schema: *ref_124 ConcurrencyId: name: concurrency_id in: path required: true - schema: *ref_109 + schema: *ref_125 schemas: Script: type: object - properties: *ref_31 - required: *ref_32 + properties: *ref_35 + required: *ref_36 NewScript: type: object - properties: *ref_34 - required: *ref_35 + properties: *ref_40 + required: *ref_41 NewScriptWithDraft: - allOf: *ref_110 + allOf: *ref_126 ScriptHistory: - type: object - properties: *ref_111 - required: *ref_112 - ScriptArgs: - type: object - additionalProperties: *ref_14 - Input: - type: object - properties: *ref_87 - required: *ref_88 - CreateInput: - type: object - properties: *ref_113 - required: *ref_114 - UpdateInput: - type: object - properties: *ref_115 - required: *ref_116 - RunnableType: - type: string - enum: *ref_117 - QueuedJob: - type: object - properties: *ref_71 - required: *ref_72 - CompletedJob: - type: object - properties: *ref_69 - required: *ref_70 - Job: - allOf: *ref_74 - discriminator: *ref_75 - User: - type: object - properties: *ref_8 - required: *ref_9 - Usage: - type: object - properties: *ref_118 - Login: - type: object - properties: *ref_119 - required: *ref_120 - NewUser: - type: object - properties: *ref_121 - required: *ref_122 - EditWorkspaceUser: - type: object - properties: *ref_123 - TruncatedToken: - type: object - properties: *ref_124 - required: *ref_125 - NewToken: - type: object - properties: *ref_126 - NewTokenImpersonate: type: object properties: *ref_127 required: *ref_128 - ListableVariable: + ScriptArgs: type: object - properties: *ref_18 - required: *ref_19 - ContextualVariable: + additionalProperties: *ref_16 + Input: + type: object + properties: *ref_103 + required: *ref_104 + CreateInput: type: object properties: *ref_129 required: *ref_130 - CreateVariable: + UpdateInput: type: object properties: *ref_131 required: *ref_132 + RunnableType: + type: string + enum: *ref_133 + QueuedJob: + type: object + properties: *ref_81 + required: *ref_82 + CompletedJob: + type: object + properties: *ref_79 + required: *ref_80 + ObscuredJob: + type: object + properties: *ref_134 + Job: + oneOf: *ref_84 + discriminator: *ref_85 + User: + type: object + properties: *ref_10 + required: *ref_11 + UserUsage: + type: object + properties: *ref_135 + Login: + type: object + properties: *ref_136 + required: *ref_137 + EditWorkspaceUser: + type: object + properties: *ref_138 + TruncatedToken: + type: object + properties: *ref_38 + required: *ref_39 + NewToken: + type: object + properties: *ref_139 + NewTokenImpersonate: + type: object + properties: *ref_140 + required: *ref_141 + ListableVariable: + type: object + properties: *ref_22 + required: *ref_23 + ContextualVariable: + type: object + properties: *ref_142 + required: *ref_143 + CreateVariable: + type: object + properties: *ref_144 + required: *ref_145 EditVariable: type: object - properties: *ref_133 + properties: *ref_146 AuditLog: type: object properties: *ref_1 @@ -11457,124 +14200,164 @@ components: required: - name - typ + no_main_func: + type: boolean + nullable: true + has_preprocessor: + type: boolean + nullable: true required: - star_args - start_kwargs - args - type - error + - no_main_func + - has_preprocessor Preview: - type: object - properties: *ref_134 - required: *ref_135 - CreateResource: - type: object - properties: *ref_136 - required: *ref_137 - EditResource: - type: object - properties: *ref_138 - Resource: - type: object - properties: *ref_139 - required: *ref_140 - ListableResource: - type: object - properties: *ref_141 - required: *ref_142 - ResourceType: - type: object - properties: *ref_22 - required: *ref_23 - EditResourceType: - type: object - properties: *ref_143 - Schedule: - type: object - properties: *ref_78 - required: *ref_79 - ScheduleWJobs: - allOf: *ref_144 - NewSchedule: - type: object - properties: *ref_145 - required: *ref_146 - EditSchedule: type: object properties: *ref_147 required: *ref_148 - Group: - type: object - properties: *ref_83 - required: *ref_84 - InstanceGroup: - type: object - properties: *ref_81 - required: *ref_82 - Folder: - type: object - properties: *ref_85 - required: *ref_86 - WorkerPing: + WorkflowTask: type: object properties: *ref_149 required: *ref_150 - UserWorkspaceList: + WorkflowStatusRecord: type: object - properties: *ref_151 - required: *ref_152 - CreateWorkspace: + additionalProperties: *ref_151 + WorkflowStatus: + type: object + properties: *ref_152 + CreateResource: type: object properties: *ref_153 required: *ref_154 - Workspace: - type: object - properties: *ref_5 - required: *ref_6 - WorkspaceInvite: - type: object - properties: *ref_12 - required: *ref_13 - GlobalUserInfo: - type: object - properties: *ref_10 - required: *ref_11 - Flow: - allOf: *ref_45 - FlowMetadata: + EditResource: type: object properties: *ref_155 - required: *ref_156 - OpenFlowWPath: - allOf: *ref_46 - FlowPreview: + Resource: type: object - properties: *ref_157 - required: *ref_158 - RestartedFrom: + properties: *ref_156 + required: *ref_157 + ListableResource: type: object - properties: *ref_159 - Policy: + properties: *ref_158 + required: *ref_159 + ResourceType: type: object - properties: *ref_47 - ListableApp: + properties: *ref_26 + required: *ref_27 + EditResourceType: type: object properties: *ref_160 - required: *ref_161 - ListableRawApp: + Schedule: + type: object + properties: *ref_88 + required: *ref_89 + ScheduleWJobs: + allOf: *ref_161 + NewSchedule: type: object properties: *ref_162 required: *ref_163 + EditSchedule: + type: object + properties: *ref_164 + required: *ref_165 + HttpTrigger: + type: object + properties: *ref_90 + required: *ref_91 + NewHttpTrigger: + type: object + properties: *ref_166 + required: *ref_167 + EditHttpTrigger: + type: object + properties: *ref_168 + required: *ref_169 + TriggersCount: + type: object + properties: *ref_53 + Group: + type: object + properties: *ref_97 + required: *ref_98 + InstanceGroup: + type: object + properties: *ref_93 + required: *ref_94 + Folder: + type: object + properties: *ref_99 + required: *ref_100 + WorkerPing: + type: object + properties: *ref_170 + required: *ref_171 + UserWorkspaceList: + type: object + properties: *ref_172 + required: *ref_173 + CreateWorkspace: + type: object + properties: *ref_174 + required: *ref_175 + Workspace: + type: object + properties: *ref_7 + required: *ref_8 + WorkspaceInvite: + type: object + properties: *ref_14 + required: *ref_15 + GlobalUserInfo: + type: object + properties: *ref_12 + required: *ref_13 + Flow: + allOf: *ref_52 + ExtraPerms: + type: object + additionalProperties: *ref_176 + FlowMetadata: + type: object + properties: *ref_177 + required: *ref_178 + OpenFlowWPath: + allOf: *ref_54 + FlowPreview: + type: object + properties: *ref_179 + required: *ref_180 + RestartedFrom: + type: object + properties: *ref_181 + Policy: + type: object + properties: *ref_55 + ListableApp: + type: object + properties: *ref_182 + required: *ref_183 + ListableRawApp: + type: object + properties: *ref_184 + required: *ref_185 AppWithLastVersion: type: object - properties: *ref_48 - required: *ref_49 + properties: *ref_56 + required: *ref_57 AppWithLastVersionWDraft: - allOf: *ref_164 + allOf: *ref_186 AppHistory: type: object - properties: *ref_165 - required: *ref_166 + properties: *ref_187 + required: *ref_188 + FlowVersion: + type: object + properties: *ref_189 + required: *ref_190 SlackToken: type: object properties: @@ -11596,40 +14379,46 @@ components: - bot TokenResponse: type: object - properties: *ref_167 - required: *ref_168 + properties: *ref_191 + required: *ref_192 HubScriptKind: name: kind - schema: *ref_30 + schema: *ref_34 PolarsClientKwargs: type: object - properties: *ref_93 - required: *ref_94 + properties: *ref_107 + required: *ref_108 LargeFileStorage: type: object - properties: *ref_15 + properties: *ref_17 WindmillLargeFile: type: object - properties: *ref_169 - required: *ref_170 + properties: *ref_193 + required: *ref_194 WindmillFileMetadata: type: object - properties: *ref_171 + properties: *ref_195 WindmillFilePreview: type: object - properties: *ref_172 - required: *ref_173 + properties: *ref_196 + required: *ref_197 S3Resource: type: object - properties: *ref_91 - required: *ref_92 + properties: *ref_105 + required: *ref_106 WorkspaceGitSyncSettings: type: object - properties: *ref_16 + properties: *ref_18 + WorkspaceDeployUISettings: + type: object + properties: *ref_19 + WorkspaceDefaultScripts: + type: object + properties: *ref_20 GitRepositorySettings: type: object - properties: *ref_174 - required: *ref_175 + properties: *ref_198 + required: *ref_199 UploadFilePart: type: object properties: @@ -11641,91 +14430,118 @@ components: - part_number - tag MetricMetadata: - type: object - properties: *ref_176 - required: *ref_177 - ScalarMetric: - type: object - properties: *ref_178 - required: *ref_179 - TimeseriesMetric: - type: object - properties: *ref_180 - required: *ref_181 - MetricDataPoint: - type: object - properties: *ref_182 - required: *ref_183 - RawScriptForDependencies: - type: object - properties: *ref_184 - required: *ref_185 - ConcurrencyGroup: - type: object - properties: *ref_186 - required: *ref_187 - StaticTransform: - type: object - properties: *ref_188 - required: *ref_189 - JavascriptTransform: - type: object - properties: *ref_190 - required: *ref_191 - InputTransform: - oneOf: *ref_25 - discriminator: *ref_26 - RawScript: - type: object - properties: *ref_192 - required: *ref_193 - PathScript: - type: object - properties: *ref_194 - required: *ref_195 - PathFlow: - type: object - properties: *ref_196 - required: *ref_197 - FlowModule: - type: object - properties: *ref_27 - required: *ref_28 - ForloopFlow: - type: object - properties: *ref_198 - required: *ref_199 - BranchOne: type: object properties: *ref_200 required: *ref_201 - BranchAll: + ScalarMetric: type: object properties: *ref_202 required: *ref_203 - Identity: + TimeseriesMetric: type: object properties: *ref_204 required: *ref_205 + MetricDataPoint: + type: object + properties: *ref_206 + required: *ref_207 + RawScriptForDependencies: + type: object + properties: *ref_208 + required: *ref_209 + ConcurrencyGroup: + type: object + properties: *ref_210 + required: *ref_211 + ExtendedJobs: + type: object + properties: *ref_212 + required: *ref_213 + ExportedUser: + type: object + properties: *ref_3 + required: *ref_4 + GlobalSetting: + type: object + properties: *ref_214 + required: *ref_215 + Config: + type: object + properties: *ref_216 + required: *ref_217 + ExportedInstanceGroup: + type: object + properties: *ref_95 + required: *ref_96 + JobSearchHit: + type: object + properties: *ref_218 + StaticTransform: + type: object + properties: *ref_219 + required: *ref_220 + JavascriptTransform: + type: object + properties: *ref_221 + required: *ref_222 + InputTransform: + oneOf: *ref_29 + discriminator: *ref_30 + RawScript: + type: object + properties: *ref_223 + required: *ref_224 + PathScript: + type: object + properties: *ref_225 + required: *ref_226 + PathFlow: + type: object + properties: *ref_227 + required: *ref_228 + FlowModule: + type: object + properties: *ref_31 + required: *ref_32 + ForloopFlow: + type: object + properties: *ref_229 + required: *ref_230 + WhileloopFlow: + type: object + properties: *ref_231 + required: *ref_232 + BranchOne: + type: object + properties: *ref_233 + required: *ref_234 + BranchAll: + type: object + properties: *ref_235 + required: *ref_236 + Identity: + type: object + properties: *ref_237 + required: *ref_238 FlowModuleValue: - oneOf: *ref_206 - discriminator: *ref_207 + oneOf: *ref_239 + discriminator: *ref_240 Retry: type: object - properties: *ref_77 + properties: *ref_87 FlowValue: + type: object + properties: *ref_58 + required: *ref_59 + OpenFlow: type: object properties: *ref_50 required: *ref_51 - OpenFlow: - type: object - properties: *ref_43 - required: *ref_44 FlowStatusModule: type: object - properties: *ref_52 - required: *ref_53 + properties: *ref_60 + required: *ref_61 FlowStatus: type: object - properties: *ref_65 - required: *ref_66 + properties: *ref_76 + required: *ref_77 diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 0a44378b6d..eebb8fd0a9 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.381.0 + version: 1.416.2 title: Windmill API contact: @@ -342,6 +342,8 @@ paths: properties: is_super_admin: type: boolean + name: + type: string responses: "200": description: user updated @@ -740,6 +742,35 @@ paths: schema: type: string + /settings/test_critical_channels: + post: + summary: test critical channels + operationId: testCriticalChannels + tags: + - setting + requestBody: + description: test critical channel payload + required: true + content: + application/json: + schema: + type: array + items: + type: object + properties: + email: + type: string + slack_channel: + type: string + responses: + "200": + description: status + content: + text/plain: + schema: + type: string + + /settings/test_license_key: post: summary: test license key @@ -1436,6 +1467,11 @@ paths: parameters: - $ref: "#/components/parameters/Page" - $ref: "#/components/parameters/PerPage" + - name: active_only + in: query + description: filter only active users + schema: + type: boolean responses: "200": description: user @@ -2131,6 +2167,30 @@ paths: schema: type: number + /w/{workspace}/workspaces/used_triggers: + get: + summary: get used triggers + operationId: getUsedTriggers + tags: + - workspace + parameters: + - $ref: "#/components/parameters/WorkspaceId" + responses: + "200": + description: status + content: + application/json: + schema: + type: object + properties: + http_routes_used: + type: boolean + websocket_used: + type: boolean + required: + - http_routes_used + - websocket_used + /w/{workspace}/users/list: get: summary: list users @@ -2585,6 +2645,36 @@ paths: schema: type: string + + /oauth/connect_slack_callback: + post: + summary: connect slack callback instance + operationId: connectSlackCallbackInstance + tags: + - oauth + requestBody: + description: code endpoint + required: true + content: + application/json: + schema: + type: object + properties: + code: + type: string + state: + type: string + required: + - code + - state + responses: + "200": + description: success message + content: + text/plain: + schema: + type: string + /oauth/connect_callback/{client_name}: post: summary: connect callback @@ -2728,7 +2818,14 @@ paths: oauth: type: array items: - type: string + type: object + properties: + type: + type: string + display_name: + type: string + required: + - type saml: type: string required: @@ -3056,6 +3153,22 @@ paths: schema: type: string + /w/{workspace}/resources/file_resource_type_to_file_ext_map: + get: + summary: get map from resource type to format extension + operationId: fileResourceTypeToFileExtMap + tags: + - resource + parameters: + - $ref: "#/components/parameters/WorkspaceId" + responses: + "200": + description: map from resource type to file ext + content: + application/json: + schema: {} + + /w/{workspace}/resources/type/delete/{path}: delete: summary: delete resource_type @@ -3924,6 +4037,10 @@ paths: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ScriptPath" + - name: with_starred_info + in: query + schema: + type: boolean responses: "200": description: script details @@ -3932,6 +4049,42 @@ paths: schema: $ref: "#/components/schemas/Script" + /w/{workspace}/scripts/get_triggers_count/{path}: + get: + summary: get triggers count of script + operationId: getTriggersCountOfScript + tags: + - script + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/ScriptPath" + responses: + "200": + description: triggers count + content: + application/json: + schema: + $ref: "#/components/schemas/TriggersCount" + + /w/{workspace}/scripts/list_tokens/{path}: + get: + summary: get tokens with script scope + operationId: listTokensOfScript + tags: + - script + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/ScriptPath" + responses: + "200": + description: tokens list + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/TruncatedToken" + /w/{workspace}/scripts/get/draft/{path}: get: summary: get script by path with draft @@ -3968,6 +4121,26 @@ paths: items: $ref: "#/components/schemas/ScriptHistory" + /w/{workspace}/scripts/get_latest_version/{path}: + get: + summary: get scripts's latest version (hash) + operationId: getScriptLatestVersion + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/ScriptPath" + tags: + - script + responses: + "200": + description: Script version/hash + content: + application/json: + + required: false + + schema: + $ref: "#/components/schemas/ScriptHistory" + /w/{workspace}/scripts/history_update/h/{hash}/p/{path}: post: summary: update history of a script @@ -4059,6 +4232,10 @@ paths: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ScriptHash" + - name: with_starred_info + in: query + schema: + type: boolean responses: "200": description: script details @@ -4126,6 +4303,11 @@ paths: in: query schema: type: integer + - name: skip_preprocessor + description: skip the preprocessor + in: query + schema: + type: boolean - $ref: "#/components/parameters/ParentJob" - $ref: "#/components/parameters/WorkerTag" - $ref: "#/components/parameters/CacheTtl" @@ -4447,6 +4629,25 @@ paths: items: $ref: "#/components/schemas/FlowVersion" + /w/{workspace}/flows/get_latest_version/{path}: + get: + summary: get flow's latest version + operationId: getFlowLatestVersion + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/ScriptPath" + tags: + - flow + responses: + "200": + description: Flow version + content: + application/json: + required: false + + schema: + $ref: "#/components/schemas/FlowVersion" + /w/{workspace}/flows/get/v/{version}/p/{path}: get: summary: get flow version @@ -4515,6 +4716,10 @@ paths: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ScriptPath" + - name: with_starred_info + in: query + schema: + type: boolean responses: "200": description: flow details @@ -4523,6 +4728,43 @@ paths: schema: $ref: "#/components/schemas/Flow" + /w/{workspace}/flows/get_triggers_count/{path}: + get: + summary: get triggers count of flow + operationId: getTriggersCountOfFlow + tags: + - flow + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/ScriptPath" + responses: + "200": + description: triggers count + content: + application/json: + schema: + $ref: "#/components/schemas/TriggersCount" + + /w/{workspace}/flows/list_tokens/{path}: + get: + summary: get tokens with flow scope + operationId: listTokensOfFlow + tags: + - flow + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/ScriptPath" + responses: + "200": + description: tokens list + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/TruncatedToken" + + /w/{workspace}/flows/toggle_workspace_error_handler/{path}: post: summary: Toggle ON and OFF the workspace error handler for a given flow @@ -4693,26 +4935,6 @@ paths: schema: type: string - /w/{workspace}/flows/input_history/p/{path}: - get: - summary: list inputs for previous completed flow jobs - operationId: getFlowInputHistoryByPath - tags: - - flow - parameters: - - $ref: "#/components/parameters/WorkspaceId" - - $ref: "#/components/parameters/ScriptPath" - - $ref: "#/components/parameters/Page" - - $ref: "#/components/parameters/PerPage" - responses: - "200": - description: input history for completed jobs with this flow path - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/Input" /w/{workspace}/raw_apps/list: get: @@ -4932,6 +5154,10 @@ paths: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ScriptPath" + - name: with_starred_info + in: query + schema: + type: boolean responses: "200": description: app details @@ -4976,6 +5202,24 @@ paths: items: $ref: "#/components/schemas/AppHistory" + /w/{workspace}/apps/get_latest_version/{path}: + get: + summary: get apps's latest version + operationId: getAppLatestVersion + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/ScriptPath" + tags: + - app + responses: + "200": + description: App version + content: + application/json: + required: false + schema: + $ref: "#/components/schemas/AppHistory" + /w/{workspace}/apps/history_update/a/{id}/v/{version}: post: summary: update app history @@ -5284,6 +5528,11 @@ paths: in: query schema: type: integer + - name: skip_preprocessor + description: skip the preprocessor + in: query + schema: + type: boolean - $ref: "#/components/parameters/ParentJob" - $ref: "#/components/parameters/WorkerTag" - $ref: "#/components/parameters/NewJobId" @@ -5392,6 +5641,11 @@ paths: in: query schema: type: integer + - name: skip_preprocessor + description: skip the preprocessor + in: query + schema: + type: boolean - $ref: "#/components/parameters/ParentJob" - $ref: "#/components/parameters/WorkerTag" - $ref: "#/components/parameters/CacheTtl" @@ -5808,6 +6062,8 @@ paths: - $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" @@ -5874,6 +6130,43 @@ paths: schema: type: integer + /jobs/completed/count_by_tag: + get: + summary: Count jobs by tag + operationId: countJobsByTag + tags: + - job + parameters: + - name: horizon_secs + in: query + description: Past Time horizon in seconds (when to start the count = now - horizon) (default is 3600) + required: false + schema: + type: integer + - name: workspace_id + in: query + description: Specific workspace ID to filter results (optional) + required: false + schema: + type: string + responses: + "200": + description: Job counts by tag + content: + application/json: + schema: + type: array + items: + type: object + properties: + tag: + type: string + count: + type: integer + required: + - tag + - count + /w/{workspace}/jobs_u/get/{id}: get: summary: get job @@ -5963,6 +6256,10 @@ paths: in: query schema: type: integer + - name: get_progress + in: query + schema: + type: boolean responses: "200": @@ -5982,6 +6279,8 @@ paths: type: integer mem_peak: type: integer + progress: + type: integer flow_status: $ref: "#/components/schemas/WorkflowStatusRecord" @@ -6119,7 +6418,7 @@ paths: /w/{workspace}/jobs_u/queue/cancel/{id}: post: - summary: cancel queued job + summary: cancel queued or running job operationId: cancelQueuedJob tags: - job @@ -6402,6 +6701,7 @@ paths: schema: type: string + /w/{workspace}/jobs_u/cancel/{id}/{resume_id}/{signature}: get: summary: cancel a job for a suspended flow @@ -6750,7 +7050,7 @@ paths: properties: handler_type: type: string - enum: ["error", "recovery"] + enum: ["error", "recovery", "success"] override_existing: type: boolean path: @@ -6770,6 +7070,338 @@ paths: "201": description: default error handler set + + /w/{workspace}/http_triggers/create: + post: + summary: create http trigger + operationId: createHttpTrigger + tags: + - http_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: new http trigger + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/NewHttpTrigger" + responses: + "201": + description: http trigger created + content: + text/plain: + schema: + type: string + + /w/{workspace}/http_triggers/update/{path}: + post: + summary: update http trigger + operationId: updateHttpTrigger + tags: + - http_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/EditHttpTrigger" + responses: + "200": + description: http trigger updated + content: + text/plain: + schema: + type: string + + /w/{workspace}/http_triggers/delete/{path}: + delete: + summary: delete http trigger + operationId: deleteHttpTrigger + tags: + - http_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: http trigger deleted + content: + text/plain: + schema: + type: string + + /w/{workspace}/http_triggers/get/{path}: + get: + summary: get http trigger + operationId: getHttpTrigger + tags: + - http_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: http trigger deleted + content: + application/json: + schema: + $ref: "#/components/schemas/HttpTrigger" + + + /w/{workspace}/http_triggers/list: + get: + summary: list http triggers + operationId: listHttpTriggers + tags: + - http_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: http trigger list + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/HttpTrigger" + + + /w/{workspace}/http_triggers/exists/{path}: + get: + summary: does http trigger exists + operationId: existsHttpTrigger + tags: + - http_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: http trigger exists + content: + application/json: + schema: + type: boolean + + /w/{workspace}/http_triggers/route_exists: + post: + summary: does route exists + operationId: existsRoute + tags: + - http_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: route exists request + required: true + content: + application/json: + schema: + type: object + properties: + route_path: + type: string + http_method: + type: string + enum: ["get", "post", "put", "delete", "patch"] + required: + - kind + - route_path + - http_method + responses: + "200": + description: route exists + content: + application/json: + schema: + type: boolean + + /w/{workspace}/websocket_triggers/create: + post: + summary: create websocket trigger + operationId: createWebsocketTrigger + tags: + - websocket_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: new websocket trigger + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/NewWebsocketTrigger" + responses: + "201": + description: websocket trigger created + content: + text/plain: + schema: + type: string + + /w/{workspace}/websocket_triggers/update/{path}: + post: + summary: update websocket trigger + operationId: updateWebsocketTrigger + tags: + - websocket_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/EditWebsocketTrigger" + responses: + "200": + description: websocket trigger updated + content: + text/plain: + schema: + type: string + + /w/{workspace}/websocket_triggers/delete/{path}: + delete: + summary: delete websocket trigger + operationId: deleteWebsocketTrigger + tags: + - websocket_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: websocket trigger deleted + content: + text/plain: + schema: + type: string + + /w/{workspace}/websocket_triggers/get/{path}: + get: + summary: get websocket trigger + operationId: getWebsocketTrigger + tags: + - websocket_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: websocket trigger deleted + content: + application/json: + schema: + $ref: "#/components/schemas/WebsocketTrigger" + + + /w/{workspace}/websocket_triggers/list: + get: + summary: list websocket triggers + operationId: listWebsocketTriggers + tags: + - websocket_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: websocket trigger list + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/WebsocketTrigger" + + + /w/{workspace}/websocket_triggers/exists/{path}: + get: + summary: does websocket trigger exists + operationId: existsWebsocketTrigger + tags: + - websocket_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: websocket trigger exists + content: + application/json: + schema: + type: boolean + + /w/{workspace}/websocket_triggers/setenabled/{path}: + post: + summary: set enabled websocket trigger + operationId: setWebsocketTriggerEnabled + tags: + - websocket_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: updated websocket trigger enable + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + "200": + description: websocket trigger enabled set + content: + text/plain: + schema: + type: string + + /groups/list: get: summary: list instance groups @@ -7571,6 +8203,29 @@ paths: items: $ref: "#/components/schemas/Config" + /configs/list_autoscaling_events/{worker_group}: + get: + summary: List autoscaling events + operationId: listAutoscalingEvents + tags: + - config + parameters: + - name: worker_group + in: path + required: true + schema: + type: string + responses: + "200": + description: List of autoscaling events + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/AutoscalingEvent" + + /w/{workspace}/acls/get/{kind}/{path}: get: summary: get granular acls @@ -7596,6 +8251,8 @@ paths: folder, app, raw_app, + http_trigger, + websocket_trigger, ] responses: "200": @@ -7632,6 +8289,8 @@ paths: folder, app, raw_app, + http_trigger, + websocket_trigger, ] requestBody: description: acl to add @@ -7679,6 +8338,8 @@ paths: folder, app, raw_app, + http_trigger, + websocket_trigger, ] requestBody: description: acl to add @@ -8317,6 +8978,38 @@ paths: application/json: schema: {} + /w/{workspace}/job_helpers/load_table_count/{path}: + get: + summary: Load the table row count + operationId: loadTableRowCount + tags: + - helpers + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + - name: search_col + in: query + schema: + type: string + - name: search_term + in: query + schema: + type: string + - name: storage + in: query + schema: + type: string + responses: + "200": + description: Table count + content: + application/json: + schema: + type: object + properties: + count: + type: number + /w/{workspace}/job_helpers/load_csv_preview/{path}: get: summary: Load a preview of a csv file @@ -8585,6 +9278,116 @@ paths: items: $ref: "#/components/schemas/TimeseriesMetric" + /w/{workspace}/job_metrics/set_progress/{id}: + post: + summary: set job metrics + operationId: setJobProgress + tags: + - metrics + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/JobId" + requestBody: + description: parameters for statistics retrieval + required: true + content: + application/json: + schema: + type: object + properties: + percent: + type: integer + flow_job_id: + type: string + format: uuid + + responses: + "200": + description: Job progress updated + content: + application/json: + schema: {} + + /w/{workspace}/job_metrics/get_progress/{id}: + get: + summary: get job progress + operationId: getJobProgress + tags: + - metrics + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/JobId" + responses: + "200": + description: job progress between 0 and 99 + content: + application/json: + schema: + type: integer + /service_logs/list_files: + get: + summary: list log files ordered by timestamp + operationId: listLogFiles + tags: + - service_logs + parameters: + - $ref: "#/components/parameters/Before" + - $ref: "#/components/parameters/After" + - name: with_error + in: query + required: false + schema: + type: boolean + responses: + "200": + description: time + content: + application/json: + schema: + type: array + items: + type: object + properties: + hostname: + type: string + mode: + type: string + worker_group: + type: string + log_ts: + type: string + format: date-time + file_path: + type: string + ok_lines: + type: integer + err_lines: + type: integer + json_fmt: + type: boolean + required: + - hostname + - mode + - log_ts + - file_path + - json_fmt + + /service_logs/get_log_file/{path}: + get: + summary: get log file by path + operationId: getLogFile + tags: + - service_logs + parameters: + - $ref: "#/components/parameters/Path" + responses: + "200": + description: log stream + content: + text/plain: + schema: + type: string + /concurrency_groups/list: get: summary: List all concurrency groups @@ -8942,6 +9745,20 @@ components: in: query schema: type: string + CreatedBefore: + name: created_before + description: filter on created before (inclusive) timestamp + in: query + schema: + type: string + format: date-time + CreatedAfter: + name: created_after + description: filter on created after (exclusive) timestamp + in: query + schema: + type: string + format: date-time StartedBefore: name: started_before description: filter on started before (inclusive) timestamp @@ -8956,6 +9773,13 @@ components: schema: type: string format: date-time + Before: + name: before + description: filter on started before (inclusive) timestamp + in: query + schema: + type: string + format: date-time CreatedOrStartedAfter: name: created_or_started_after description: @@ -9032,13 +9856,6 @@ components: schema: type: string format: date-time - Before: - name: before - description: filter on created before (exclusive) timestamp - in: query - schema: - type: string - format: date-time Username: name: username description: filter on exact username of user @@ -9169,6 +9986,8 @@ components: nativets, bun, php, + rust, + ansible, ] kind: type: string @@ -9211,6 +10030,8 @@ components: type: boolean codebase: type: string + has_preprocessor: + type: boolean required: - hash @@ -9228,6 +10049,7 @@ components: - kind - starred - no_main_func + - has_preprocessor NewScript: @@ -9267,6 +10089,8 @@ components: nativets, bun, php, + rust, + ansible, ] kind: type: string @@ -9307,6 +10131,8 @@ components: type: boolean codebase: type: string + has_preprocessor: + type: boolean required: - path - summary @@ -9484,6 +10310,8 @@ components: nativets, bun, php, + rust, + ansible, ] email: type: string @@ -9499,6 +10327,8 @@ components: type: number aggregate_wait_time_ms: type: number + suspend: + type: number required: - id - running @@ -9599,6 +10429,8 @@ components: nativets, bun, php, + rust, + ansible, ] is_skipped: type: boolean @@ -9755,6 +10587,8 @@ components: type: array items: type: string + email: + type: string required: - token_prefix - created_at @@ -9772,6 +10606,8 @@ components: type: array items: type: string + workspace_id: + type: string NewTokenImpersonate: type: object @@ -9783,6 +10619,8 @@ components: format: date-time impersonate_email: type: string + workspace_id: + type: string required: - impersonate_email @@ -9925,6 +10763,7 @@ components: - "users.delete" - "users.update" - "users.login" + - "users.login_failure" - "users.logout" - "users.accept_invite" - "users.decline_invite" @@ -9936,6 +10775,7 @@ components: - "users.impersonate" - "users.leave_workspace" - "oauth.login" + - "oauth.login_failure" - "oauth.signup" - "variables.create" - "variables.delete" @@ -10103,6 +10943,9 @@ components: no_main_func: type: boolean nullable: true + has_preprocessor: + type: boolean + nullable: true required: - star_args - start_kwargs @@ -10110,6 +10953,7 @@ components: - type - error - no_main_func + - has_preprocessor Preview: type: object @@ -10137,7 +10981,9 @@ components: graphql, nativets, bun, - php + php, + rust, + ansible, ] tag: type: string @@ -10285,6 +11131,8 @@ components: edited_at: type: string format: date-time + format_extension: + type: string required: - name @@ -10340,6 +11188,10 @@ components: type: number on_recovery_extra_args: $ref: "#/components/schemas/ScriptArgs" + on_success: + type: string + on_success_extra_args: + $ref: "#/components/schemas/ScriptArgs" ws_error_handler_muted: type: boolean retry: @@ -10418,6 +11270,10 @@ components: type: number on_recovery_extra_args: $ref: "#/components/schemas/ScriptArgs" + on_success: + type: string + on_success_extra_args: + $ref: "#/components/schemas/ScriptArgs" ws_error_handler_muted: type: boolean retry: @@ -10463,6 +11319,10 @@ components: type: number on_recovery_extra_args: $ref: "#/components/schemas/ScriptArgs" + on_success: + type: string + on_success_extra_args: + $ref: "#/components/schemas/ScriptArgs" ws_error_handler_muted: type: boolean retry: @@ -10483,6 +11343,261 @@ components: - is_flow - args + HttpTrigger: + type: object + properties: + path: + type: string + edited_by: + type: string + edited_at: + type: string + format: date-time + script_path: + type: string + route_path: + type: string + is_flow: + type: boolean + extra_perms: + type: object + additionalProperties: + type: boolean + email: + type: string + workspace_id: + type: string + http_method: + type: string + enum: + - get + - post + - put + - delete + - patch + is_async: + type: boolean + requires_auth: + type: boolean + + required: + - path + - edited_by + - edited_at + - script_path + - route_path + - extra_perms + - is_flow + - email + - workspace_id + - is_async + - requires_auth + - http_method + + NewHttpTrigger: + type: object + properties: + path: + type: string + script_path: + type: string + route_path: + type: string + is_flow: + type: boolean + http_method: + type: string + enum: + - get + - post + - put + - delete + - patch + is_async: + type: boolean + requires_auth: + type: boolean + + required: + - path + - script_path + - route_path + - is_flow + - is_async + - requires_auth + - http_method + + EditHttpTrigger: + type: object + properties: + path: + type: string + script_path: + type: string + route_path: + type: string + is_flow: + type: boolean + http_method: + type: string + enum: + - get + - post + - put + - delete + - patch + is_async: + type: boolean + requires_auth: + type: boolean + required: + - path + - script_path + - is_flow + - kind + - is_async + - requires_auth + - http_method + + TriggersCount: + type: object + properties: + primary_schedule: + type: object + properties: + schedule: + type: string + schedule_count: + type: number + http_routes_count: + type: number + webhook_count: + type: number + email_count: + type: number + websocket_count: + type: number + + WebsocketTrigger: + type: object + properties: + path: + type: string + edited_by: + type: string + edited_at: + type: string + format: date-time + script_path: + type: string + url: + type: string + is_flow: + type: boolean + extra_perms: + type: object + additionalProperties: + type: boolean + email: + type: string + workspace_id: + type: string + server_id: + type: string + last_server_ping: + type: string + format: date-time + error: + type: string + enabled: + type: boolean + filters: + type: array + items: + type: object + properties: + key: + type: string + value: {} + required: + - key + - value + + required: + - path + - edited_by + - edited_at + - script_path + - url + - extra_perms + - is_flow + - email + - workspace_id + - enabled + - filters + + NewWebsocketTrigger: + type: object + properties: + path: + type: string + script_path: + type: string + is_flow: + type: boolean + url: + type: string + enabled: + type: boolean + filters: + type: array + items: + type: object + properties: + key: + type: string + value: {} + required: + - key + - value + + required: + - path + - script_path + - url + - is_flow + - filters + + EditWebsocketTrigger: + type: object + properties: + url: + type: string + path: + type: string + script_path: + type: string + is_flow: + type: boolean + filters: + type: array + items: + type: object + properties: + key: + type: string + value: {} + required: + - key + - value + + required: + - path + - script_path + - url + - is_flow + - filters + Group: type: object properties: @@ -10564,12 +11679,18 @@ components: type: string wm_version: type: string - current_job_id: + last_job_id: type: string - current_job_workspace_id: + last_job_workspace_id: type: string occupancy_rate: type: number + occupancy_rate_15s: + type: number + occupancy_rate_5m: + type: number + occupancy_rate_30m: + type: number memory: type: number vcpus: @@ -10675,6 +11796,8 @@ components: type: string username: type: string + operator_only: + type: boolean required: - email @@ -11267,7 +12390,9 @@ components: graphql, nativets, bun, - php + php, + rust, + ansible, ] required: - raw_code @@ -11374,3 +12499,21 @@ components: properties: dancer: type: string + + AutoscalingEvent: + type: object + properties: + id: + type: integer + format: int64 + worker_group: + type: string + event_type: + type: string + desired_workers: + type: integer + reason: + type: string + applied_at: + type: string + format: date-time diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs index 9bfb84e34f..cd65136a2a 100644 --- a/backend/windmill-api/src/apps.rs +++ b/backend/windmill-api/src/apps.rs @@ -11,6 +11,7 @@ use crate::{ db::{ApiAuthed, DB}, resources::get_resource_value_interpolated_internal, users::{require_owner_of_path, OptAuthed}, + utils::WithStarredInfoQuery, variables::encrypt, webhook_util::{WebhookMessage, WebhookShared}, HTTP_CLIENT, @@ -61,6 +62,7 @@ pub fn workspaced_service() -> Router { .route("/delete/*path", delete(delete_app)) .route("/create", post(create_app)) .route("/history/p/*path", get(get_app_history)) + .route("/get_latest_version/*path", get(get_latest_version)) .route("/history_update/a/:id/v/:version", post(update_app_history)) } @@ -118,6 +120,15 @@ pub struct AppWithLastVersion { pub extra_perms: Option, } +#[derive(Serialize, FromRow)] +pub struct AppWithLastVersionAndStarred { + #[sqlx(flatten)] + #[serde(flatten)] + pub app: AppWithLastVersion, + #[serde(skip_serializing_if = "Option::is_none")] + pub starred: Option, +} + #[derive(Serialize, Deserialize, FromRow)] pub struct AppWithLastVersionAndDraft { pub id: i64, @@ -316,20 +327,44 @@ async fn get_app( authed: ApiAuthed, Extension(user_db): Extension, Path((w_id, path)): Path<(String, StripPath)>, -) -> JsonResult { + Query(query): Query, +) -> JsonResult { let path = path.to_path(); let mut tx = user_db.begin(&authed).await?; - let app_o = sqlx::query_as::<_, AppWithLastVersion>( - "SELECT app.id, app.path, app.summary, app.versions, app.policy, - app.extra_perms, app_version.value, - app_version.created_at, app_version.created_by from app, app_version - WHERE app.path = $1 AND app.workspace_id = $2 AND app_version.id = app.versions[array_upper(app.versions, 1)]", - ) - .bind(path.to_owned()) - .bind(&w_id) - .fetch_optional(&mut *tx) - .await?; + let app_o = if query.with_starred_info.unwrap_or(false) { + sqlx::query_as::<_, AppWithLastVersionAndStarred>( + "SELECT app.id, app.path, app.summary, app.versions, app.policy, + app.extra_perms, app_version.value, + app_version.created_at, app_version.created_by, favorite.path IS NOT NULL as starred + FROM app + JOIN app_version + ON app_version.id = app.versions[array_upper(app.versions, 1)] + LEFT JOIN favorite + ON favorite.favorite_kind = 'app' + AND favorite.workspace_id = app.workspace_id + AND favorite.path = app.path + AND favorite.usr = $3 + WHERE app.path = $1 AND app.workspace_id = $2", + ) + .bind(path.to_owned()) + .bind(&w_id) + .bind(&authed.username) + .fetch_optional(&mut *tx) + .await? + } else { + sqlx::query_as::<_, AppWithLastVersionAndStarred>( + "SELECT app.id, app.path, app.summary, app.versions, app.policy, + app.extra_perms, app_version.value, + app_version.created_at, app_version.created_by, NULL as starred + FROM app, app_version + WHERE app.path = $1 AND app.workspace_id = $2 AND app_version.id = app.versions[array_upper(app.versions, 1)]", + ) + .bind(path.to_owned()) + .bind(&w_id) + .fetch_optional(&mut *tx) + .await? + }; tx.commit().await?; let app = not_found_if_none(app_o, "App", path)?; @@ -393,6 +428,38 @@ async fn get_app_history( return Ok(Json(result)); } +async fn get_latest_version( + authed: ApiAuthed, + Extension(user_db): Extension, + Path((w_id, path)): Path<(String, StripPath)>, + +) -> JsonResult> { + + let mut tx = user_db.begin(&authed).await?; + let row = sqlx::query!( + "SELECT a.id as app_id, av.id as version_id, dm.deployment_msg as deployment_msg + FROM app a LEFT JOIN app_version av ON a.id = av.app_id LEFT JOIN deployment_metadata dm ON av.id = dm.app_version + WHERE a.workspace_id = $1 AND a.path = $2 + ORDER BY created_at DESC", + w_id, + path.to_path(), + ).fetch_optional(&mut *tx).await?; + tx.commit().await?; + + if let Some(row) = row { + let result = AppHistory { + app_id: row.app_id, + version: row.version_id, + deployment_msg: row.deployment_msg, + }; + + return Ok(Json(Some(result))); + } else { + return Ok(Json(None)); + } + +} + async fn update_app_history( authed: ApiAuthed, Extension(user_db): Extension, @@ -575,7 +642,7 @@ async fn create_app( } let exists = sqlx::query_scalar!( - "SELECT EXISTS(SELECT 1 FROM raw_app WHERE path = $1 AND workspace_id = $2)", + "SELECT EXISTS(SELECT 1 FROM app WHERE path = $1 AND workspace_id = $2)", &app.path, w_id ) diff --git a/backend/windmill-api/src/concurrency_groups.rs b/backend/windmill-api/src/concurrency_groups.rs index 9510dec475..945df75573 100644 --- a/backend/windmill-api/src/concurrency_groups.rs +++ b/backend/windmill-api/src/concurrency_groups.rs @@ -144,7 +144,7 @@ async fn get_concurrent_intervals( Query(iq): Query, Query(lq): Query, ) -> JsonResult { - check_scopes(&authed, || format!("listjobs"))?; + check_scopes(&authed, || format!("jobs:listjobs"))?; if lq.success.is_some() && lq.running.is_some_and(|x| x) { return Err(error::Error::BadRequest( diff --git a/backend/windmill-api/src/configs.rs b/backend/windmill-api/src/configs.rs index aacfd49ef7..81b65216e0 100644 --- a/backend/windmill-api/src/configs.rs +++ b/backend/windmill-api/src/configs.rs @@ -29,11 +29,15 @@ pub fn global_service() -> Router { .route("/update/:name", post(update_config).delete(delete_config)) .route("/get/:name", get(get_config)) .route("/list", get(list_configs)) + .route( + "/list_autoscaling_events/:worker_group", + get(list_autoscaling_events), + ) } #[derive(Serialize, Deserialize, FromRow)] struct Config { - name: String, + name: Option, config: serde_json::Value, } @@ -41,9 +45,18 @@ async fn list_worker_groups( authed: ApiAuthed, Extension(db): Extension, ) -> error::JsonResult> { - let configs_raw = sqlx::query_as!(Config, "SELECT * FROM config WHERE name LIKE 'worker__%'") - .fetch_all(&db) - .await?; + let mut configs_raw = + sqlx::query_as!(Config, "SELECT * FROM config WHERE name LIKE 'worker__%'") + .fetch_all(&db) + .await?; + // Remove the 'worker__' prefix from all config names + for config in configs_raw.iter_mut() { + if let Some(name) = &config.name { + if name.starts_with("worker__") { + config.name = Some(name.strip_prefix("worker__").unwrap().to_string()); + } + } + } let configs = if !authed.is_admin { let mut obfuscated_configs: Vec = vec![]; for config in configs_raw { @@ -168,6 +181,30 @@ async fn delete_config( Ok(format!("Deleted config {name}")) } +#[derive(Serialize, Deserialize, FromRow)] +struct AutoscalingEvent { + id: i64, + worker_group: String, + event_type: Option, + desired_workers: i32, + reason: Option, + applied_at: chrono::NaiveDateTime, +} + +async fn list_autoscaling_events( + Extension(db): Extension, + Path(worker_group): Path, +) -> error::JsonResult> { + let events = sqlx::query_as!( + AutoscalingEvent, + "SELECT id, worker_group, event_type::text, desired_workers, reason, applied_at FROM autoscaling_event WHERE worker_group = $1 ORDER BY applied_at DESC LIMIT 5", + worker_group + ) + .fetch_all(&db) + .await?; + Ok(Json(events)) +} + #[cfg(feature = "enterprise")] async fn list_configs( authed: ApiAuthed, diff --git a/backend/windmill-api/src/db.rs b/backend/windmill-api/src/db.rs index dc8a37149f..6186b0ada1 100644 --- a/backend/windmill-api/src/db.rs +++ b/backend/windmill-api/src/db.rs @@ -15,6 +15,7 @@ use sqlx::{ PgConnection, Pool, Postgres, }; use windmill_audit::audit_ee::{AuditAuthor, AuditAuthorable}; +use windmill_common::utils::generate_lock_id; use windmill_common::{ db::{Authable, Authed}, error::Error, @@ -29,13 +30,6 @@ async fn current_database(conn: &mut PgConnection) -> Result i64 { - const CRC_IEEE: crc::Crc = crc::Crc::::new(&crc::CRC_32_ISO_HDLC); - // 0x3d32ad9e chosen by fair dice roll - 0x3d32ad9e * (CRC_IEEE.checksum(database_name.as_bytes()) as i64) -} - struct CustomMigrator { inner: PoolConnection, } @@ -136,18 +130,30 @@ impl Migrate for CustomMigrator { migration.version, migration.description ); - if migration.version == 20240424083501 { - tracing::info!("Special migration to add index concurrently on job labels 2"); - sqlx::query!( - "DROP INDEX CONCURRENTLY IF EXISTS labeled_jobs_on_jobs" - ).execute(&mut *self.inner).await?; - sqlx::query!( - "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_label';" - ).execute(&mut *self.inner).await?; + if migration.version == 20221207103910 { + tracing::info!("Skipping migration 20221207103910 to avoid using md5"); + self.inner + .execute(include_str!( + "../../custom_migrations/create_workspace_without_md5.sql" + )) + .await?; + let _ = sqlx::query( + r#" + INSERT INTO _sqlx_migrations ( version, description, success, checksum, execution_time ) + VALUES ( $1, $2, TRUE, $3, -1 ) ON CONFLICT DO NOTHING + "#, + ) + .bind(migration.version) + .bind(&*migration.description) + .bind(&*migration.checksum) + .execute(&mut *self.inner) + .await?; + return Ok(std::time::Duration::from_secs(0)); + } else { + let r = self.inner.apply(migration).await; + tracing::info!("Finished applying migration {}", migration.version); + return r; } - let r = self.inner.apply(migration).await; - tracing::info!("Finished applying migration {}", migration.version); - r } .boxed() } @@ -167,17 +173,6 @@ pub async fn migrate(db: &DB) -> Result<(), Error> { let migrator = db.acquire().await?; let mut custom_migrator = CustomMigrator { inner: migrator }; - if let Err(err) = fix_flow_versioning_migration(&mut custom_migrator, db).await { - tracing::error!("Could not apply flow versioning fix migration: {err:#}"); - } - - let db2 = db.clone(); - let _ = tokio::task::spawn(async move { - if let Err(err) = fix_job_completed_index(&db2).await { - tracing::error!("Could not apply job completed index fix migration: {err:#}"); - } - }); - match sqlx::migrate!("../migrations") .run_direct(&mut custom_migrator) .await @@ -193,11 +188,17 @@ pub async fn migrate(db: &DB) -> Result<(), Error> { Err(err) => Err(err), }?; - #[cfg(feature = "enterprise")] - if let Err(e) = windmill_migrations(&mut custom_migrator, db).await { - tracing::error!("Could not apply windmill custom migrations: {e:#}") + if let Err(err) = fix_flow_versioning_migration(&mut custom_migrator, db).await { + tracing::error!("Could not apply flow versioning fix migration: {err:#}"); } + let db2 = db.clone(); + let _ = tokio::task::spawn(async move { + if let Err(err) = fix_job_completed_index(&db2).await { + tracing::error!("Could not apply job completed index fix migration: {err:#}"); + } + }); + Ok(()) } @@ -248,6 +249,75 @@ async fn fix_flow_versioning_migration( Ok(()) } +macro_rules! run_windmill_migration { + ($migration_job_name:expr, $db:expr, $code:block) => { + { + let migration_job_name = $migration_job_name; + let db: &Pool = $db; + + let has_done_migration = sqlx::query_scalar!( + "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)", + migration_job_name + ) + .fetch_one(db) + .await? + .unwrap_or(false); + if !has_done_migration { + tracing::info!("Applying {migration_job_name} migration"); + let mut tx = db.begin().await?; + let mut r = false; + while !r { + r = sqlx::query_scalar!("SELECT pg_try_advisory_lock(4242)") + .fetch_one(&mut *tx) + .await + .map_err(|e| { + tracing::error!("Error acquiring {migration_job_name} lock: {e:#}"); + sqlx::migrate::MigrateError::Execute(e) + })? + .unwrap_or(false); + if !r { + tracing::info!("PG {migration_job_name} lock already acquired by another server or worker, retrying in 5s. (look for the advisory lock in pg_lock with granted = true)"); + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } + } + tracing::info!("acquired lock for {migration_job_name}"); + + let has_done_migration = sqlx::query_scalar!( + "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)", + migration_job_name + ) + .fetch_one(db) + .await? + .unwrap_or(false); + + if !has_done_migration { + + $code + + sqlx::query!( + "INSERT INTO windmill_migrations (name) VALUES ($1) ON CONFLICT DO NOTHING", + migration_job_name + ) + .execute(&mut *tx) + .await?; + tracing::info!("Finished applying {migration_job_name} migration"); + } else { + tracing::debug!("migration {migration_job_name} already done"); + } + + let _ = sqlx::query("SELECT pg_advisory_unlock(4242)") + .execute(&mut *tx) + .await?; + tx.commit().await?; + tracing::info!("released lock for {migration_job_name}"); + } else { + tracing::debug!("migration {migration_job_name} already done"); + + } + } + }; +} + async fn fix_job_completed_index(db: &DB) -> Result<(), Error> { // let has_done_migration = sqlx::query_scalar!( // "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = 'fix_job_completed_index')" @@ -290,312 +360,135 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> { // tx.commit().await?; // } - let migration_job_name = "fix_job_completed_index_2"; - let has_done_migration = sqlx::query_scalar!( - "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)", - migration_job_name - ) - .fetch_one(db) - .await? - .unwrap_or(false); - if !has_done_migration { - tracing::info!("Applying {migration_job_name} migration"); - let mut tx = db.begin().await?; - let mut r = false; - while !r { - r = sqlx::query_scalar!("SELECT pg_try_advisory_lock(4242)") - .fetch_one(&mut *tx) - .await - .map_err(|e| { - tracing::error!("Error acquiring {migration_job_name} lock: {e:#}"); - sqlx::migrate::MigrateError::Execute(e) - })? - .unwrap_or(false); - if !r { - tracing::info!("PG {migration_job_name} lock already acquired by another server or worker, retrying in 5s. (look for the advisory lock in pg_lock with granted = true)"); - tokio::time::sleep(std::time::Duration::from_secs(5)).await; - } - } + run_windmill_migration!("fix_job_completed_index_2", &db, { + // sqlx::query( + // "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_completed_job_workspace_id_created_at_new_2 ON completed_job (workspace_id, job_kind, success, is_skipped, is_flow_step, created_at DESC)" + // ).execute(db).await?; - tracing::info!("acquired lock for {migration_job_name}"); - let has_done_migration = sqlx::query_scalar!( - "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)", - migration_job_name + // sqlx::query( + // "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_completed_job_workspace_id_started_at_new ON completed_job (workspace_id, job_kind, success, is_skipped, is_flow_step, started_at DESC)" + // ).execute(db).await?; + + sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at") + .execute(db) + .await?; + + sqlx::query( + "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at_new", ) - .fetch_one(db) - .await? - .unwrap_or(false); + .execute(db) + .await?; + }); - if !has_done_migration { - // sqlx::query( - // "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_completed_job_workspace_id_created_at_new_2 ON completed_job (workspace_id, job_kind, success, is_skipped, is_flow_step, created_at DESC)" - // ).execute(db).await?; - - // sqlx::query( - // "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_completed_job_workspace_id_started_at_new ON completed_job (workspace_id, job_kind, success, is_skipped, is_flow_step, started_at DESC)" - // ).execute(db).await?; - - sqlx::query( - "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at", - ) + run_windmill_migration!("fix_job_completed_index_3", &db, { + sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS index_completed_job_on_schedule_path") .execute(db) .await?; - sqlx::query( - "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at_new", - ) + sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS concurrency_limit_stats_queue") .execute(db) .await?; - sqlx::query!( - "INSERT INTO windmill_migrations (name) VALUES ($1) ON CONFLICT DO NOTHING", - migration_job_name - ) - .execute(&mut *tx) - .await?; - tracing::info!("Finished applying {migration_job_name} migration"); - } else { - tracing::info!("migration {migration_job_name} already done"); - } - - let _ = sqlx::query("SELECT pg_advisory_unlock(4242)") - .execute(&mut *tx) - .await?; - tx.commit().await?; - tracing::info!("released lock for {migration_job_name}"); - } - - let migration_job_name = "fix_job_completed_index_3"; - let has_done_migration = sqlx::query_scalar!( - "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)", - migration_job_name - ) - .fetch_one(db) - .await? - .unwrap_or(false); - if !has_done_migration { - tracing::info!("Applying {migration_job_name} migration"); - let mut tx = db.begin().await?; - let mut r = false; - while !r { - r = sqlx::query_scalar!("SELECT pg_try_advisory_lock(4242)") - .fetch_one(&mut *tx) - .await - .map_err(|e| { - tracing::error!("Error acquiring {migration_job_name} lock: {e:#}"); - sqlx::migrate::MigrateError::Execute(e) - })? - .unwrap_or(false); - if !r { - tracing::info!("PG {migration_job_name} lock already acquired by another server or worker, retrying in 5s. (look for the advisory lock in pg_lock with granted = true)"); - tokio::time::sleep(std::time::Duration::from_secs(5)).await; - } - } - tracing::info!("acquired lock for {migration_job_name}"); - - let has_done_migration = sqlx::query_scalar!( - "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)", - migration_job_name - ) - .fetch_one(db) - .await? - .unwrap_or(false); - - if !has_done_migration { - sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS index_completed_job_on_schedule_path") - .execute(db) - .await?; - - sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS concurrency_limit_stats_queue") - .execute(db) - .await?; - - sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS root_job_index") - .execute(db) - .await?; - - sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS index_completed_on_created") - .execute(db) - .await?; - - sqlx::query!( - "INSERT INTO windmill_migrations (name) VALUES ($1) ON CONFLICT DO NOTHING", - migration_job_name - ) - .execute(&mut *tx) - .await?; - tracing::info!("Finished applying {migration_job_name} migration"); - } else { - tracing::info!("migration {migration_job_name} already done"); - } - - let _ = sqlx::query("SELECT pg_advisory_unlock(4242)") - .execute(&mut *tx) - .await?; - tx.commit().await?; - tracing::info!("released lock for {migration_job_name}"); - } - - let migration_job_name = "fix_job_completed_index_4"; - let has_done_migration = sqlx::query_scalar!( - "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)", - migration_job_name - ) - .fetch_one(db) - .await? - .unwrap_or(false); - if !has_done_migration { - tracing::info!("Applying {migration_job_name} migration"); - let mut tx = db.begin().await?; - let mut r = false; - while !r { - r = sqlx::query_scalar!("SELECT pg_try_advisory_lock(4242)") - .fetch_one(&mut *tx) - .await - .map_err(|e| { - tracing::error!("Error acquiring {migration_job_name} lock: {e:#}"); - sqlx::migrate::MigrateError::Execute(e) - })? - .unwrap_or(false); - if !r { - tracing::info!("PG {migration_job_name} lock already acquired by another server or worker, retrying in 5s. (look for the advisory lock in pg_lock with granted = true)"); - tokio::time::sleep(std::time::Duration::from_secs(5)).await; - } - } - tracing::info!("acquired lock for {migration_job_name}"); - - let has_done_migration = sqlx::query_scalar!( - "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)", - migration_job_name - ) - .fetch_one(db) - .await? - .unwrap_or(false); - - if !has_done_migration { - let mut i = 1; - tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_3 ON completed_job (workspace_id, created_at DESC)") - .execute(db) - .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); - - sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_8 ON completed_job (workspace_id, created_at DESC) where job_kind in ('deploymentcallback') AND parent_job IS NULL") + sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS root_job_index") .execute(db) .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_9 ON completed_job (workspace_id, created_at DESC) where job_kind in ('dependencies', 'flowdependencies', 'appdependencies') AND parent_job IS NULL") + sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS index_completed_on_created") .execute(db) .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); + }); - sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_5 ON completed_job (workspace_id, created_at DESC) where job_kind in ('preview', 'flowpreview') AND parent_job IS NULL") + run_windmill_migration!("fix_job_completed_index_4", &db, { + let migration_job_name = "fix_job_completed_index_4"; + let mut i = 1; + tracing::info!("step {i} of {migration_job_name} migration"); + sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_3 ON completed_job (workspace_id, created_at DESC)") .execute(db) .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_6 ON completed_job (workspace_id, created_at DESC) where job_kind in ('script', 'flow') AND parent_job IS NULL") + sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_8 ON completed_job (workspace_id, created_at DESC) where job_kind in ('deploymentcallback') AND parent_job IS NULL") + .execute(db) + .await?; + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); + + sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_9 ON completed_job (workspace_id, created_at DESC) where job_kind in ('dependencies', 'flowdependencies', 'appdependencies') AND parent_job IS NULL") + .execute(db) + .await?; + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); + + sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_5 ON completed_job (workspace_id, created_at DESC) where job_kind in ('preview', 'flowpreview') AND parent_job IS NULL") .execute(db) .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_7 ON completed_job (workspace_id, success, created_at DESC) where job_kind in ('script', 'flow') AND parent_job IS NULL") + sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_6 ON completed_job (workspace_id, created_at DESC) where job_kind in ('script', 'flow') AND parent_job IS NULL") .execute(db) .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_started_at_new_2 ON completed_job (workspace_id, started_at DESC)") + sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_7 ON completed_job (workspace_id, success, created_at DESC) where job_kind in ('script', 'flow') AND parent_job IS NULL") .execute(db) .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query("create index concurrently if not exists root_job_index_by_path_2 ON completed_job (workspace_id, script_path, created_at desc) WHERE parent_job IS NULL") + sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_started_at_new_2 ON completed_job (workspace_id, started_at DESC)") + .execute(db) + .await?; + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); + + sqlx::query("create index concurrently if not exists root_job_index_by_path_2 ON completed_job (workspace_id, script_path, created_at desc) WHERE parent_job IS NULL") .execute(db) .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query("create index concurrently if not exists ix_completed_job_created_at ON completed_job (created_at DESC)") + sqlx::query("create index concurrently if not exists ix_completed_job_created_at ON completed_job (created_at DESC)") .execute(db) .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query( - "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at_new_2", - ) - .execute(db) - .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); - - sqlx::query( - "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_started_at_new", - ) - .execute(db) - .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); - - sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS root_job_index_by_path") - .execute(db) - .await?; - - sqlx::query!( - "INSERT INTO windmill_migrations (name) VALUES ($1) ON CONFLICT DO NOTHING", - migration_job_name - ) - .execute(&mut *tx) - .await?; - tracing::info!("Finished applying {migration_job_name} migration"); - } else { - tracing::info!("migration {migration_job_name} already done"); - } - - let _ = sqlx::query("SELECT pg_advisory_unlock(4242)") - .execute(&mut *tx) - .await?; - tx.commit().await?; - tracing::info!("released lock for {migration_job_name}"); - } - - Ok(()) -} - -#[cfg(feature = "enterprise")] -async fn windmill_migrations(migrator: &mut CustomMigrator, db: &DB) -> Result<(), Error> { - if std::env::var("MIGRATION_NO_BYPASSRLS").is_ok() { - migrator.lock().await?; - let has_done_migration = sqlx::query_scalar!( - "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = 'bypassrls_1-2')", + sqlx::query( + "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at_new_2", ) - .fetch_one(db) - .await? - .unwrap_or(false); + .execute(db) + .await?; + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); + + sqlx::query( + "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_started_at_new", + ) + .execute(db) + .await?; + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); + + sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS root_job_index_by_path") + .execute(db) + .await?; + }); + + run_windmill_migration!("fix_labeled_jobs_index", &db, { + tracing::info!("Special migration to add index concurrently on job labels 2"); + sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS labeled_jobs_on_jobs") + .execute(db) + .await?; + sqlx::query!( + "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_labels'" + ).execute(db).await?; + }); - if !has_done_migration { - let query = include_str!("../../custom_migrations/bypassrls_1.sql"); - tracing::info!("Applying bypassrls_1.sql"); - let mut tx: sqlx::Transaction<'_, Postgres> = db.begin().await?; - tx.execute(query).await?; - tracing::info!("Applied bypassrls_1.sql"); - sqlx::query!("INSERT INTO windmill_migrations (name) VALUES ('bypassrls_1-2')") - .execute(&mut *tx) - .await?; - tx.commit().await?; - } - migrator.unlock().await?; - } Ok(()) } diff --git a/backend/windmill-api/src/ee.rs b/backend/windmill-api/src/ee.rs index b20521e8b4..cddb639e95 100644 --- a/backend/windmill-api/src/ee.rs +++ b/backend/windmill-api/src/ee.rs @@ -4,7 +4,7 @@ use std::sync::Arc; #[cfg(feature = "enterprise")] use tokio::sync::RwLock; -pub async fn validate_license_key(_license_key: String) -> anyhow::Result { +pub async fn validate_license_key(_license_key: String) -> anyhow::Result<(String, bool)> { // Implementation is not open source Err(anyhow!("License can't be validated in Windmill CE")) } diff --git a/backend/windmill-api/src/embeddings.rs b/backend/windmill-api/src/embeddings.rs index 5cc7226753..fd222bdbfa 100644 --- a/backend/windmill-api/src/embeddings.rs +++ b/backend/windmill-api/src/embeddings.rs @@ -53,6 +53,7 @@ use crate::{resources::ResourceType, HTTP_CLIENT}; lazy_static::lazy_static! { pub static ref EMBEDDINGS_DB: Arc>> = Arc::new(RwLock::new(None)); pub static ref MODEL_INSTANCE: Arc>>> = Arc::new(RwLock::new(None)); + pub static ref HUB_EMBEDDINGS_PULLING_INTERVAL_SECS: u64 = std::env::var("HUB_EMBEDDINGS_PULLING_INTERVAL_SECS").ok().map(|x| x.parse::().ok()).flatten().unwrap_or(3600 * 24); } #[cfg(feature = "embedding")] @@ -607,7 +608,10 @@ pub fn load_embeddings_db(db: &Pool) -> () { drop(model_instance_lock); loop { update_embeddings_db(&db_clone).await; - tokio::time::sleep(std::time::Duration::from_secs(3600 * 24)).await; + tokio::time::sleep(std::time::Duration::from_secs( + *HUB_EMBEDDINGS_PULLING_INTERVAL_SECS, + )) + .await; } } else { tracing::error!( diff --git a/backend/windmill-api/src/flows.rs b/backend/windmill-api/src/flows.rs index ccec53c4dc..4fc9ce514f 100644 --- a/backend/windmill-api/src/flows.rs +++ b/backend/windmill-api/src/flows.rs @@ -9,6 +9,10 @@ use std::collections::HashMap; use crate::db::ApiAuthed; +use crate::triggers::{ + get_triggers_count_internal, list_tokens_internal, TriggersCount, TruncatedTokenWithEmail, +}; +use crate::utils::WithStarredInfoQuery; use crate::{ db::DB, schedule::clear_schedule, @@ -35,7 +39,7 @@ use windmill_common::HUB_BASE_URL; use windmill_common::{ db::UserDB, error::{self, to_anyhow, Error, JsonResult, Result}, - flows::{Flow, ListFlowQuery, ListableFlow, NewFlow}, + flows::{Flow, FlowWithStarred, ListFlowQuery, ListableFlow, NewFlow}, jobs::JobPayload, schedule::Schedule, scripts::Schema, @@ -52,11 +56,14 @@ pub fn workspaced_service() -> Router { .route("/update/*path", post(update_flow)) .route("/archive/*path", post(archive_flow_by_path)) .route("/delete/*path", delete(delete_flow_by_path)) + .route("/get_triggers_count/*path", get(get_triggers_count)) + .route("/list_tokens/*path", get(list_tokens)) .route("/get/*path", get(get_flow_by_path)) .route("/get/draft/*path", get(get_flow_by_path_w_draft)) .route("/exists/*path", get(exists_flow_by_path)) .route("/list_paths", get(list_paths)) .route("/history/p/*path", get(get_flow_history)) + .route("/get_latest_version/*path", get(get_latest_version)) .route( "/history_update/v/:version/p/*path", post(update_flow_history), @@ -241,6 +248,7 @@ pub async fn get_hub_flow_by_id( #[derive(Deserialize)] pub struct ToggleWorkspaceErrorHandler { + #[cfg(feature = "enterprise")] pub muted: Option, } @@ -531,6 +539,30 @@ async fn get_flow_history( Ok(Json(flows)) } +async fn get_latest_version( + authed: ApiAuthed, + Extension(user_db): Extension, + Path((w_id, path)): Path<(String, StripPath)>, +) -> JsonResult> { + let path = path.to_path(); + let mut tx = user_db.begin(&authed).await?; + + let version = sqlx::query_as!( + FlowVersion, + "SELECT flow_version.id, flow_version.created_at, deployment_metadata.deployment_msg FROM flow_version + LEFT JOIN deployment_metadata ON flow_version.id = deployment_metadata.flow_version + WHERE flow_version.path = $1 AND flow_version.workspace_id = $2 + ORDER BY flow_version.created_at DESC", + path, + w_id + ) + .fetch_optional(&mut *tx) + .await?; + tx.commit().await?; + + Ok(Json(version)) +} + async fn get_flow_version( authed: ApiAuthed, Extension(user_db): Extension, @@ -872,17 +904,51 @@ async fn update_flow( Ok(nf.path.to_string()) } +async fn get_triggers_count( + Extension(db): Extension, + Path((w_id, path)): Path<(String, StripPath)>, +) -> JsonResult { + let path = path.to_path(); + get_triggers_count_internal(&db, &w_id, &path, true).await +} + +async fn list_tokens( + Extension(db): Extension, + Path((w_id, path)): Path<(String, StripPath)>, +) -> JsonResult> { + let path = path.to_path(); + list_tokens_internal(&db, &w_id, &path, true).await +} + async fn get_flow_by_path( authed: ApiAuthed, Extension(user_db): Extension, Path((w_id, path)): Path<(String, StripPath)>, -) -> JsonResult { + Query(query): Query, +) -> JsonResult { let path = path.to_path(); let mut tx = user_db.begin(&authed).await?; - let flow_o = - sqlx::query_as::<_, Flow>( - "SELECT flow.workspace_id, flow.path, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by + let flow_o = if query.with_starred_info.unwrap_or(false) { + sqlx::query_as::<_, FlowWithStarred>( + "SELECT flow.workspace_id, flow.path, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by, favorite.path IS NOT NULL as starred + FROM flow + LEFT JOIN favorite + ON favorite.favorite_kind = 'flow' + AND favorite.workspace_id = flow.workspace_id + AND favorite.path = flow.path + AND favorite.usr = $3 + LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] + WHERE flow.path = $1 AND flow.workspace_id = $2" + ) + .bind(path) + .bind(w_id) + .bind(&authed.username) + .fetch_optional(&mut *tx) + .await? + } else { + sqlx::query_as::<_, FlowWithStarred>( + "SELECT flow.workspace_id, flow.path, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by, NULL as starred FROM flow LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] WHERE flow.path = $1 AND flow.workspace_id = $2" @@ -890,7 +956,8 @@ async fn get_flow_by_path( .bind(path) .bind(w_id) .fetch_optional(&mut *tx) - .await?; + .await? + }; tx.commit().await?; let flow = not_found_if_none(flow_o, "Flow", path)?; @@ -1144,6 +1211,7 @@ mod tests { tag_override: None, }), stop_after_if: None, + stop_after_all_iters_if: None, summary: None, suspend: Default::default(), retry: None, @@ -1154,6 +1222,7 @@ mod tests { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }, FlowModule { id: "b".to_string(), @@ -1172,6 +1241,7 @@ mod tests { expr: "foo = 'bar'".to_string(), skip_if_stopped: false, }), + stop_after_all_iters_if: None, summary: None, suspend: Default::default(), retry: None, @@ -1182,6 +1252,7 @@ mod tests { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }, FlowModule { id: "c".to_string(), @@ -1198,6 +1269,7 @@ mod tests { expr: "previous.isEmpty()".to_string(), skip_if_stopped: false, }), + stop_after_all_iters_if: None, summary: None, suspend: Default::default(), retry: None, @@ -1208,6 +1280,7 @@ mod tests { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, }, ], failure_module: Some(Box::new(FlowModule { @@ -1223,6 +1296,7 @@ mod tests { expr: "previous.isEmpty()".to_string(), skip_if_stopped: false, }), + stop_after_all_iters_if: None, summary: None, suspend: Default::default(), retry: None, @@ -1233,7 +1307,9 @@ mod tests { priority: None, delete_after_use: None, continue_on_error: None, + skip_if: None, })), + preprocessor_module: None, same_worker: false, concurrent_limit: None, concurrency_time_window_s: None, @@ -1256,7 +1332,6 @@ mod tests { }, "type": "script", "path": "test", - "tag_override": Option::::None, }, }, { @@ -1300,13 +1375,12 @@ mod tests { "input_transforms": {}, "type": "script", "path": "test", - "tag_override": Option::::None, }, "stop_after_if": { "expr": "previous.isEmpty()", "skip_if_stopped": false } - } + }, }); assert_eq!(dbg!(serde_json::json!(fv)), dbg!(expect)); } diff --git a/backend/windmill-api/src/folders.rs b/backend/windmill-api/src/folders.rs index fef5b7fe07..c9b69836c6 100644 --- a/backend/windmill-api/src/folders.rs +++ b/backend/windmill-api/src/folders.rs @@ -275,8 +275,10 @@ pub fn require_is_owner(authed: &ApiAuthed, name: &str) -> Result<()> { async fn update_folder( authed: ApiAuthed, + Extension(db): Extension, Extension(user_db): Extension, Extension(webhook): Extension, + Extension(rsmq): Extension>, Path((w_id, name)): Path<(String, String)>, Json(mut ng): Json, ) -> Result { @@ -367,6 +369,18 @@ async fn update_folder( } } + handle_deployment_metadata( + &authed.email, + &authed.username, + &db, + &w_id, + DeployedObject::Folder { path: format!("f/{}", name) }, + Some(format!("Folder '{}' updated", name)), + rsmq, + true, + ) + .await?; + audit_log( &mut *tx, &authed, diff --git a/backend/windmill-api/src/granular_acls.rs b/backend/windmill-api/src/granular_acls.rs index f7c984d0e7..ad5793816b 100644 --- a/backend/windmill-api/src/granular_acls.rs +++ b/backend/windmill-api/src/granular_acls.rs @@ -23,6 +23,19 @@ use windmill_common::{ utils::{not_found_if_none, StripPath}, }; +const KINDS: [&str; 10] = [ + "script", + "group_", + "resource", + "schedule", + "variable", + "flow", + "folder", + "app", + "raw_app", + "http_trigger", +]; + pub fn workspaced_service() -> Router { Router::new() .route("/get/*path", get(get_granular_acls)) @@ -49,6 +62,11 @@ async fn add_granular_acl( let (kind, path) = path .split_once('/') .ok_or_else(|| Error::BadRequest("Invalid path or kind".to_string()))?; + + if !KINDS.contains(&kind) { + return Err(Error::BadRequest("Invalid kind".to_string())); + } + let mut tx = user_db.begin(&authed).await?; let identifier = if kind == "group_" || kind == "folder" { @@ -69,9 +87,10 @@ async fn add_granular_acl( } let obj_o = sqlx::query_scalar::<_, serde_json::Value>(&format!( - "UPDATE {kind} SET extra_perms = jsonb_set(extra_perms, '{{\"{owner}\"}}', to_jsonb($1), \ - true) WHERE {identifier} = $2 AND workspace_id = $3 RETURNING extra_perms" + "UPDATE {kind} SET extra_perms = jsonb_set(extra_perms, $1, to_jsonb($2), \ + true) WHERE {identifier} = $3 AND workspace_id = $4 RETURNING extra_perms" )) + .bind(vec![owner]) .bind(write.unwrap_or(false)) .bind(path) .bind(&w_id) @@ -158,6 +177,10 @@ async fn remove_granular_acl( .split_once('/') .ok_or_else(|| Error::BadRequest("Invalid path or kind".to_string()))?; + if !KINDS.contains(&kind) { + return Err(Error::BadRequest("Invalid kind".to_string())); + } + if !authed.is_admin { if kind == "folder" { crate::folders::require_is_owner(&authed, path)?; @@ -267,6 +290,10 @@ async fn get_granular_acls( .split_once('/') .ok_or_else(|| Error::BadRequest("Invalid path or kind".to_string()))?; + if !KINDS.contains(&kind) { + return Err(Error::BadRequest("Invalid kind".to_string())); + } + let mut tx = user_db.begin(&authed).await?; let identifier = if kind == "group_" { "name" } else { "path" }; diff --git a/backend/windmill-api/src/http_triggers.rs b/backend/windmill-api/src/http_triggers.rs new file mode 100644 index 0000000000..61757cb164 --- /dev/null +++ b/backend/windmill-api/src/http_triggers.rs @@ -0,0 +1,615 @@ +use axum::{ + extract::{Path, Query}, + response::IntoResponse, + routing::{delete, get, post}, + Extension, Json, Router, +}; +use http::{HeaderMap, StatusCode}; +use serde::{Deserialize, Serialize}; +use sql_builder::{bind::Bind, SqlBuilder}; +use sqlx::prelude::FromRow; +use std::collections::HashMap; +use tower_http::cors::CorsLayer; +use windmill_audit::{audit_ee::audit_log, ActionKind}; +use windmill_common::{ + db::UserDB, + error::{self, JsonResult}, + utils::{not_found_if_none, paginate, require_admin, Pagination, StripPath}, + worker::{to_raw_value, CLOUD_HOSTED}, +}; +use windmill_queue::PushArgsOwned; + +use crate::{ + db::{ApiAuthed, DB}, + jobs::{ + run_flow_by_path_inner, run_script_by_path_inner, run_wait_result_flow_by_path_internal, + run_wait_result_script_by_path_internal, RunJobQuery, + }, + users::{fetch_api_authed, OptAuthed}, +}; + +lazy_static::lazy_static! { + static ref ROUTE_PATH_KEY_RE: regex::Regex = regex::Regex::new(r"/:\w+").unwrap(); +} + +pub fn routes_global_service() -> Router { + let cors = CorsLayer::new() + .allow_methods([ + http::Method::GET, + http::Method::POST, + http::Method::DELETE, + http::Method::PUT, + http::Method::PATCH, + ]) + .allow_headers([http::header::CONTENT_TYPE, http::header::AUTHORIZATION]) + .allow_origin(tower_http::cors::Any); + Router::new() + .route( + "/*path", + get(route_job) + .post(route_job) + .delete(route_job) + .put(route_job) + .patch(route_job) + .head(|| async { "" }), + ) + .layer(cors) +} + +pub fn workspaced_service() -> Router { + Router::new() + .route("/create", post(create_trigger)) + .route("/list", get(list_triggers)) + .route("/get/*path", get(get_trigger)) + .route("/update/*path", post(update_trigger)) + .route("/delete/*path", delete(delete_trigger)) + .route("/exists/*path", get(exists_trigger)) + .route("/route_exists", post(exists_route)) +} + +#[derive(Serialize, Deserialize, sqlx::Type)] +#[sqlx(type_name = "HTTP_METHOD", rename_all = "lowercase")] +#[serde(rename_all = "lowercase")] +enum HttpMethod { + Get, + Post, + Put, + Delete, + Patch, +} + +impl From for http::Method { + fn from(method: HttpMethod) -> Self { + match method { + HttpMethod::Get => http::Method::GET, + HttpMethod::Post => http::Method::POST, + HttpMethod::Put => http::Method::PUT, + HttpMethod::Delete => http::Method::DELETE, + HttpMethod::Patch => http::Method::PATCH, + } + } +} + +#[derive(Deserialize)] +struct NewTrigger { + path: String, + route_path: String, + script_path: String, + is_flow: bool, + is_async: bool, + requires_auth: bool, + http_method: HttpMethod, +} + +#[derive(FromRow, Serialize)] +struct Trigger { + workspace_id: String, + path: String, + route_path: String, + route_path_key: String, + script_path: String, + is_flow: bool, + edited_by: String, + email: String, + edited_at: chrono::DateTime, + extra_perms: serde_json::Value, + is_async: bool, + requires_auth: bool, + http_method: HttpMethod, +} + +#[derive(Deserialize)] +struct EditTrigger { + path: String, + route_path: Option, + script_path: String, + is_flow: bool, + is_async: bool, + requires_auth: bool, + http_method: HttpMethod, +} + +#[derive(Deserialize)] +pub struct ListTriggerQuery { + pub page: Option, + pub per_page: Option, + pub path: Option, + pub is_flow: Option, + pub path_start: Option, +} + +async fn list_triggers( + authed: ApiAuthed, + Extension(user_db): Extension, + Path(w_id): Path, + Query(lst): Query, +) -> error::JsonResult> { + let mut tx = user_db.begin(&authed).await?; + let (per_page, offset) = paginate(Pagination { per_page: lst.per_page, page: lst.page }); + let mut sqlb = SqlBuilder::select_from("http_trigger") + .field("*") + .order_by("edited_at", true) + .and_where("workspace_id = ?".bind(&w_id)) + .offset(offset) + .limit(per_page) + .clone(); + if let Some(path) = lst.path { + sqlb.and_where_eq("script_path", "?".bind(&path)); + } + if let Some(is_flow) = lst.is_flow { + sqlb.and_where_eq("is_flow", "?".bind(&is_flow)); + } + if let Some(path_start) = &lst.path_start { + sqlb.and_where_like_left("path", path_start); + } + let sql = sqlb + .sql() + .map_err(|e| error::Error::InternalErr(e.to_string()))?; + let rows = sqlx::query_as::<_, Trigger>(&sql) + .fetch_all(&mut *tx) + .await?; + tx.commit().await?; + + Ok(Json(rows)) +} + +async fn get_trigger( + authed: ApiAuthed, + Extension(user_db): Extension, + Path((w_id, path)): Path<(String, StripPath)>, +) -> error::JsonResult { + let mut tx = user_db.begin(&authed).await?; + let path = path.to_path(); + let trigger = sqlx::query_as!( + Trigger, + r#"SELECT workspace_id, path, route_path, route_path_key, script_path, is_flow, http_method as "http_method: _", edited_by, email, edited_at, extra_perms, is_async, requires_auth + FROM http_trigger + WHERE workspace_id = $1 AND path = $2"#, + w_id, + path, + ) + .fetch_optional(&mut *tx) + .await?; + tx.commit().await?; + + let trigger = not_found_if_none(trigger, "Trigger", path)?; + + Ok(Json(trigger)) +} + +async fn create_trigger( + authed: ApiAuthed, + Extension(user_db): Extension, + Path(w_id): Path, + Json(ct): Json, +) -> error::Result<(StatusCode, String)> { + require_admin(authed.is_admin, &authed.username)?; + + let route_path_key = ROUTE_PATH_KEY_RE.replace_all(ct.route_path.as_str(), ":key"); + + let mut tx = user_db.begin(&authed).await?; + sqlx::query!( + "INSERT INTO http_trigger (workspace_id, path, route_path, route_path_key, script_path, is_flow, is_async, requires_auth, http_method, edited_by, email, edited_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, now())", + w_id, + ct.path, + ct.route_path, + &route_path_key, + ct.script_path, + ct.is_flow, + ct.is_async, + ct.requires_auth, + ct.http_method as HttpMethod, + &authed.username, + &authed.email + ) + .execute(&mut *tx).await?; + + audit_log( + &mut *tx, + &authed, + "http_triggers.create", + ActionKind::Create, + &w_id, + Some(ct.path.as_str()), + None, + ) + .await?; + + tx.commit().await?; + + Ok((StatusCode::CREATED, format!("{}", ct.path))) +} + +async fn update_trigger( + authed: ApiAuthed, + Extension(user_db): Extension, + Path((w_id, path)): Path<(String, StripPath)>, + Json(ct): Json, +) -> error::Result { + let path = path.to_path(); + let mut tx = user_db.begin(&authed).await?; + + if authed.is_admin { + if ct.route_path.is_none() { + return Err(error::Error::BadRequest( + "route_path is required".to_string(), + )); + } + + let route_path_key = + ROUTE_PATH_KEY_RE.replace_all(ct.route_path.as_ref().unwrap().as_str(), ":key"); + + sqlx::query!( + "UPDATE http_trigger + SET route_path = $1, route_path_key = $2, script_path = $3, path = $4, is_flow = $5, http_method = $6, edited_by = $7, email = $8, is_async = $9, requires_auth = $10, edited_at = now() + WHERE workspace_id = $11 AND path = $12", + ct.route_path, + &route_path_key, + ct.script_path, + ct.path, + ct.is_flow, + ct.http_method as HttpMethod, + &authed.username, + &authed.email, + ct.is_async, + ct.requires_auth, + w_id, + path, + ) + .execute(&mut *tx).await?; + } else { + sqlx::query!( + "UPDATE http_trigger SET script_path = $1, path = $2, is_flow = $3, http_method = $4, edited_by = $5, email = $6, is_async = $7, requires_auth = $8, edited_at = now() + WHERE workspace_id = $9 AND path = $10", + ct.script_path, + ct.path, + ct.is_flow, + ct.http_method as HttpMethod, + &authed.username, + &authed.email, + ct.is_async, + ct.requires_auth, + w_id, + path, + ) + .execute(&mut *tx).await?; + } + + audit_log( + &mut *tx, + &authed, + "http_triggers.update", + ActionKind::Create, + &w_id, + Some(path), + None, + ) + .await?; + + tx.commit().await?; + + Ok(path.to_string()) +} + +async fn delete_trigger( + authed: ApiAuthed, + Extension(user_db): Extension, + Path((w_id, path)): Path<(String, StripPath)>, +) -> error::Result { + require_admin(authed.is_admin, &authed.username)?; + let path = path.to_path(); + let mut tx = user_db.begin(&authed).await?; + sqlx::query!( + "DELETE FROM http_trigger WHERE workspace_id = $1 AND path = $2", + w_id, + path, + ) + .execute(&mut *tx) + .await?; + + audit_log( + &mut *tx, + &authed, + "http_triggers.delete", + ActionKind::Delete, + &w_id, + Some(path), + None, + ) + .await?; + + tx.commit().await?; + + Ok(format!("HTTP trigger {path} deleted")) +} + +async fn exists_trigger( + Extension(db): Extension, + Path((w_id, path)): Path<(String, StripPath)>, +) -> JsonResult { + let path = path.to_path(); + let exists = sqlx::query_scalar!( + "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE path = $1 AND workspace_id = $2)", + path, + w_id, + ) + .fetch_one(&db) + .await? + .unwrap_or(false); + Ok(Json(exists)) +} + +#[derive(Deserialize)] +struct RouteExists { + route_path: String, + http_method: HttpMethod, +} + +async fn exists_route( + Extension(db): Extension, + Path(w_id): Path, + Json(RouteExists { route_path, http_method }): Json, +) -> JsonResult { + let route_path_key = ROUTE_PATH_KEY_RE.replace_all(route_path.as_str(), ":key"); + let exists = if *CLOUD_HOSTED { + sqlx::query_scalar!( + "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE route_path_key = $1 AND workspace_id = $2 AND http_method = $3)", + &route_path_key, + w_id, + http_method as HttpMethod + ) + .fetch_one(&db) + .await? + .unwrap_or(false) + } else { + sqlx::query_scalar!( + "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE route_path_key = $1 AND http_method = $2)", + &route_path_key, + http_method as HttpMethod + ) + .fetch_one(&db) + .await? + .unwrap_or(false) + }; + Ok(Json(exists)) +} + +struct TriggerRoute { + path: String, + script_path: String, + is_flow: bool, + route_path: String, + workspace_id: String, + is_async: bool, + requires_auth: bool, + edited_by: String, + email: String, + http_method: HttpMethod, +} + +async fn get_http_route_trigger( + route_path: &str, + opt_authed: Option, + db: &DB, + user_db: UserDB, +) -> error::Result<(TriggerRoute, String, HashMap, ApiAuthed)> { + let (mut triggers, route_path) = if *CLOUD_HOSTED { + let mut splitted = route_path.split("/"); + let w_id = splitted.next().ok_or_else(|| { + error::Error::BadRequest("Missing workspace id in route path".to_string()) + })?; + let route_path = StripPath(splitted.collect::>().join("/")); + let triggers = sqlx::query_as!( + TriggerRoute, + r#"SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, http_method as "http_method: _" FROM http_trigger WHERE workspace_id = $1"#, + w_id + ) + .fetch_all(db) + .await?; + (triggers, route_path) + } else { + let triggers = sqlx::query_as!( + TriggerRoute, + r#"SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, http_method as "http_method: _" FROM http_trigger"#, + ) + .fetch_all(db) + .await?; + (triggers, StripPath(route_path.to_string())) + }; + + let mut router = matchit::Router::new(); + + for (idx, trigger) in triggers.iter().enumerate() { + let route_path = trigger.route_path.clone(); + router.insert(route_path.as_str(), idx).unwrap_or_else(|e| { + tracing::warn!( + "Failed to consider http trigger route {}: {:?}", + route_path, + e, + ); + }); + } + + let trigger_idx = router.at(route_path.0.as_str()).ok(); + + let matchit::Match { value: trigger_idx, params } = + not_found_if_none(trigger_idx, "Trigger", route_path.0.as_str())?; + + let trigger = triggers.remove(trigger_idx.to_owned()); + + let params: HashMap = params + .iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(); + + let username_override = if trigger.requires_auth { + if let Some(authed) = opt_authed { + // check that the user has access to the trigger + let mut tx = user_db.begin(&authed).await?; + let exists = sqlx::query_scalar!( + "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1 AND path = $2)", + trigger.workspace_id, + trigger.path + ) + .fetch_one(&mut *tx) + .await? + .unwrap_or(false); + tx.commit().await?; + if exists { + Some(authed.display_username().to_owned()) + } else { + return Err(error::Error::NotAuthorized("Unauthorized".to_string())); + } + } else { + return Err(error::Error::NotAuthorized( + "Requires authentication".to_string(), + )); + } + } else { + None + }; + + let authed = fetch_api_authed( + trigger.edited_by.clone(), + trigger.email.clone(), + &trigger.workspace_id, + &db, + username_override.unwrap_or("anonymous".to_string()), + ) + .await?; + + Ok((trigger, route_path.0, params, authed)) +} + +async fn route_job( + Extension(db): Extension, + Extension(user_db): Extension, + Extension(rsmq): Extension>, + Path(route_path): Path, + OptAuthed(opt_authed): OptAuthed, + Query(query): Query>, + method: http::Method, + headers: HeaderMap, + mut args: PushArgsOwned, +) -> impl IntoResponse { + let route_path = route_path.to_path(); + let (trigger, called_path, params, authed) = + match get_http_route_trigger(route_path, opt_authed, &db, user_db.clone()).await { + Ok(trigger) => trigger, + Err(e) => return e.into_response(), + }; + let headers = headers + .iter() + .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string())) + .collect::>(); + let extra = args.extra.get_or_insert_with(HashMap::new); + extra.insert( + "wm_trigger".to_string(), + to_raw_value(&serde_json::json!({ + "kind": "http", + "http": { + "route": trigger.route_path, + "path": called_path, + "method": method.to_string().to_lowercase(), + "params": params, + "query": query, + "headers": headers + }, + })), + ); + let http_method = http::Method::from(trigger.http_method); + + if http_method != method { + return error::Error::BadRequest("Invalid HTTP method".to_string()).into_response(); + } + + let label_prefix = Some(format!( + "http-{}-{}-", + http_method.as_str().to_lowercase(), + trigger.route_path + )); + + let run_query = RunJobQuery::default(); + + if trigger.is_flow { + if trigger.is_async { + run_flow_by_path_inner( + authed, + db, + user_db, + rsmq, + trigger.workspace_id.clone(), + StripPath(trigger.script_path.to_owned()), + run_query, + args, + label_prefix, + ) + .await + .into_response() + } else { + run_wait_result_flow_by_path_internal( + db, + run_query, + StripPath(trigger.script_path.to_owned()), + authed, + rsmq, + user_db, + args, + trigger.workspace_id.clone(), + label_prefix, + ) + .await + .into_response() + } + } else { + if trigger.is_async { + run_script_by_path_inner( + authed, + db, + user_db, + rsmq, + trigger.workspace_id.clone(), + StripPath(trigger.script_path.to_owned()), + run_query, + args, + label_prefix, + ) + .await + .into_response() + } else { + run_wait_result_script_by_path_internal( + db, + run_query, + StripPath(trigger.script_path.to_owned()), + authed, + rsmq, + user_db, + trigger.workspace_id.clone(), + args, + label_prefix, + ) + .await + .into_response() + } + } +} diff --git a/backend/windmill-api/src/job_metrics.rs b/backend/windmill-api/src/job_metrics.rs index 4a57ed28d4..2af59383a8 100644 --- a/backend/windmill-api/src/job_metrics.rs +++ b/backend/windmill-api/src/job_metrics.rs @@ -1,12 +1,18 @@ use crate::db::DB; -use axum::{extract::Path, routing::post, Extension, Json, Router}; +use axum::{ + extract::Path, + routing::{get, post}, + Extension, Json, Router, +}; use serde::{Deserialize, Serialize}; use tower_http::cors::{Any, CorsLayer}; use uuid::Uuid; use windmill_common::{ - error, - job_metrics::{JobStatsRecord, MetricKind}, + error::{self, Error}, + job_metrics::{ + record_metric, register_metric_for_job, JobStatsRecord, MetricKind, MetricNumericValue, + }, }; pub fn workspaced_service() -> Router { @@ -15,7 +21,16 @@ pub fn workspaced_service() -> Router { .allow_headers([http::header::CONTENT_TYPE, http::header::AUTHORIZATION]) .allow_origin(Any); - Router::new().route("/get/:id", post(get_job_metrics).layer(cors.clone())) + Router::new() + .route("/get/:id", post(get_job_metrics).layer(cors.clone())) + .route( + "/set_progress/:id", + post(set_job_progress).layer(cors.clone()), + ) + .route( + "/get_progress/:id", + get(get_job_progress).layer(cors.clone()), + ) } #[derive(Deserialize)] @@ -137,6 +152,93 @@ async fn get_job_metrics( let response = JobStatsResponse { metrics_metadata, scalar_metrics, timeseries_metrics }; Ok(Json(response)) } +#[derive(Deserialize)] +struct JobProgressSetRequest { + percent: i32, + /// Optional parent flow id + /// Used to modify flow status + /// Specifically `progress` field in corresponding FlowStatusModule in `InProgress` state + flow_job_id: Option, +} + +async fn set_job_progress( + Extension(db): Extension, + Path((w_id, job_id)): Path<(String, Uuid)>, + Json(JobProgressSetRequest { percent, flow_job_id }): Json, +) -> error::JsonResult<()> { + // If flow_job_id exists, than we should modify flow_status of corresponding module + // Individual jobs and flows are handled differently + if let Some(flow_job_id) = flow_job_id { + // TODO: Return error if trying to set completed job? + sqlx::query!( + "UPDATE queue + SET flow_status = JSONB_SET(flow_status, ARRAY['modules', flow_status->>'step', 'progress'], $1) + WHERE id = $2", + serde_json::json!(percent.clamp(0, 99)), + flow_job_id + ) + .execute(&db) + .await?; + } + + let record_progress = || { + record_metric( + &db, + w_id.clone(), + job_id, + "progress_perc".to_owned(), + MetricNumericValue::Integer(percent), + ) + }; + + // Try to record + if let Err(err) = record_progress().await { + if matches!(err, Error::MetricNotFound(..)) { + // Register + // TODO: Reset progress after job is finished (in case it reruns same job)? + _ = register_metric_for_job( + &db, + w_id.clone(), + job_id, + "progress_perc".to_string(), + MetricKind::ScalarInt, + Some("Job Execution Progress (%)".to_owned()), + ) + .await?; + // Retry recording progress + record_progress().await.map_err(|err| { + // If for some reason it still returns same error, this error will be converted to BadRequest and returned + if let Error::MetricNotFound(body) = err { + Error::BadRequest(body) + } else { + err + } + })?; + } else { + return Err(err); + } + }; + return Ok(Json(())); +} + +async fn get_job_progress( + Extension(db): Extension, + Path((w_id, job_id)): Path<(String, Uuid)>, +) -> error::JsonResult> { + let progress: Option> = sqlx::query_scalar!( + "SELECT (scalar_int)::int FROM job_stats WHERE job_id = $1 AND workspace_id = $2 AND metric_id = 'progress_perc'", + job_id, w_id) + .fetch_optional(&db) + .await?; + + let respond_value = if let Some(Some(progress)) = progress { + Some(progress.clamp(0, 99)) + } else { + None + }; + + Ok(Json(respond_value)) +} fn timeseries_sample( from: Option>, diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 43db962e6a..7244b2be17 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -18,12 +18,13 @@ use tokio::io::AsyncReadExt; #[cfg(feature = "prometheus")] use tokio::time::Instant; 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, CompletedJobWithFormattedResult, FormattedResult, ENTRYPOINT_OVERRIDE, }; -use windmill_common::worker::TMP_DIR; +use windmill_common::worker::{CLOUD_HOSTED, TMP_DIR}; #[cfg(all(feature = "enterprise", feature = "parquet"))] use windmill_common::scripts::PREVIEW_IS_CODEBASE_HASH; @@ -33,6 +34,8 @@ use crate::add_webhook_allowed_origin; use crate::concurrency_groups::join_concurrency_key; use crate::db::ApiAuthed; +use crate::users::get_scope_tags; +use crate::utils::content_plain; use crate::{ db::DB, users::{check_scopes, require_owner_of_path, OptAuthed}, @@ -57,7 +60,7 @@ use tower_http::cors::{Any, CorsLayer}; use urlencoding::encode; use windmill_audit::audit_ee::{audit_log, AuditAuthor}; use windmill_audit::ActionKind; -use windmill_common::worker::{to_raw_value, CUSTOM_TAGS_PER_WORKSPACE, SERVER_CONFIG}; +use windmill_common::worker::{to_raw_value, CUSTOM_TAGS_PER_WORKSPACE}; use windmill_common::{ db::UserDB, error::{self, to_anyhow, Error}, @@ -67,7 +70,10 @@ use windmill_common::{ oauth2::HmacSha256, scripts::{ScriptHash, ScriptLang}, users::username_to_permissioned_as, - utils::{not_found_if_none, now_from_db, paginate, require_admin, Pagination, StripPath}, + utils::{ + not_found_if_none, now_from_db, paginate, paginate_without_limits, require_admin, + Pagination, StripPath, + }, }; #[cfg(all(feature = "enterprise", feature = "parquet"))] @@ -78,7 +84,7 @@ use windmill_common::{METRICS_DEBUG_ENABLED, METRICS_ENABLED}; use windmill_common::{get_latest_deployed_hash_for_path, BASE_URL}; use windmill_queue::{ cancel_job, get_queued_job, get_result_by_id_from_running_flow, job_is_complete, push, - DecodeQueries, PushArgs, PushArgsOwned, PushIsolationLevel, QueueTransaction, + DecodeQueries, PushArgs, PushArgsOwned, PushIsolationLevel, }; #[cfg(feature = "prometheus")] @@ -245,7 +251,7 @@ pub fn workspaced_service() -> Router { .route("/run/flow_dependencies", post(run_flow_dependencies_job)) } -pub fn global_service() -> Router { +pub fn workspace_unauthed_service() -> Router { Router::new() .route( "/resume/:job_id/:resume_id/:secret", @@ -289,7 +295,9 @@ pub fn global_service() -> Router { } pub fn global_root_service() -> Router { - Router::new().route("/db_clock", get(get_db_clock)) + Router::new() + .route("/db_clock", get(get_db_clock)) + .route("/completed/count_by_tag", get(count_by_tag)) } #[derive(Deserialize)] @@ -539,8 +547,8 @@ pub async fn get_path_for_hash<'c>( Ok(path) } -pub async fn get_path_tag_limits_cache_for_hash<'c, R: rsmq_async::RsmqConnection + Send>( - tx: &mut QueueTransaction<'c, R>, +pub async fn get_path_tag_limits_cache_for_hash( + tx: &DB, w_id: &str, hash: i64, ) -> error::Result<( @@ -555,9 +563,10 @@ pub async fn get_path_tag_limits_cache_for_hash<'c, R: rsmq_async::RsmqConnectio Option, Option, Option, + Option, )> { let script = sqlx::query!( - "select path, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, cache_ttl, language as \"language: ScriptLang\", dedicated_worker, priority, delete_after_use, timeout from script where hash = $1 AND workspace_id = $2", + "select path, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, cache_ttl, language as \"language: ScriptLang\", dedicated_worker, priority, delete_after_use, timeout, has_preprocessor from script where hash = $1 AND workspace_id = $2", hash, w_id ) @@ -582,6 +591,7 @@ pub async fn get_path_tag_limits_cache_for_hash<'c, R: rsmq_async::RsmqConnectio script.priority, script.delete_after_use, script.timeout, + script.has_preprocessor, )) } @@ -791,6 +801,11 @@ async fn get_logs_from_store( let logs = logs.to_string(); let stream = async_stream::stream! { + yield Ok(bytes::Bytes::from( + r#"to remove ansi colors, use: | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' + "# + .to_string(), + )); for file_p in file_index.clone() { let file_p_2 = file_p.clone(); let file = os.get(&object_store::path::Path::from(file_p)).await; @@ -832,6 +847,10 @@ async fn get_logs_from_disk( let logs = logs.to_string(); let stream = async_stream::stream! { + yield Ok(bytes::Bytes::from( + r#"to remove ansi colors, use: | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' + "#.to_string(), + )); for file_p in file_index.clone() { let mut file = tokio::fs::File::open(format!("{TMP_DIR}/{file_p}")).await.map_err(to_anyhow)?; let mut buffer = Vec::new(); @@ -847,14 +866,6 @@ async fn get_logs_from_disk( return None; } -fn content_plain(body: Body) -> Response { - use axum::http::header; - Response::builder() - .header(header::CONTENT_TYPE, "text/plain") - .body(body) - .unwrap() -} - async fn get_job_logs( OptAuthed(opt_authed): OptAuthed, Extension(db): Extension, @@ -899,6 +910,10 @@ async fn get_job_logs( { return r.map(content_plain); } + let logs = format!( + "to remove ansi colors, use: | sed 's/\\x1B\\[[0-9;]\\{{1,\\}}[A-Za-z]//g'\n{}", + logs + ); Ok(content_plain(Body::from(logs))) } else { let text = sqlx::query!( @@ -929,6 +944,11 @@ async fn get_job_logs( if let Some(r) = get_logs_from_disk(text.log_offset, &logs, &text.log_file_index).await { return r.map(content_plain); } + + let logs = format!( + "to remove ansi colors, use: | sed 's/\\x1B\\[[0-9;]\\{{1,\\}}[A-Za-z]//g'\n{}", + logs + ); Ok(content_plain(Body::from(logs))) } } @@ -1036,17 +1056,18 @@ pub struct ListableCompletedJob { #[derive(Deserialize, Clone, Default)] pub struct RunJobQuery { - scheduled_for: Option>, - scheduled_in_secs: Option, - parent_job: Option, - root_job: Option, - invisible_to_owner: Option, - queue_limit: Option, - payload: Option, - job_id: Option, - tag: Option, - timeout: Option, - cache_ttl: Option, + pub scheduled_for: Option>, + pub scheduled_in_secs: Option, + pub parent_job: Option, + pub root_job: Option, + pub invisible_to_owner: Option, + pub queue_limit: Option, + pub payload: Option, + pub job_id: Option, + pub tag: Option, + pub timeout: Option, + pub cache_ttl: Option, + pub skip_preprocessor: Option, } impl RunJobQuery { @@ -1168,16 +1189,10 @@ pub fn filter_list_queue_query( sqlb.and_where_eq("parent_job", "?".bind(pj)); } if let Some(dt) = &lq.started_before { - sqlb.and_where_le( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_le("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.started_after { - sqlb.and_where_ge( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(fs) = &lq.is_flow_step { sqlb.and_where_eq("is_flow_step", fs); @@ -1189,16 +1204,10 @@ pub fn filter_list_queue_query( } if let Some(dt) = &lq.created_before { - sqlb.and_where_le( - "created_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_le("created_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_after { - sqlb.and_where_ge( - "created_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("created_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_or_started_after { @@ -1245,20 +1254,29 @@ pub fn list_queue_jobs_query( w_id: &str, lq: &ListQueueQuery, fields: &[&str], + pagination: Pagination, join_outstanding_wait_times: bool, + tags: Option>, ) -> SqlBuilder { - let sqlb = SqlBuilder::select_from("queue") + let (limit, offset) = paginate_without_limits(pagination); + let mut sqlb = SqlBuilder::select_from("queue") .fields(fields) .order_by("created_at", lq.order_desc.unwrap_or(true)) - .limit(1000) + .limit(limit) + .offset(offset) .clone(); + if let Some(tags) = tags { + sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::>()); + } + filter_list_queue_query(sqlb, lq, w_id, join_outstanding_wait_times) } #[derive(Serialize, FromRow)] struct ListableQueuedJob { pub id: Uuid, + pub running: bool, pub created_by: String, pub created_at: chrono::DateTime, pub started_at: Option>, @@ -1281,6 +1299,7 @@ async fn list_queue_jobs( authed: ApiAuthed, Extension(user_db): Extension, Path(w_id): Path, + Query(pagination): Query, Query(lq): Query, ) -> error::JsonResult> { let sql = list_queue_jobs_query( @@ -1288,6 +1307,7 @@ async fn list_queue_jobs( &lq, &[ "id", + "running", "created_by", "created_at", "started_at", @@ -1307,7 +1327,9 @@ async fn list_queue_jobs( "priority", "workspace_id", ], + pagination, false, + get_scope_tags(&authed), ) .sql()?; let mut tx = user_db.begin(&authed).await?; @@ -1450,6 +1472,8 @@ async fn cancel_jobs( } } + uuids.extend(trivial_jobs); + Ok(Json(uuids)) } @@ -1496,6 +1520,10 @@ async fn list_filtered_uuids( sqlb.and_where_is_null("schedule_path"); + if let Some(tags) = get_scope_tags(&authed) { + sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::>()); + } + sqlb = filter_list_queue_query(sqlb, &lq, w_id.as_str(), false); let sql = sqlb.query()?; @@ -1555,8 +1583,9 @@ async fn list_jobs( Query(lq): Query, Extension(_api_list_jobs_query_duration): Extension>, ) -> error::JsonResult> { - check_scopes(&authed, || format!("listjobs"))?; + check_scopes(&authed, || format!("jobs:listjobs"))?; + let limit = pagination.per_page.unwrap_or(1000); let (per_page, offset) = paginate(pagination); let lqc = lq.clone(); @@ -1573,17 +1602,24 @@ async fn list_jobs( &ListCompletedQuery { order_desc: Some(true), ..lqc }, UnifiedJob::completed_job_fields(), true, + get_scope_tags(&authed), )) } else { None }; - let sql = if lq.success.is_none() && lq.label.is_none() { + let sql = if lq.success.is_none() + && lq.label.is_none() + && lq.created_or_started_before.is_none() + && lq.started_before.is_none() + { let mut sqlq = list_queue_jobs_query( &w_id, &ListQueueQuery { order_desc: Some(true), ..lq.into() }, UnifiedJob::queued_job_fields(), + Pagination { per_page: Some(limit), page: None }, true, + get_scope_tags(&authed), ); if let Some(sqlc) = sqlc { @@ -1598,6 +1634,11 @@ async fn list_jobs( sqlq.limit(per_page).offset(offset).query()? } } 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(), + )); + } sqlc.unwrap().limit(per_page).offset(offset).query()? }; let mut tx = user_db.begin(&authed).await?; @@ -1629,7 +1670,7 @@ pub async fn resume_suspended_flow_as_owner( Path((_w_id, flow_id)): Path<(String, Uuid)>, QueryOrBody(value): QueryOrBody, ) -> error::Result { - check_scopes(&authed, || format!("resumeflow"))?; + check_scopes(&authed, || format!("jobs:resumeflow"))?; let value = value.unwrap_or(serde_json::Value::Null); let mut tx = db.begin().await?; @@ -2774,16 +2815,18 @@ pub async fn run_flow_by_path_inner( let flow_path = flow_path.to_path(); check_scopes(&authed, || format!("run:flow/{flow_path}"))?; - let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into(); - - let (tag, dedicated_worker) = sqlx::query!( - "SELECT tag, dedicated_worker from flow WHERE path = $1 and workspace_id = $2", + let (tag, dedicated_worker, has_preprocessor) = sqlx::query!( + "SELECT tag, dedicated_worker, flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor + FROM flow + LEFT JOIN flow_version + ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] + WHERE flow.path = $1 and flow.workspace_id = $2", flow_path, w_id ) - .fetch_optional(&mut tx) + .fetch_optional(&db) .await? - .map(|x| (x.tag, x.dedicated_worker)) + .map(|x| (x.tag, x.dedicated_worker, x.has_preprocessor)) .ok_or_else(|| { Error::NotFound(format!( "flow not found at path {flow_path} in workspace {w_id}" @@ -2794,12 +2837,17 @@ pub async fn run_flow_by_path_inner( check_tag_available_for_workspace(&w_id, &tag).await?; let scheduled_for = run_query.get_scheduled_for(&db).await?; - let tx = PushIsolationLevel::Transaction(tx); + let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq); let (uuid, tx) = push( &db, tx, &w_id, - JobPayload::Flow { path: flow_path.to_string(), dedicated_worker }, + JobPayload::Flow { + path: flow_path.to_string(), + dedicated_worker, + apply_preprocessor: !run_query.skip_preprocessor.unwrap_or(false) + && has_preprocessor.unwrap_or(false), + }, PushArgs { args: &args.args, extra: args.extra }, &label_prefix .map(|x| x + authed.display_username()) @@ -2861,14 +2909,12 @@ pub async fn restart_flow( ) -> error::Result<(StatusCode, String)> { check_license_key_valid().await?; - let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into(); - let completed_job = sqlx::query_as::<_, CompletedJob>( "SELECT *, result->'wm_labels' as labels from completed_job WHERE id = $1 and workspace_id = $2", ) .bind(job_id) .bind(&w_id) - .fetch_optional(&mut tx) + .fetch_optional(&db) .await? .with_context(|| "Unable to find completed job with the given job UUID")?; @@ -2886,7 +2932,7 @@ pub async fn restart_flow( let scheduled_for = run_query.get_scheduled_for(&db).await?; - let tx = PushIsolationLevel::Transaction(tx); + let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq); let (uuid, tx) = push( &db, @@ -2962,16 +3008,14 @@ pub async fn run_script_by_path_inner( check_scopes(&authed, || format!("run:script/{script_path}"))?; - let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into(); - let (job_payload, tag, _delete_after_use, timeout) = - script_path_to_payload(script_path, &mut tx, &w_id).await?; + script_path_to_payload(script_path, &db, &w_id, run_query.skip_preprocessor).await?; let scheduled_for = run_query.get_scheduled_for(&db).await?; let tag = run_query.tag.clone().or(tag); check_tag_available_for_workspace(&w_id, &tag).await?; - let tx = PushIsolationLevel::Transaction(tx); + let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq); let (uuid, tx) = push( &db, @@ -3004,6 +3048,11 @@ pub async fn run_script_by_path_inner( Ok((StatusCode::CREATED, uuid.to_string())) } +#[derive(Deserialize)] +pub struct WorkflowAsCodeQuery { + pub skip_update: Option, +} + pub async fn run_workflow_as_code( authed: ApiAuthed, Extension(db): Extension, @@ -3011,15 +3060,32 @@ pub async fn run_workflow_as_code( Extension(rsmq): Extension>, Path((w_id, job_id, entrypoint)): Path<(String, Uuid, String)>, Query(run_query): Query, + Query(wkflow_query): Query, Json(task): Json, ) -> error::Result<(StatusCode, String)> { + let mut i = 1; + + if *CLOUD_HOSTED { + tracing::info!("workflow_as_code_tracing id {i} "); + i += 1; + } + #[cfg(feature = "enterprise")] check_license_key_valid().await?; check_tag_available_for_workspace(&w_id, &run_query.tag).await?; - let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into(); + if *CLOUD_HOSTED { + tracing::info!("workflow_as_code_tracing id {i} "); + i += 1; + } let job = get_queued_job(&job_id, &w_id, &db).await?; + + if *CLOUD_HOSTED { + tracing::info!("workflow_as_code_tracing id {i} "); + i += 1; + } + let job = not_found_if_none(job, "Queued Job", &job_id.to_string())?; let (job_payload, tag, _delete_after_use, timeout) = match job.job_kind { JobKind::Preview => ( @@ -3041,10 +3107,18 @@ pub async fn run_workflow_as_code( None, run_query.timeout, ), - JobKind::Script => script_path_to_payload(job.script_path(), &mut tx, &w_id).await?, + JobKind::Script => { + script_path_to_payload(job.script_path(), &db, &w_id, run_query.skip_preprocessor) + .await? + } _ => return Err(anyhow::anyhow!("Not supported").into()), }; + if *CLOUD_HOSTED { + tracing::info!("workflow_as_code_tracing id {i} "); + i += 1; + } + let mut extra = HashMap::new(); extra.insert(ENTRYPOINT_OVERRIDE.to_string(), to_raw_value(&entrypoint)); @@ -3053,7 +3127,17 @@ pub async fn run_workflow_as_code( let tag = run_query.tag.clone().or(tag).or(Some(job.tag)); - let tx = PushIsolationLevel::Transaction(tx); + if *CLOUD_HOSTED { + tracing::info!("workflow_as_code_tracing id {i} "); + i += 1; + } + + let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq); + + if *CLOUD_HOSTED { + tracing::info!("workflow_as_code_tracing id {i} "); + i += 1; + } let (uuid, mut tx) = push( &db, @@ -3080,14 +3164,35 @@ pub async fn run_workflow_as_code( Some(&authed.clone().into()), ) .await?; - sqlx::query!( - "UPDATE queue SET flow_status = jsonb_set(COALESCE(flow_status, '{}'::jsonb), array[$1], jsonb_set(jsonb_set('{}'::jsonb, '{scheduled_for}', to_jsonb(now()::text)), '{name}', to_jsonb($4::text))) WHERE id = $2 AND workspace_id = $3", - uuid.to_string(), - job_id, - w_id, - entrypoint - ).execute(&mut tx).await?; + + if *CLOUD_HOSTED { + tracing::info!("workflow_as_code_tracing id {i} "); + i += 1; + } + + if !wkflow_query.skip_update.unwrap_or(false) { + sqlx::query!( + "UPDATE queue SET flow_status = jsonb_set(COALESCE(flow_status, '{}'::jsonb), array[$1], jsonb_set(jsonb_set('{}'::jsonb, '{scheduled_for}', to_jsonb(now()::text)), '{name}', to_jsonb($4::text))) WHERE id = $2 AND workspace_id = $3", + uuid.to_string(), + job_id, + w_id, + entrypoint + ).execute(&mut tx).await?; + } else { + tracing::info!("Skipping update of flow status for job {job_id} in workspace {w_id}"); + } + + if *CLOUD_HOSTED { + tracing::info!("workflow_as_code_tracing id {i} "); + i += 1; + } + tx.commit().await?; + + if *CLOUD_HOSTED { + tracing::info!("workflow_as_code_tracing id {i} "); + } + Ok((StatusCode::CREATED, uuid.to_string())) } @@ -3137,6 +3242,17 @@ impl Drop for Guard { } } +use std::sync::Arc; +use tokio::sync::RwLock; + +lazy_static::lazy_static! { + pub static ref TIMEOUT_WAIT_RESULT: Arc>> = Arc::new(RwLock::new( + std::env::var("TIMEOUT_WAIT_RESULT") + .ok() + .and_then(|x| x.parse::().ok()) + )); +} + #[derive(Deserialize)] pub struct WindmillCompositeResult { windmill_status_code: Option, @@ -3151,7 +3267,7 @@ async fn run_wait_result( username: &str, ) -> error::Result { let mut result = None; - let timeout = SERVER_CONFIG.read().await.timeout_wait_result.clone(); + let timeout = TIMEOUT_WAIT_RESULT.read().await.clone().unwrap_or(600); let timeout_ms = if timeout <= 0 { 2000 } else { @@ -3440,15 +3556,13 @@ pub async fn run_wait_result_job_by_path_get( let script_path = script_path.to_path(); check_scopes(&authed, || format!("run:script/{script_path}"))?; - let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into(); - let (job_payload, tag, delete_after_use, timeout) = - script_path_to_payload(script_path, &mut tx, &w_id).await?; + script_path_to_payload(script_path, &db, &w_id, run_query.skip_preprocessor).await?; let tag = run_query.tag.clone().or(tag); check_tag_available_for_workspace(&w_id, &tag).await?; - let tx = PushIsolationLevel::Transaction(tx); + let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq); let (uuid, tx) = push( &db, @@ -3519,7 +3633,7 @@ pub async fn run_wait_result_flow_by_path_get( let args = PushArgsOwned { extra: Some(payload_args), args: HashMap::new() }; run_wait_result_flow_by_path_internal( - db, run_query, flow_path, authed, rsmq, user_db, args, w_id, + db, run_query, flow_path, authed, rsmq, user_db, args, w_id, None, ) .await } @@ -3545,11 +3659,12 @@ pub async fn run_wait_result_script_by_path( user_db, w_id, args, + None, ) .await } -async fn run_wait_result_script_by_path_internal( +pub async fn run_wait_result_script_by_path_internal( db: sqlx::Pool, run_query: RunJobQuery, script_path: StripPath, @@ -3558,20 +3673,19 @@ async fn run_wait_result_script_by_path_internal( user_db: UserDB, w_id: String, args: PushArgsOwned, + label_prefix: Option, ) -> error::Result { check_queue_too_long(&db, QUEUE_LIMIT_WAIT_RESULT.or(run_query.queue_limit)).await?; let script_path = script_path.to_path(); check_scopes(&authed, || format!("run:script/{script_path}"))?; - let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into(); - let (job_payload, tag, delete_after_use, timeout) = - script_path_to_payload(script_path, &mut tx, &w_id).await?; + script_path_to_payload(script_path, &db, &w_id, run_query.skip_preprocessor).await?; let tag = run_query.tag.clone().or(tag); check_tag_available_for_workspace(&w_id, &tag).await?; - let tx = PushIsolationLevel::Transaction(tx); + let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq); let (uuid, tx) = push( &db, @@ -3579,7 +3693,9 @@ async fn run_wait_result_script_by_path_internal( &w_id, job_payload, PushArgs { args: &args.args, extra: args.extra }, - authed.display_username(), + &label_prefix + .map(|x| x + authed.display_username()) + .unwrap_or_else(|| authed.display_username().to_string()), &authed.email, username_to_permissioned_as(&authed.username), None, @@ -3621,8 +3737,6 @@ pub async fn run_wait_result_script_by_hash( check_queue_too_long(&db, run_query.queue_limit).await?; - let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into(); - let hash = script_hash.0; let ( path, @@ -3636,7 +3750,8 @@ pub async fn run_wait_result_script_by_hash( priority, delete_after_use, timeout, - ) = get_path_tag_limits_cache_for_hash(&mut tx, &w_id, hash).await?; + has_preprocessor, + ) = get_path_tag_limits_cache_for_hash(&db, &w_id, hash).await?; if let Some(run_query_cache_ttl) = run_query.cache_ttl { cache_ttl = Some(run_query_cache_ttl); } @@ -3645,7 +3760,7 @@ pub async fn run_wait_result_script_by_hash( let tag = run_query.tag.clone().or(tag); check_tag_available_for_workspace(&w_id, &tag).await?; - let tx = PushIsolationLevel::Transaction(tx); + let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq); let (uuid, tx) = push( &db, @@ -3661,6 +3776,8 @@ pub async fn run_wait_result_script_by_hash( language, dedicated_worker, priority, + apply_preprocessor: !run_query.skip_preprocessor.unwrap_or(false) + && has_preprocessor.unwrap_or(false), }, PushArgs { args: &args.args, extra: args.extra }, authed.display_username(), @@ -3704,12 +3821,12 @@ pub async fn run_wait_result_flow_by_path( check_license_key_valid().await?; run_wait_result_flow_by_path_internal( - db, run_query, flow_path, authed, rsmq, user_db, args, w_id, + db, run_query, flow_path, authed, rsmq, user_db, args, w_id, None, ) .await } -async fn run_wait_result_flow_by_path_internal( +pub async fn run_wait_result_flow_by_path_internal( db: sqlx::Pool, run_query: RunJobQuery, flow_path: StripPath, @@ -3718,18 +3835,17 @@ async fn run_wait_result_flow_by_path_internal( user_db: UserDB, args: PushArgsOwned, w_id: String, + label_prefix: Option, ) -> error::Result { check_queue_too_long(&db, run_query.queue_limit).await?; let flow_path = flow_path.to_path(); check_scopes(&authed, || format!("run:flow/{flow_path}"))?; - let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into(); - let scheduled_for = run_query.get_scheduled_for(&db).await?; - let (tag, dedicated_worker, early_return) = sqlx::query!( - "SELECT tag, dedicated_worker, flow_version.value->>'early_return' as early_return + let (tag, dedicated_worker, early_return, has_preprocessor) = sqlx::query!( + "SELECT tag, dedicated_worker, flow_version.value->>'early_return' as early_return, flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor FROM flow LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] @@ -3737,9 +3853,9 @@ async fn run_wait_result_flow_by_path_internal( flow_path, w_id ) - .fetch_optional(&mut tx) + .fetch_optional(&db) .await? - .map(|x| (x.tag, x.dedicated_worker, x.early_return)) + .map(|x| (x.tag, x.dedicated_worker, x.early_return, x.has_preprocessor)) .ok_or_else(|| { Error::NotFound(format!( "flow not found at path {flow_path} in workspace {w_id}" @@ -3749,15 +3865,22 @@ async fn run_wait_result_flow_by_path_internal( let tag = run_query.tag.clone().or(tag); check_tag_available_for_workspace(&w_id, &tag).await?; - let tx = PushIsolationLevel::Transaction(tx); + let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq); let (uuid, tx) = push( &db, tx, &w_id, - JobPayload::Flow { path: flow_path.to_string(), dedicated_worker }, + JobPayload::Flow { + path: flow_path.to_string(), + dedicated_worker, + apply_preprocessor: !run_query.skip_preprocessor.unwrap_or(false) + && has_preprocessor.unwrap_or(false), + }, PushArgs { args: &args.args, extra: args.extra }, - authed.display_username(), + &label_prefix + .map(|x| x + authed.display_username()) + .unwrap_or_else(|| authed.display_username().to_string()), &authed.email, username_to_permissioned_as(&authed.username), scheduled_for, @@ -3793,7 +3916,7 @@ async fn run_preview_script( #[cfg(feature = "enterprise")] check_license_key_valid().await?; - check_scopes(&authed, || format!("runscript"))?; + check_scopes(&authed, || format!("jobs:runscript"))?; if authed.is_operator { return Err(error::Error::NotAuthorized( "Operators cannot run preview jobs for security reasons".to_string(), @@ -3863,7 +3986,7 @@ async fn run_bundle_preview_script( check_license_key_valid().await?; - check_scopes(&authed, || format!("runscript"))?; + check_scopes(&authed, || format!("jobs:runscript"))?; if authed.is_operator { return Err(error::Error::NotAuthorized( "Operators cannot run preview jobs for security reasons".to_string(), @@ -4048,10 +4171,10 @@ async fn run_dependencies_job( JsonRawValue::from_string("true".to_string()).unwrap(), ); if language == ScriptLang::Bun { - let annotation = windmill_common::worker::get_annotation(&raw_code); + let annotation = windmill_common::worker::TypeScriptAnnotations::parse(&raw_code); hm.insert( "npm_mode".to_string(), - JsonRawValue::from_string(annotation.npm_mode.to_string()).unwrap(), + JsonRawValue::from_string(annotation.npm.to_string()).unwrap(), ); } (PushArgs { extra: Some(hm), args: &ehm }, deps) @@ -4194,6 +4317,7 @@ async fn add_batch_jobs( _priority, _delete_after_use, timeout, + _, ) = get_latest_deployed_hash_for_path(&db, &w_id, &path).await?; ( Some(script_hash), @@ -4213,20 +4337,23 @@ async fn add_batch_jobs( } } "flow" => { - let mut tx = PushIsolationLevel::IsolatedRoot(db.clone(), rsmq); - let mut uuids: Vec = Vec::new(); let payload = if let Some(ref fv) = batch_info.flow_value { JobPayload::RawFlow { value: fv.clone(), path: None, restarted_from: None } } else { if let Some(path) = batch_info.path.as_ref() { - JobPayload::Flow { path: path.to_string(), dedicated_worker: None } + JobPayload::Flow { + path: path.to_string(), + dedicated_worker: None, + apply_preprocessor: false, + } } else { Err(anyhow::anyhow!( "Path is required if no value is not provided" ))? } }; + let mut tx = PushIsolationLevel::IsolatedRoot(db.clone(), rsmq); for _ in 0..n { let ehm = HashMap::new(); let (uuid, ntx) = push( @@ -4344,7 +4471,7 @@ async fn run_preview_flow_job( Query(run_query): Query, Json(raw_flow): Json, ) -> error::Result<(StatusCode, String)> { - check_scopes(&authed, || format!("runflow"))?; + check_scopes(&authed, || format!("jobs:runflow"))?; if authed.is_operator { return Err(error::Error::NotAuthorized( "Operators cannot run preview jobs for security reasons".to_string(), @@ -4427,8 +4554,6 @@ pub async fn run_job_by_hash_inner( #[cfg(feature = "enterprise")] check_license_key_valid().await?; - let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into(); - let hash = script_hash.0; let ( path, @@ -4442,7 +4567,8 @@ pub async fn run_job_by_hash_inner( priority, _delete_after_use, // not taken into account in async endpoints timeout, - ) = get_path_tag_limits_cache_for_hash(&mut tx, &w_id, hash).await?; + has_preprocessor, + ) = get_path_tag_limits_cache_for_hash(&db, &w_id, hash).await?; check_scopes(&authed, || format!("run:script/{path}"))?; if let Some(run_query_cache_ttl) = run_query.cache_ttl { cache_ttl = Some(run_query_cache_ttl); @@ -4451,7 +4577,7 @@ pub async fn run_job_by_hash_inner( let tag = run_query.tag.clone().or(tag); check_tag_available_for_workspace(&w_id, &tag).await?; - let tx = PushIsolationLevel::Transaction(tx); + let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq); let (uuid, tx) = push( &db, @@ -4467,6 +4593,8 @@ pub async fn run_job_by_hash_inner( language, dedicated_worker, priority, + apply_preprocessor: !run_query.skip_preprocessor.unwrap_or(false) + && has_preprocessor.unwrap_or(false), }, PushArgs { args: &args.args, extra: args.extra }, &label_prefix @@ -4499,6 +4627,7 @@ pub async fn run_job_by_hash_inner( pub struct JobUpdateQuery { pub running: bool, pub log_offset: i32, + pub get_progress: Option, } #[derive(Serialize)] @@ -4508,6 +4637,7 @@ pub struct JobUpdate { pub new_logs: Option, pub log_offset: Option, pub mem_peak: Option, + pub progress: Option, pub flow_status: Option>, } @@ -4575,7 +4705,7 @@ async fn get_job_update( OptAuthed(opt_authed): OptAuthed, Extension(db): Extension, Path((w_id, job_id)): Path<(String, Uuid)>, - Query(JobUpdateQuery { running, log_offset }): Query, + Query(JobUpdateQuery { running, log_offset, get_progress }): Query, ) -> error::JsonResult { let record = sqlx::query_as::<_, JobUpdateRow>( "SELECT running, substr(concat(coalesce(queue.logs, ''), job_logs.logs), greatest($1 - job_logs.log_offset, 0)) as logs, mem_peak, @@ -4591,6 +4721,19 @@ async fn get_job_update( .fetch_optional(&db) .await?; + let progress: Option = if get_progress == Some(true) { + sqlx::query_scalar!( + "SELECT scalar_int FROM job_stats WHERE workspace_id = $1 AND job_id = $2 AND metric_id = $3", + &w_id, + job_id, + "progress_perc" + ) + .fetch_optional(&db) + .await?.and_then(|inner| inner) + } else { + None + }; + if let Some(record) = record { if opt_authed.is_none() && record.created_by != "anonymous" { return Err(Error::BadRequest( @@ -4608,6 +4751,7 @@ async fn get_job_update( completed: None, new_logs: record.logs, mem_peak: record.mem_peak, + progress, flow_status: record .flow_status .map(|x: sqlx::types::Json>| x.0), @@ -4640,6 +4784,7 @@ async fn get_job_update( log_offset: record.log_offset, new_logs: record.logs, mem_peak: record.mem_peak, + progress, flow_status: record .flow_status .map(|x: sqlx::types::Json>| x.0), @@ -4662,6 +4807,13 @@ pub fn filter_list_completed_query( .on_eq("id", "outstanding_wait_time.job_id"); } + 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 w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) { sqlb.and_where_eq("workspace_id", "?".bind(&w_id)); } @@ -4692,36 +4844,28 @@ pub fn filter_list_completed_query( sqlb.and_where_eq("parent_job", "?".bind(pj)); } if let Some(dt) = &lq.started_before { - sqlb.and_where_le( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_le("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.started_after { - sqlb.and_where_ge( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_or_started_before { - sqlb.and_where_le( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_le("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_or_started_after { - sqlb.and_where_ge( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339())); + } + + if let Some(dt) = &lq.created_before { + sqlb.and_where_le("created_at", "?".bind(&dt.to_rfc3339())); + } + if let Some(dt) = &lq.created_after { + sqlb.and_where_ge("created_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_or_started_after_completed_jobs { - sqlb.and_where_ge( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(sk) = &lq.is_skipped { @@ -4750,13 +4894,6 @@ pub fn filter_list_completed_query( sqlb.and_where("result @> ?".bind(&result.replace("'", "''"))); } - if let Some(label) = &lq.label { - let mut wh = format!("result->'wm_labels' ? "); - wh.push_str(&format!("'{}'", &label.replace("'", "''"))); - sqlb.and_where(&wh); - sqlb.and_where("result ? 'wm_labels'"); - } - if lq.is_not_schedule.unwrap_or(false) { sqlb.and_where("schedule_path IS null"); } @@ -4771,14 +4908,19 @@ pub fn list_completed_jobs_query( lq: &ListCompletedQuery, fields: &[&str], join_outstanding_wait_times: bool, + tags: Option>, ) -> SqlBuilder { - let sqlb = SqlBuilder::select_from("completed_job") + let mut sqlb = SqlBuilder::select_from("completed_job") .fields(fields) .order_by("created_at", lq.order_desc.unwrap_or(true)) .offset(offset) .limit(per_page) .clone(); + if let Some(tags) = tags { + sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::>()); + } + filter_list_completed_query(sqlb, lq, w_id, join_outstanding_wait_times) } #[derive(Deserialize, Clone)] @@ -4823,7 +4965,7 @@ async fn list_completed_jobs( Query(pagination): Query, Query(lq): Query, ) -> error::JsonResult> { - check_scopes(&authed, || format!("listjobs"))?; + check_scopes(&authed, || format!("jobs:listjobs"))?; let (per_page, offset) = paginate(pagination); @@ -4865,6 +5007,7 @@ async fn list_completed_jobs( "'CompletedJob' as type", ], false, + get_scope_tags(&authed), ) .sql()?; let mut tx = user_db.begin(&authed).await?; @@ -5009,6 +5152,44 @@ async fn get_completed_job_result( Ok(Json(result).into_response()) } +#[derive(Deserialize)] +struct CountByTagQuery { + horizon_secs: Option, + workspace_id: Option, +} + +#[derive(Serialize)] +struct TagCount { + tag: String, + count: i64, +} + +async fn count_by_tag( + ApiAuthed { email, .. }: ApiAuthed, + Extension(db): Extension, + Query(query): Query, +) -> JsonResult> { + require_super_admin(&db, &email).await?; + let horizon = query.horizon_secs.unwrap_or(3600); // Default to 1 hour if not specified + + let counts = sqlx::query_as!( + TagCount, + r#" + SELECT tag as "tag!", COUNT(*) as "count!" + FROM completed_job + WHERE started_at > NOW() - make_interval(secs => $1) AND ($2::text IS NULL OR workspace_id = $2) + GROUP BY tag + ORDER BY "count!" DESC + "#, + horizon as f64, + query.workspace_id + ) + .fetch_all(&db) + .await?; + + Ok(Json(counts)) +} + #[derive(Serialize)] struct CompletedJobResult { started: Option, @@ -5089,7 +5270,7 @@ async fn delete_completed_job<'a>( Extension(user_db): Extension, Path((w_id, id)): Path<(String, Uuid)>, ) -> error::Result { - check_scopes(&authed, || format!("deletejob"))?; + check_scopes(&authed, || format!("jobs:deletejob"))?; let mut tx = user_db.begin(&authed).await?; diff --git a/backend/windmill-api/src/lib.rs b/backend/windmill-api/src/lib.rs index ed842aeb42..3ea78ffd6d 100644 --- a/backend/windmill-api/src/lib.rs +++ b/backend/windmill-api/src/lib.rs @@ -39,9 +39,8 @@ use tower_http::{ trace::TraceLayer, }; use windmill_common::db::UserDB; -use windmill_common::utils::rd_string; -use windmill_common::worker::ALL_TAGS; -use windmill_common::BASE_URL; +use windmill_common::worker::{ALL_TAGS, CLOUD_HOSTED}; +use windmill_common::{BASE_URL, INSTANCE_NAME}; use crate::scim_ee::has_scim_token; use windmill_common::error::AppError; @@ -60,6 +59,7 @@ mod flows; mod folders; mod granular_acls; mod groups; +mod http_triggers; mod indexer_ee; mod inputs; mod integration; @@ -76,17 +76,22 @@ mod saml_ee; mod schedule; mod scim_ee; mod scripts; +mod service_logs; mod settings; pub mod smtp_server_ee; mod static_assets; mod stripe_ee; mod tracing_init; +mod triggers; mod users; +mod users_ee; mod utils; mod variables; mod webhook_util; +mod websocket_triggers; mod workers; mod workspaces; +mod workspaces_ee; pub const GIT_VERSION: &str = git_version!(args = ["--tag", "--always"], fallback = "unknown-version"); @@ -223,7 +228,7 @@ pub async fn run_server( db: db.clone(), user_db: user_db, auth_cache: auth_cache.clone(), - rsmq: rsmq, + rsmq: rsmq.clone(), base_internal_url: base_internal_url.clone(), }); if let Err(err) = smtp_server.start_listener_thread(addr).await { @@ -243,6 +248,11 @@ pub async fn run_server( } }; + if !*CLOUD_HOSTED { + let ws_killpill_rx = rx.resubscribe(); + websocket_triggers::start_websockets(db.clone(), rsmq, ws_killpill_rx).await; + } + // build our application with a route let app = Router::new() .nest( @@ -282,7 +292,12 @@ pub async fn run_server( ) .nest("/variables", variables::workspaced_service()) .nest("/workspaces", workspaces::workspaced_service()) - .nest("/oidc", oidc_ee::workspaced_service()), + .nest("/oidc", oidc_ee::workspaced_service()) + .nest("/http_triggers", http_triggers::workspaced_service()) + .nest( + "/websocket_triggers", + websocket_triggers::workspaced_service(), + ), ) .nest("/workspaces", workspaces::global_service()) .nest( @@ -291,6 +306,7 @@ pub async fn run_server( ) .nest("/settings", settings::global_service()) .nest("/workers", workers::global_service()) + .nest("/service_logs", service_logs::global_service()) .nest("/configs", configs::global_service()) .nest("/scripts", scripts::global_service()) .nest("/integrations", integration::global_service()) @@ -326,7 +342,7 @@ pub async fn run_server( ) .nest( "/w/:workspace_id/jobs_u", - jobs::global_service().layer(cors.clone()), + jobs::workspace_unauthed_service().layer(cors.clone()), ) .nest( "/w/:workspace_id/resources_u", @@ -334,7 +350,7 @@ pub async fn run_server( ) .nest( "/w/:workspace_id/capture_u", - capture::global_service().layer(cors), + capture::global_service().layer(cors.clone()), ) .nest( "/auth", @@ -344,6 +360,10 @@ pub async fn run_server( "/oauth", oauth2_ee::global_service().layer(Extension(Arc::clone(&sp_extension))), ) + .nest( + "/r", + http_triggers::routes_global_service().layer(from_extractor::()), + ) .route("/version", get(git_v)) .route("/uptodate", get(is_up_to_date)) .route("/ee_license", get(ee_license)) @@ -365,8 +385,6 @@ pub async fn run_server( ) }; - let instance_name = rd_string(5); - let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); let port = listener.local_addr().map(|x| x.port()).unwrap_or(8000); let ip = listener @@ -377,7 +395,7 @@ pub async fn run_server( let server = axum::serve(listener, app.into_make_service()); tracing::info!( - instance = %instance_name, + instance = %*INSTANCE_NAME, "server started on port={} and addr={}", port, ip @@ -389,7 +407,7 @@ pub async fn run_server( let server = server.with_graceful_shutdown(async move { rx.recv().await.ok(); - println!("Graceful shutdown of server"); + tracing::info!("Graceful shutdown of server"); }); server.await?; @@ -440,9 +458,13 @@ async fn ee_license() -> &'static str { #[cfg(feature = "enterprise")] async fn ee_license() -> String { - use windmill_common::ee::LICENSE_KEY_ID; + use windmill_common::ee::{LICENSE_KEY_ID, LICENSE_KEY_VALID}; - LICENSE_KEY_ID.read().await.clone() + if *LICENSE_KEY_VALID.read().await { + LICENSE_KEY_ID.read().await.clone() + } else { + "".to_string() + } } async fn openapi() -> &'static str { diff --git a/backend/windmill-api/src/openai.rs b/backend/windmill-api/src/openai.rs index d11bfcd6ed..0794dadaa5 100644 --- a/backend/windmill-api/src/openai.rs +++ b/backend/windmill-api/src/openai.rs @@ -1,9 +1,6 @@ use std::collections::HashMap; -use crate::{ - db::{ApiAuthed, DB}, - HTTP_CLIENT, -}; +use crate::db::{ApiAuthed, DB}; use axum::{ body::Bytes, @@ -13,6 +10,7 @@ use axum::{ Router, }; use quick_cache::sync::Cache; +use reqwest::Client; use serde_json::value::RawValue; use windmill_audit::audit_ee::audit_log; use windmill_audit::ActionKind; @@ -24,6 +22,13 @@ use windmill_common::{ use crate::variables::decrypt; use serde::Deserialize; +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(); +} + pub fn workspaced_service() -> Router { let router = Router::new().route("/proxy/*openai_path", post(proxy)); diff --git a/backend/windmill-api/src/raw_apps.rs b/backend/windmill-api/src/raw_apps.rs index 20da51f3c7..59f2471c4d 100644 --- a/backend/windmill-api/src/raw_apps.rs +++ b/backend/windmill-api/src/raw_apps.rs @@ -158,7 +158,7 @@ async fn create_app( } let exists = sqlx::query_scalar!( - "SELECT EXISTS(SELECT 1 FROM app WHERE path = $1 AND workspace_id = $2)", + "SELECT EXISTS(SELECT 1 FROM raw_app WHERE path = $1 AND workspace_id = $2)", app.path, w_id ) diff --git a/backend/windmill-api/src/resources.rs b/backend/windmill-api/src/resources.rs index fbc5f53d00..bb881d5369 100644 --- a/backend/windmill-api/src/resources.rs +++ b/backend/windmill-api/src/resources.rs @@ -6,6 +6,8 @@ * LICENSE-AGPL for a copy of the license. */ +use std::collections::HashMap; + use crate::{ db::{ApiAuthed, DB}, users::{maybe_refresh_folders, require_owner_of_path, Tokened}, @@ -56,6 +58,10 @@ pub fn workspaced_service() -> Router { .route("/type/exists/:name", get(exists_resource_type)) .route("/type/update/:name", post(update_resource_type)) .route("/type/delete/:name", delete(delete_resource_type)) + .route( + "/file_resource_type_to_file_ext_map", + get(file_resource_ext_to_resource_type), + ) .route("/type/create", post(create_resource_type)) } @@ -71,6 +77,7 @@ pub struct ResourceType { pub description: Option, pub created_by: Option, pub edited_at: Option>, + pub format_extension: Option, } #[derive(Deserialize)] @@ -78,6 +85,7 @@ pub struct CreateResourceType { pub name: String, pub schema: Option, pub description: Option, + pub format_extension: Option, } #[derive(Deserialize)] @@ -913,6 +921,35 @@ async fn update_resource_value( Ok(format!("value of resource {} updated", path)) } +async fn file_resource_ext_to_resource_type( + Extension(db): Extension, + Path(w_id): Path, +) -> JsonResult> { + #[derive(Serialize, sqlx::FromRow)] + struct LocalFileResourceExtension { + name: String, + format_extension: Option, + } + + let r = sqlx::query_as!(LocalFileResourceExtension, " + SELECT name, format_extension FROM resource_type WHERE format_extension IS NOT NULL AND (workspace_id = $1 OR workspace_id = 'admins')", w_id) + .fetch_all(&db) + .await?; + + let hashmap: HashMap = r + .into_iter() + .filter_map(|entry| { + if let Some(format_extension) = entry.format_extension { + Some((entry.name, format_extension)) + } else { + None + } + }) + .collect(); + + Ok(Json(hashmap)) +} + async fn list_resource_types( Extension(db): Extension, Path(w_id): Path, @@ -996,13 +1033,14 @@ async fn create_resource_type( sqlx::query!( "INSERT INTO resource_type - (workspace_id, name, schema, description, created_by, edited_at) - VALUES ($1, $2, $3, $4, $5, now())", + (workspace_id, name, schema, description, created_by, format_extension, edited_at) + VALUES ($1, $2, $3, $4, $5, $6, now())", w_id, resource_type.name, resource_type.schema, resource_type.description, - authed.username + authed.username, + resource_type.format_extension, ) .execute(&mut *tx) .await?; diff --git a/backend/windmill-api/src/schedule.rs b/backend/windmill-api/src/schedule.rs index d52d441608..7a18976b03 100644 --- a/backend/windmill-api/src/schedule.rs +++ b/backend/windmill-api/src/schedule.rs @@ -69,6 +69,8 @@ pub struct NewSchedule { pub on_recovery: Option, pub on_recovery_times: Option, pub on_recovery_extra_args: Option, + pub on_success: Option, + pub on_success_extra_args: Option, pub ws_error_handler_muted: Option, pub retry: Option, pub tag: Option, @@ -92,6 +94,7 @@ pub struct ErrorOrRecoveryHandler { pub enum HandlerType { Error, Recovery, + Success, } async fn check_path_conflict<'c>( @@ -133,6 +136,13 @@ async fn create_schedule( )); } + #[cfg(not(feature = "enterprise"))] + if ns.on_success.is_some() { + return Err(Error::BadRequest( + "on_success is only available in enterprise version".to_string(), + )); + } + #[cfg(not(feature = "enterprise"))] if ns.on_failure_times.is_some() && ns.on_failure_times.unwrap() > 1 { return Err(Error::BadRequest( @@ -158,9 +168,10 @@ async fn create_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 \ ) VALUES ( \ - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23 \ + $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 \ ) RETURNING *") .bind(&w_id) .bind(&ns.path) @@ -179,6 +190,8 @@ async fn create_schedule( .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) @@ -248,9 +261,10 @@ async fn edit_schedule( 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, ws_error_handler_muted = $11, retry = $12, summary = $13, \ - no_flow_overlap = $14, tag = $15, paused_until = $16 - WHERE path = $17 AND workspace_id = $18 RETURNING *") + 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 + WHERE path = $19 AND workspace_id = $20 RETURNING *") .bind(&es.schedule) .bind(&es.timezone) .bind(&es.args) @@ -261,6 +275,8 @@ async fn edit_schedule( .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) @@ -376,6 +392,8 @@ pub struct ScheduleWJobs { pub on_recovery: Option, pub on_recovery_times: Option, pub on_recovery_extra_args: Option, + pub on_success: Option, + pub on_success_extra_args: Option, pub ws_error_handler_muted: bool, pub retry: Option, pub jobs: Option>, @@ -680,6 +698,18 @@ async fn set_default_error_handler( (key, None) } } + HandlerType::Success => { + let key = format!("default_success_handler_{}", w_id); + if let Some(payload_path) = payload.path.as_ref() { + let value = serde_json::json!({ + "successHandlerPath": payload_path, + "successHandlerExtraArgs": payload.extra_args, + }); + (key, Some(value)) + } else { + (key, None) + } + } }; if let Some(value_content) = value { @@ -733,6 +763,25 @@ async fn set_default_error_handler( .await?; } } + HandlerType::Success => { + if payload.path.is_some() { + updated_schedules = sqlx::query_scalar!( + "UPDATE schedule SET on_success = $1, on_success_extra_args = $2 WHERE workspace_id = $3 RETURNING path", + payload.path, + payload.extra_args, + w_id, + ) + .fetch_all(&db) + .await?; + } else { + updated_schedules = sqlx::query_scalar!( + "UPDATE schedule SET on_success = NULL, on_success_extra_args = NULL WHERE workspace_id = $1 RETURNING path", + w_id, + ) + .fetch_all(&db) + .await?; + } + } } for updated_schedule_path in updated_schedules { handle_deployment_metadata( @@ -790,6 +839,8 @@ pub struct EditSchedule { pub on_recovery: Option, pub on_recovery_times: Option, pub on_recovery_extra_args: Option, + pub on_success: Option, + pub on_success_extra_args: Option, pub ws_error_handler_muted: Option, pub retry: Option, pub no_flow_overlap: Option, diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index 41214dfcbb..56b991713f 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -9,7 +9,11 @@ use crate::{ db::{ApiAuthed, DB}, schedule::clear_schedule, + triggers::{ + get_triggers_count_internal, list_tokens_internal, TriggersCount, TruncatedTokenWithEmail, + }, users::{maybe_refresh_folders, require_owner_of_path, AuthCache}, + utils::WithStarredInfoQuery, webhook_util::{WebhookMessage, WebhookShared}, HTTP_CLIENT, }; @@ -46,13 +50,13 @@ use windmill_common::{ schedule::Schedule, scripts::{ to_i64, HubScript, ListScriptQuery, ListableScript, NewScript, Schema, Script, ScriptHash, - ScriptHistory, ScriptHistoryUpdate, ScriptKind, ScriptLang, + ScriptHistory, ScriptHistoryUpdate, ScriptKind, ScriptLang, ScriptWithStarred, }, users::username_to_permissioned_as, utils::{ not_found_if_none, paginate, query_elems_from_hub, require_admin, Pagination, StripPath, }, - worker::{get_annotation, to_raw_value}, + worker::to_raw_value, HUB_BASE_URL, }; use windmill_git_sync::{handle_deployment_metadata, DeployedObject}; @@ -102,6 +106,8 @@ pub struct ScriptWDraft { pub visible_to_runner_only: Option, #[serde(skip_serializing_if = "Option::is_none")] pub no_main_func: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub has_preprocessor: Option, } pub fn global_service() -> Router { @@ -129,6 +135,8 @@ pub fn workspaced_service() -> Router { .route("/archive/p/*path", post(archive_script_by_path)) .route("/get/draft/*path", get(get_script_by_path_w_draft)) .route("/get/p/*path", get(get_script_by_path)) + .route("/get_triggers_count/*path", get(get_triggers_count)) + .route("/list_tokens/*path", get(list_tokens)) .route("/raw/p/*path", get(raw_script_by_path)) .route("/raw_unpinned/p/*path", get(raw_script_by_path_unpinned)) .route("/exists/p/*path", get(exists_script_by_path)) @@ -144,6 +152,7 @@ pub fn workspaced_service() -> Router { post(toggle_workspace_error_handler), ) .route("/history/p/*path", get(get_script_history)) + .route("/get_latest_version/*path", get(get_latest_version)) .route( "/history_update/h/:hash/p/*path", post(update_script_history), @@ -526,7 +535,8 @@ async fn create_script_internal<'c>( ))); }; - let ps = get_script_by_hash_internal(tx.transaction_mut(), &w_id, p_hash).await?; + let ScriptWithStarred { script: ps, .. } = + get_script_by_hash_internal(tx.transaction_mut(), &w_id, p_hash, None).await?; if ps.path != ns.path { require_owner_of_path(&authed, &ps.path)?; @@ -578,6 +588,8 @@ async fn create_script_internal<'c>( || ns.language == ScriptLang::Bun || ns.language == ScriptLang::Bunnative || ns.language == ScriptLang::Deno + || ns.language == ScriptLang::Rust + || ns.language == ScriptLang::Ansible || ns.language == ScriptLang::Php) { Some(String::new()) @@ -595,8 +607,8 @@ async fn create_script_internal<'c>( }; let lang = if &ns.language == &ScriptLang::Bun || &ns.language == &ScriptLang::Bunnative { - let anns = get_annotation(&ns.content); - if anns.native_mode { + let anns = windmill_common::worker::TypeScriptAnnotations::parse(&ns.content); + if anns.native { ScriptLang::Bunnative } else { ScriptLang::Bun @@ -609,8 +621,8 @@ async fn create_script_internal<'c>( content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, \ draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, \ dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, \ - delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase) \ - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30)", + delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase, has_preprocessor) \ + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31)", &w_id, &hash.0, ns.path, @@ -640,7 +652,8 @@ async fn create_script_internal<'c>( ns.concurrency_key, ns.visible_to_runner_only, ns.no_main_func, - codebase + codebase, + ns.has_preprocessor, ) .execute(&mut tx) .await?; @@ -735,6 +748,7 @@ async fn create_script_internal<'c>( }, ); } + let permissioned_as = username_to_permissioned_as(&authed.username); if needs_lock_gen { let tag = if ns.dedicated_worker.is_some_and(|x| x) { @@ -826,25 +840,62 @@ async fn get_script_by_path( authed: ApiAuthed, Extension(user_db): Extension, Path((w_id, path)): Path<(String, StripPath)>, -) -> JsonResult {#if !notFound} @@ -181,13 +193,29 @@ {#if !emptyString(error)}{error}{:else}
{/if} - +
+ +
+{:else if resourceTypeInfo?.format_extension} +
+ File content ({resourceTypeInfo.format_extension}) +
+
+
+ +
{:else}
{#if step > 1} diff --git a/frontend/src/lib/components/AppConnectInner.svelte b/frontend/src/lib/components/AppConnectInner.svelte index b99ad4855c..e568589b49 100644 --- a/frontend/src/lib/components/AppConnectInner.svelte +++ b/frontend/src/lib/components/AppConnectInner.svelte @@ -31,6 +31,7 @@ export let isGoogleSignin = false export let disabled = false export let manual = true + export let express = false let isValid = true @@ -53,17 +54,23 @@ let args: any = {} let renderDescription = true - $: linkedSecretCandidates = apiTokenApps[resourceType]?.linkedSecret - ? ([apiTokenApps[resourceType]?.linkedSecret] as string[]) - : args != undefined - ? Object.keys(args).filter((x) => - ['token', 'secret', 'key', 'pass', 'private'].some((y) => x.toLowerCase().includes(y)) - ) - : undefined + function computeCandidates(resourceType: string, argsKeys: string[]) { + return apiTokenApps[resourceType]?.linkedSecret + ? ([apiTokenApps[resourceType]?.linkedSecret] as string[]) + : argsKeys.filter((x) => + ['token', 'secret', 'key', 'pass', 'private'].some((y) => x.toLowerCase().includes(y)) + ) + } - $: linkedSecret = - forceSecretValue(resourceType) ?? - linkedSecretCandidates?.sort((ua, ub) => linkedSecretValue(ub) - linkedSecretValue(ua))?.[0] + let linkedSecret: string | undefined = undefined + let linkedSecretCandidates: string[] | undefined = undefined + function computeLinkedSecret(resourceType: string, argsKeys: string[]) { + linkedSecretCandidates = computeCandidates(resourceType, argsKeys) + return ( + forceSecretValue(resourceType) ?? + linkedSecretCandidates?.sort((ua, ub) => linkedSecretValue(ub) - linkedSecretValue(ua))?.[0] + ) + } let scopes: string[] = [] let extra_params: [string, string][] = [] @@ -75,10 +82,7 @@ let pathError = '' - let expressOAuthSetup = false - - export async function open(rt?: string, express?: boolean) { - expressOAuthSetup = express ?? false + export async function open(rt?: string) { if (!rt) { loadResourceTypes() } @@ -89,12 +93,12 @@ valueToken = undefined await loadConnects() manual = !connects?.includes(resourceType) - if (manual && expressOAuthSetup) { + if (manual && express) { dispatch('error', 'Express OAuth setup is not available for non OAuth resource types') return } if (rt) { - if (!manual && expressOAuthSetup) { + if (!manual && express) { await getScopesAndParams() step = 2 } @@ -165,7 +169,6 @@ } function popupListener(event) { - console.log('popupListener', event.data, event.origin, window.location.origin) let data = event.data if (event.origin == null || event.origin !== window.location.origin) { return @@ -181,7 +184,7 @@ value = data.res.access_token! valueToken = data.res step = 4 - if (expressOAuthSetup) { + if (express) { path = `u/${$userStore?.username}/${resourceType}_${new Date().getTime()}` next() } @@ -199,9 +202,14 @@ workspace: $workspaceStore!, path: resourceType }) + const newArgsKeys = Object.keys(resourceTypeInfo?.schema?.['properties'] ?? {}) ?? [] + if (!linkedSecret) { + linkedSecret = computeLinkedSecret(resourceType, newArgsKeys) + } } export async function next() { if (step == 1) { + linkedSecret = undefined if (manual) { getResourceTypeInfo() args = {} @@ -318,253 +326,254 @@ let editScopes = false - a.localeCompare(b)) - .map((key) => ({ - key - })) - : undefined} - bind:filteredItems={filteredConnects} - f={(x) => x.key} -/> - a[0].localeCompare(b[0]))} - bind:filteredItems={filteredConnectsManual} - f={(x) => x[0]} -/> - -{#if step == 1} -
- -
- -

OAuth APIs

-
- {#if filteredConnects} - {#each filteredConnects as { key }} - - {/each} - {:else} - {#each new Array(3) as _} - - {/each} - {/if} -
- {#if connects && connects.length == 0} -
No OAuth APIs has been setup on the instance. To add oauth APIs, first sync the resource - types with the hub, then add oauth configuration. See documentation -
- {/if} - -

Others

- - {#if connectsManual && connectsManual?.length < 10} -
- Resource Types have not been synced with the hub. Go to the admins workspace to sync them (and - add a schedule to do daily): -

1. Go to the "admins" workspaces: - sync resource types -

-

- 2: Run the synchronization script: - sync resource types -

-
- {/if} - -
- {#if filteredConnectsManual} - {#each filteredConnectsManual as [key, _]} - {#if nativeLanguagesCategory.includes(key)} - - {/if} - {/each} - {/if} -
- -
-
- {#if filteredConnectsManual} - {#each filteredConnectsManual as [key, _]} - {#if !nativeLanguagesCategory.includes(key)} - - - {/if} - {/each} - {:else} - {#each new Array(9) as _} - - {/each} - {/if} -
-{:else if step == 2 && manual} - a.localeCompare(b)) + .map((key) => ({ + key + })) + : undefined} + bind:filteredItems={filteredConnects} + f={(x) => x.key} /> - - {#if apiTokenApps[resourceType]} -

Instructions

-
-
    - {#each apiTokenApps[resourceType].instructions as step} -
  1. - {@html step} -
  2. - {/each} -
-
- {#if apiTokenApps[resourceType].img} -
- connect -
- {/if} - {:else if !emptyString(resourceTypeInfo?.description)} -

{resourceTypeInfo?.name} description

-
- -
- {/if} - {#if resourceType == 'postgresql' || resourceType == 'mysql' || resourceType == 'mongodb'} - - {/if} - -

Resource description -
- - -
-

- {#if renderDescription} -
-
GH Markdown
-