diff --git a/.github/workflows/clean-up.yml b/.github/workflows/clean-up.yml index 4cc29c4ef..9e8b951b8 100644 --- a/.github/workflows/clean-up.yml +++ b/.github/workflows/clean-up.yml @@ -16,7 +16,8 @@ jobs: # and it should run even if other tests fail, to ensure that we keep the ClickHouse Cloud # instance clean for the next runs to avoid adding cleanup cost to the critical path of the tests. cloud-cleanup: - if: always() + # Cloud secrets are not available for Dependabot pushes; skip the cleanup in that case. + if: ${{ always() && github.triggering_actor != 'dependabot[bot]' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 8303d502e..b90e7f842 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -75,7 +75,7 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Start ClickHouse (version - ${{ matrix.clickhouse }}) in Docker - uses: isbang/compose-action@3846bcd61da338e9eaaf83e7ed0234a12b099b72 # v2.4.2 + uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0 env: CLICKHOUSE_VERSION: ${{ matrix.clickhouse }} with: diff --git a/.github/workflows/github-export-otel.yml b/.github/workflows/github-export-otel.yml index a26da23c5..10baae3cb 100644 --- a/.github/workflows/github-export-otel.yml +++ b/.github/workflows/github-export-otel.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Export Workflow Telemetry - uses: ClickHouse/github-actions-opentelemetry@166e4f803ea5857cfcd90502d99fd35ccb20de32 + uses: ClickHouse/github-actions-opentelemetry@a43396f9eb698c48126a0d3cbe6b851858188753 # node24 env: OTEL_SERVICE_NAME: github-actions OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index f4770a6f2..99753c4bd 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -81,6 +81,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@c35d1b164463ee62a100735382aaaa525c5d3496 # codeql-bundle-v2.25.6 with: sarif_file: results.sarif diff --git a/.github/workflows/tests-node.yml b/.github/workflows/tests-node.yml index cb90d37a3..260300722 100644 --- a/.github/workflows/tests-node.yml +++ b/.github/workflows/tests-node.yml @@ -59,6 +59,20 @@ jobs: run: | npm run lint + - name: Check formatting (Prettier) + env: + NO_COLOR: "1" + run: | + if ! npm run -s prettier:check > prettier-output.txt 2>&1; then + cat prettier-output.txt + grep -E '^\[warn\] ' prettier-output.txt \ + | grep -vE 'Code style issues|Run Prettier|Forgot to run' \ + | sed -E 's#^\[warn\] (.+)$#::error file=\1::File is not formatted with Prettier. Run "npm run prettify" to fix.#' || true + echo "::error::Prettier check failed. Run 'npm run prettify' locally to fix formatting." + exit 1 + fi + cat prettier-output.txt + common-unit-tests: timeout-minutes: 5 runs-on: ubuntu-latest @@ -88,6 +102,19 @@ jobs: run: | node .scripts/export-coverage-metrics.mjs + - name: Upload coverage to Codecov + # Codecov token is not available for Dependabot PRs or PRs from forks; skip the upload in those cases. + # Upload coverage from a single canonical combination (Node 24) so Codecov + # receives exactly one upload per flag (see codecov.yml). + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.node == 24 }} + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 + with: + name: node-common-unit + flags: node-common-unit + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage/lcov.info + fail_ci_if_error: true + unit-tests: timeout-minutes: 5 runs-on: ubuntu-latest @@ -122,6 +149,19 @@ jobs: run: | node .scripts/export-coverage-metrics.mjs + - name: Upload coverage to Codecov + # Codecov token is not available for Dependabot PRs or PRs from forks; skip the upload in those cases. + # Upload coverage from a single canonical combination (Node 24) so Codecov + # receives exactly one upload per flag (see codecov.yml). + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.node == 24 }} + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 + with: + name: node-unit + flags: node-unit + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage/lcov.info + fail_ci_if_error: true + integration-tests-local-single-node: timeout-minutes: 5 runs-on: ubuntu-latest @@ -151,7 +191,7 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Start ClickHouse (version - ${{ matrix.clickhouse }}) in Docker - uses: isbang/compose-action@3846bcd61da338e9eaaf83e7ed0234a12b099b72 # v2.4.2 + uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0 env: CLICKHOUSE_VERSION: ${{ matrix.clickhouse }} with: @@ -183,6 +223,19 @@ jobs: run: | node .scripts/export-coverage-metrics.mjs + - name: Upload coverage to Codecov + # Codecov token is not available for Dependabot PRs or PRs from forks; skip the upload in those cases. + # Upload coverage from a single canonical combination (Node 24, ClickHouse + # latest, default log level) so Codecov receives exactly one upload per flag. + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.node == 24 && matrix.clickhouse == 'latest' && matrix.log_level == 'undefined' }} + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 + with: + name: node-integration-single + flags: node-integration-single + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage/lcov.info + fail_ci_if_error: true + integration-tests-local-cluster: timeout-minutes: 5 runs-on: ubuntu-latest @@ -196,7 +249,7 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Start ClickHouse cluster (version - ${{ matrix.clickhouse }}) in Docker - uses: isbang/compose-action@3846bcd61da338e9eaaf83e7ed0234a12b099b72 # v2.4.2 + uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0 env: CLICKHOUSE_VERSION: ${{ matrix.clickhouse }} with: @@ -222,9 +275,22 @@ jobs: run: | node .scripts/export-coverage-metrics.mjs + - name: Upload coverage to Codecov + # Codecov token is not available for Dependabot PRs or PRs from forks; skip the upload in those cases. + # Upload coverage from a single canonical combination (Node 24, ClickHouse + # latest) so Codecov receives exactly one upload per flag. + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.node == 24 && matrix.clickhouse == 'latest' }} + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 + with: + name: node-integration-cluster + flags: node-integration-cluster + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage/lcov.info + fail_ci_if_error: true + integration-tests-cloud: - # Cloud secrets are not available for PRs from forks; skip the job in that case. - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + # Cloud secrets are not available for PRs from forks or Dependabot PRs; skip the job in those cases. + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} timeout-minutes: 5 runs-on: ubuntu-latest strategy: @@ -258,50 +324,15 @@ jobs: run: | node .scripts/export-coverage-metrics.mjs - # It should only use the current LTS version of Node.js. - codecov-upload: - timeout-minutes: 5 - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - clickhouse: [head, latest] - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - fetch-depth: 0 - - - name: Start ClickHouse (version - ${{ matrix.clickhouse }}) in Docker - uses: isbang/compose-action@3846bcd61da338e9eaaf83e7ed0234a12b099b72 # v2.4.2 - env: - CLICKHOUSE_VERSION: ${{ matrix.clickhouse }} - with: - compose-file: "docker-compose.yml" - down-flags: "--volumes" - - - name: Setup NodeJS - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: 24 - - - name: Install dependencies - run: | - npm install - - - name: Add ClickHouse TLS instance to /etc/hosts - run: | - sudo echo "127.0.0.1 server.clickhouseconnect.test" | sudo tee -a /etc/hosts - - - name: Run unit + integration + TLS tests with coverage - env: - LOG_LEVEL: TRACE - run: | - npm run test:node:coverage - - name: Upload coverage to Codecov + # Codecov token is not available for Dependabot PRs or PRs from forks; skip the upload in those cases. + # Upload coverage from a single canonical combination (Node 24) so Codecov + # receives exactly one upload per flag (see codecov.yml). + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.node == 24 }} uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 with: - name: node + name: node-integration-cloud + flags: node-integration-cloud token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage/lcov.info fail_ci_if_error: true @@ -315,7 +346,6 @@ jobs: "integration-tests-local-single-node", "integration-tests-local-cluster", "integration-tests-cloud", - "codecov-upload", ] # Run even if some needed jobs were skipped (e.g. cloud jobs on PRs from forks), # but still fail if any of them failed or were cancelled. diff --git a/.github/workflows/tests-oss-dependents.yml b/.github/workflows/tests-oss-dependents.yml new file mode 100644 index 000000000..38dc93ca7 --- /dev/null +++ b/.github/workflows/tests-oss-dependents.yml @@ -0,0 +1,79 @@ +name: "oss-dependents" + +permissions: {} +on: + workflow_dispatch: + push: + branches: + - main + paths-ignore: + - "**/*.md" + - "LICENSE" + - "benchmarks/**" + pull_request: + paths-ignore: + - "**/*.md" + - "LICENSE" + - "benchmarks/**" + + schedule: + - cron: "0 9 * * *" + +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + # Runnable reproductions of how the top OSS dependents use the client, resolved + # against the workspace source via the @clickhouse/client* vitest aliases. This + # is a separate workflow so a regression that breaks a known consumer is clearly + # attributable. It targets only the stable ClickHouse release on a local + # single-node instance, across the supported Node.js versions. + oss-dependents-tests: + timeout-minutes: 5 + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node: [20, 22, 24] + + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Start ClickHouse (stable) in Docker + uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0 + env: + CLICKHOUSE_VERSION: latest + with: + compose-file: "docker-compose.yml" + down-flags: "--volumes" + + - name: Setup NodeJS ${{ matrix.node }} + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: ${{ matrix.node }} + + - name: Install dependencies + run: | + npm ci + + # The oss-dependents specs resolve `@clickhouse/client*` to the built + # workspace packages (not `src`), so build before running them. + - name: Build workspace packages + run: | + npm run build + + - name: Run OSS-dependent integration tests + run: | + npm run test:node:oss-dependents + + success: + needs: ["oss-dependents-tests"] + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Fail if any needed job failed or was cancelled + if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} + run: exit 1 + - name: All OSS-dependent tests passed + run: echo "All OSS-dependent tests passed! 🎉" diff --git a/.github/workflows/tests-web.yml b/.github/workflows/tests-web.yml index f15e1768b..fd7d53dc2 100644 --- a/.github/workflows/tests-web.yml +++ b/.github/workflows/tests-web.yml @@ -64,6 +64,19 @@ jobs: run: | node .scripts/export-coverage-metrics.mjs + - name: Upload coverage to Codecov + # Codecov token is not available for Dependabot PRs or PRs from forks; skip the upload in those cases. + # Upload coverage from a single canonical combination (Chromium) so Codecov + # receives exactly one upload per flag (see codecov.yml). + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.browser == 'chromium' }} + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 + with: + name: web-common-unit + flags: web-common-unit + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage/lcov.info + fail_ci_if_error: true + all-tests-local-single-node: timeout-minutes: 5 runs-on: ubuntu-latest @@ -76,7 +89,7 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Start ClickHouse (version - ${{ matrix.clickhouse }}) in Docker - uses: isbang/compose-action@3846bcd61da338e9eaaf83e7ed0234a12b099b72 # v2.4.2 + uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0 env: CLICKHOUSE_VERSION: ${{ matrix.clickhouse }} with: @@ -105,6 +118,19 @@ jobs: run: | node .scripts/export-coverage-metrics.mjs + - name: Upload coverage to Codecov + # Codecov token is not available for Dependabot PRs or PRs from forks; skip the upload in those cases. + # Upload coverage from a single canonical combination (Chromium, ClickHouse + # latest) so Codecov receives exactly one upload per flag. + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.browser == 'chromium' && matrix.clickhouse == 'latest' }} + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 + with: + name: web-all-single + flags: web-all-single + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage/lcov.info + fail_ci_if_error: true + integration-tests-local-cluster: timeout-minutes: 5 runs-on: ubuntu-latest @@ -117,7 +143,7 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Start ClickHouse cluster (version - ${{ matrix.clickhouse }}) in Docker - uses: isbang/compose-action@3846bcd61da338e9eaaf83e7ed0234a12b099b72 # v2.4.2 + uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0 env: CLICKHOUSE_VERSION: ${{ matrix.clickhouse }} with: @@ -146,9 +172,22 @@ jobs: run: | node .scripts/export-coverage-metrics.mjs + - name: Upload coverage to Codecov + # Codecov token is not available for Dependabot PRs or PRs from forks; skip the upload in those cases. + # Upload coverage from a single canonical combination (Chromium, ClickHouse + # latest) so Codecov receives exactly one upload per flag. + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.browser == 'chromium' && matrix.clickhouse == 'latest' }} + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 + with: + name: web-integration-cluster + flags: web-integration-cluster + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage/lcov.info + fail_ci_if_error: true + integration-tests-cloud: - # Cloud secrets are not available for PRs from forks; skip the job in that case. - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + # Cloud secrets are not available for PRs from forks or Dependabot PRs; skip the job in those cases. + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} timeout-minutes: 5 runs-on: ubuntu-latest strategy: @@ -183,51 +222,15 @@ jobs: run: | node .scripts/export-coverage-metrics.mjs - # It should only use the current version of Chrome - codecov-upload: - timeout-minutes: 5 - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - clickhouse: [head, latest] - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - fetch-depth: 0 - - - name: Start ClickHouse (version - ${{ matrix.clickhouse }}) in Docker - uses: isbang/compose-action@3846bcd61da338e9eaaf83e7ed0234a12b099b72 # v2.4.2 - env: - CLICKHOUSE_VERSION: ${{ matrix.clickhouse }} - with: - compose-file: "docker-compose.yml" - down-flags: "--volumes" - - - name: Setup NodeJS - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: 24 - - - name: Install dependencies - run: | - npm install - npx playwright install chromium - - - name: Add ClickHouse TLS instance to /etc/hosts - run: | - sudo echo "127.0.0.1 server.clickhouseconnect.test" | sudo tee -a /etc/hosts - - - name: Run unit + integration + TLS tests with coverage - env: - LOG_LEVEL: TRACE - run: | - npm run test:web:coverage - - name: Upload coverage to Codecov + # Codecov token is not available for Dependabot PRs or PRs from forks; skip the upload in those cases. + # Upload coverage from a single canonical combination (Chromium) so Codecov + # receives exactly one upload per flag (see codecov.yml). + if: ${{ github.triggering_actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.browser == 'chromium' }} uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 with: - name: web + name: web-integration-cloud + flags: web-integration-cloud token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage/lcov.info fail_ci_if_error: true @@ -239,7 +242,6 @@ jobs: "all-tests-local-single-node", "integration-tests-local-cluster", "integration-tests-cloud", - "codecov-upload", ] # Run even if some needed jobs were skipped (e.g. cloud jobs on PRs from forks), # but still fail if any of them failed or were cancelled. diff --git a/.github/workflows/upstream-sql-tests.yml b/.github/workflows/upstream-sql-tests.yml index 5c410df6c..9ce98b251 100644 --- a/.github/workflows/upstream-sql-tests.yml +++ b/.github/workflows/upstream-sql-tests.yml @@ -68,7 +68,7 @@ jobs: node-version: 24 - name: Setup Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" @@ -78,7 +78,7 @@ jobs: pip install jinja2 - name: Start ClickHouse (version - ${{ matrix.clickhouse }}) in Docker - uses: isbang/compose-action@3846bcd61da338e9eaaf83e7ed0234a12b099b72 # v2.4.2 + uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0 env: CLICKHOUSE_VERSION: ${{ matrix.clickhouse }} with: @@ -105,7 +105,7 @@ jobs: - name: Upload test artifacts if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: upstream-sql-tests-${{ matrix.clickhouse }}-shard-${{ matrix.shard }} retention-days: 14 diff --git a/.scripts/update_version.sh b/.scripts/update_version.sh index caa4b7f92..7f4ca3278 100755 --- a/.scripts/update_version.sh +++ b/.scripts/update_version.sh @@ -21,7 +21,7 @@ done for package in packages/client-common packages/client-node packages/client-web; do if [ -f "$package/package.json" ]; then echo "Updating version in $package/src/version.ts" - echo "export default '$version'" > "$package/src/version.ts" + echo "export default \"$version\";" > "$package/src/version.ts" fi done diff --git a/CHANGELOG.md b/CHANGELOG.md index fcc92e117..3804223a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +# 1.22.0 + +## New features + +- (Node.js) The `compression.request` / `compression.response` client options now accept an explicit codec via an object, in addition to the existing boolean: `true` keeps gzip (backwards compatible), and `{ codec: "zstd" }` selects zstd. The object form is intentionally extensible for future codecs and codec-specific options. zstd typically yields a similar-or-better ratio than gzip at noticeably lower CPU cost (gzip/DEFLATE is comparatively CPU-heavy and decompressed single-threaded by the ClickHouse server), and it uses the built-in `zlib` zstd support, so it requires **Node.js >= 22.15.0** (`@clickhouse/client` throws a clear error at client creation otherwise). Response decompression is driven by the server's actual `Content-Encoding`, so it degrades gracefully. The request object form also accepts an optional `level` (`{ codec, level }`) to set the codec-specific compression level (zlib level for gzip, zstd compression level for zstd); the response compression level is controlled by the server. Supported only by `@clickhouse/client` (Node.js); `@clickhouse/client-web` rejects the `zstd` codec at client creation. + +- (Node.js) Brotli (`{ codec: "br" }`) is now supported for `compression.request` / `compression.response`, alongside gzip and zstd. Unlike zstd, Brotli is available on every supported Node.js version (no minimum-version requirement). The `compression.request` option is a per-codec discriminated union, so each codec exposes its own tuning option: a `level` for gzip/zstd, a `quality` for Brotli (`{ codec: "br", quality }`). When omitted, Brotli defaults to quality 4 for request bodies, since zlib's brotli default of 11 (max) is far too slow for a streaming insert path. Response decompression follows the server's `Content-Encoding`. Supported only by `@clickhouse/client` (Node.js). + +## Internal changes (`@clickhouse/client-common`) + +> These only affect code that imports the low-level connection primitives from the deprecated `@clickhouse/client-common` package directly (e.g. a custom `Connection` implementation). The `createClient` `compression` option is unchanged and fully backwards compatible — if you only use `@clickhouse/client` or `@clickhouse/client-web`, you are not affected. + +To carry the codec (and its optional compression level) instead of a bare on/off flag, the internal compression representation changed shape: + +- `CompressionSettings.compress_request` / `decompress_response` are no longer `boolean`. They are now a normalized codec object or `undefined` (disabled): `{ codec: "gzip" | "zstd"; level?: number } | { codec: "br"; quality?: number }` for the request, `{ codec: "gzip" | "zstd" | "br" }` for the response (response compression options are chosen by the server). `getConnectionParams` normalizes the public request option into this form (`true` → `{ codec: "gzip" }`). +- `withCompressionHeaders` now takes `request_compression_codec` / `response_compression_codec` (a `CompressionMethod | undefined`) instead of the boolean `enable_request_compression` / `enable_response_compression`; the codec value is also the `Content-Encoding` / `Accept-Encoding` it emits. +- `withHttpSettings` now takes the response codec object (`{ codec } | undefined`) instead of a `boolean`. +- New exported types: `CompressionMethod`, `RequestCompression`, `ResponseCompression`. + +Why: a single `boolean` could not express which codec to use or its level, and a separate level field on `CompressionSettings` would have mixed a codec-specific option into the shared type. Discriminating by codec keeps each codec's options on the codec it belongs to. + +## Documentation + +- Added two **tracer adapter recipes** to [`docs/howto/tracing.md`](./docs/howto/tracing.md) and [`examples/node/coding/otel_tracing.ts`](./examples/node/coding/otel_tracing.ts), demonstrating how common OpenTelemetry auto-instrumentation options compose as thin userland wrappers around the `tracer` API instead of being baked into the client: `requireParentSpan` (skip ClickHouse spans when there is no active parent span — e.g. background health checks) and suppressing the duplicate nested HTTP spans emitted by `@opentelemetry/instrumentation-http` (via `suppressTracing` from `@opentelemetry/core`). + # 1.21.0 ## New features diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56b34a886..5e521a54e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,10 +37,11 @@ sudo -- sh -c "echo 127.0.0.1 server.clickhouseconnect.test >> /etc/hosts" ## Style Guide -We use an automatic code formatting with `prettier` and `eslint`, both should be installed after running `npm i`. +We use automatic code formatting with `prettier` and linting with `eslint`, both should be installed after running `npm i`. Additionally, every commit should trigger a [Husky](https://typicode.github.io/husky/) Git hook that applies `prettier` -and checks the code with `eslint` via `lint-staged` automatically. +to the staged files via `lint-staged` automatically. `eslint` is not run by the commit hook; it runs in CI (with +`--max-warnings=0`), so run it manually with `npm run lint` (or `npm run lint:fix`) before pushing. ## Testing @@ -69,7 +70,19 @@ npm run typecheck npm run lint:fix ``` -However, usually, it is enough to rely on Husky Git hooks. +Formatting can be checked or applied repo-wide with: + +```bash +npm run prettier:check +npm run prettify +``` + +The Husky Git hook formats staged files with `prettier` on commit, but does not run `eslint`; make sure to run +`npm run lint` before pushing, as CI enforces it with zero warnings. + +Every ESLint rule is configured as a `warn` (the only hard errors come from the TypeScript compiler, i.e. +`npm run typecheck`). Because CI runs `eslint --max-warnings=0`, any ESLint warning still fails the build, so +treat all warnings as errors that must be fixed before merging. ### Running unit tests diff --git a/benchmarks/eslint.config.mjs b/benchmarks/eslint.config.mjs new file mode 100644 index 000000000..4b6247838 --- /dev/null +++ b/benchmarks/eslint.config.mjs @@ -0,0 +1,20 @@ +import { defineConfig } from "eslint/config"; +import { + recommendedWarnConfigs, + typescriptEslintConfig, +} from "../eslint.config.base.mjs"; + +export default defineConfig( + // Recommended rule sets, downgraded to warnings (only tsc reports errors) + ...recommendedWarnConfigs, + typescriptEslintConfig(import.meta.dirname), + { + // Benchmarks are standalone scripts that intentionally print to stdout. + rules: { + "no-console": "off", + }, + }, + { + ignores: ["dist", "node_modules", "eslint.config.mjs"], + }, +); diff --git a/benchmarks/transport/README.md b/benchmarks/transport/README.md new file mode 100644 index 000000000..60b9b4e30 --- /dev/null +++ b/benchmarks/transport/README.md @@ -0,0 +1,119 @@ +# Transport benchmark: `http`/`https` vs `undici` + +--- + +This benchmark provides reproducible numbers for the proposal in +[#511](https://github.com/ClickHouse/clickhouse-js/issues/511): replacing the +legacy `node:http` / `node:https` transport used by `@clickhouse/client` with +`undici`. + +It compares `@clickhouse/client` **as built from this repository** (resolved via +the npm workspace symlink, which uses `http`/`https` internally) against a +**trivial `undici.request()`-based stub** over the exact same HTTP requests, so +the difference reflects raw transport cost rather than client-side parsing or +configuration. + +> **Why `undici.request()` and not the global `fetch()`?** `fetch()` exposes the +> response body through the WebStreams (`ReadableStream`) layer, which is a known +> Node.js-core bottleneck ([nodejs/undici#1203](https://github.com/nodejs/undici/issues/1203)) +> and drains large bodies several times slower than native streams. `request()` +> returns a native Node `Readable` — the same stream type `@clickhouse/client` +> drains — so this is an apples-to-apples transport comparison and reflects the +> API a real migration would actually adopt. An earlier revision of this +> benchmark used `fetch()` and showed it losing the download scenario by ~5×; +> that gap was entirely the WebStreams penalty, not undici. + +Three representative use cases are measured: + +1. **Single-request latency** — many small sequential `SELECT 1` requests. +2. **Download throughput** — streaming a large result set and draining it. +3. **Upload throughput** — `POST`ing a large insert body to the `null()` table + function (data is discarded server-side, so no table setup is required). + +For each case the report prints throughput (where applicable) and per-request +latency distribution (`min`/`mean`/`p50`/`p90`/`p99`/`max`). + +## Run it + +All commands assume you are in the repository root. + +Start a local ClickHouse instance (the default `docker-compose.yml` works): + +```sh +docker-compose up -d +``` + +The benchmark drives `@clickhouse/client` through the compiled workspace package +(`packages/client-node/dist`), so build the workspace packages first, then run +the benchmark with `tsx`: + +```sh +# 1. Build the workspace packages so `@clickhouse/client` resolves at runtime. +npm run build + +# 2. Run the benchmark. +npx tsx benchmarks/transport/index.ts +``` + +`tsx` only transpiles at startup; it is not in the timing loop, so it does not +affect these network-bound measurements (per-request latency and large-result +throughput). + +### Configuration + +All parameters are optional and provided via environment variables: + +- `CLICKHOUSE_URL` — server URL (default: `http://localhost:8123`) +- `LATENCY_REQUESTS` — number of sequential `SELECT 1` requests (default: `200`) +- `DOWNLOAD_ROWS` — rows in the download result set (default: `1000000`) +- `UPLOAD_ROWS` — rows in the upload body (default: `1000000`) +- `ITERATIONS` — measured iterations for the throughput scenarios (default: `10`) +- `WARMUP` — warmup iterations excluded from the results (default: `3`) + +Example with custom configuration: + +```sh +npm run build \ +&& LATENCY_REQUESTS=500 DOWNLOAD_ROWS=5000000 ITERATIONS=20 \ +npx tsx benchmarks/transport/index.ts +``` + +## Sample results + +Indicative numbers from a single local run (macOS / Apple Silicon, +Node.js v24.6.0, ClickHouse `head`, `docker-compose` single node, loopback +networking, **default configuration**: `LATENCY_REQUESTS=200 +DOWNLOAD_ROWS=1000000 UPLOAD_ROWS=1000000 ITERATIONS=10 WARMUP=3`). **Reproduce +on your own hardware before drawing conclusions** — absolute values are +environment-specific. + +| Scenario | `@clickhouse/client` (http/https) | `undici.request()` stub | +| ------------------------- | --------------------------------- | ----------------------- | +| `SELECT 1` latency (mean) | ~2.1–2.7 ms | ~0.50 ms | +| Download throughput | ~1310–1440 MiB/s | ~1850–1920 MiB/s | +| Upload throughput | ~223–225 MiB/s | ~241–245 MiB/s | + +In this run `undici.request()` was faster across the board: markedly lower +small-request latency (~4–5×), faster large-result draining (~1.3–1.4×), and a +small edge on upload (which is largely server-bound for both transports). This +is the kind of signal the benchmark is meant to surface — but absolute values +are environment-specific, so measure the scenarios that matter to you. Note that +these numbers compare a bare transport stub against the full client; the stub +omits everything the real client does (see below). + +## Interpreting the results + +- Run against a **local** server to minimise network noise; for a more + realistic picture, also run it against a remote/cloud endpoint via + `CLICKHOUSE_URL`. +- The `undici.request()` stub intentionally omits everything the real client + does (request settings, retries, keep-alive tuning, compression, abort + handling, logging). It is a transport baseline, **not** a drop-in replacement, + so treat it as the best case for an `undici` migration. +- Do **not** substitute the global `fetch()` for `undici.request()` here: its + WebStreams response body drains large payloads several times slower + ([nodejs/undici#1203](https://github.com/nodejs/undici/issues/1203)) and would + misrepresent what an undici-based transport can achieve. +- Numbers vary by machine, Node.js version, and ClickHouse version. Always + capture `process.version` (printed in the header) alongside the results when + sharing them. diff --git a/benchmarks/transport/clients.ts b/benchmarks/transport/clients.ts new file mode 100644 index 000000000..f3de40b7d --- /dev/null +++ b/benchmarks/transport/clients.ts @@ -0,0 +1,127 @@ +import { createClient } from "@clickhouse/client"; +import type { ClickHouseClient } from "@clickhouse/client"; +import { Readable } from "node:stream"; +import { request } from "undici"; + +/** + * A tiny transport abstraction so the benchmark can drive both the real + * Node.js client (which uses the legacy `http`/`https` modules under the hood) + * and a trivial `undici.request()`-based stub through the exact same scenarios. + * + * Every method fully drains the response body (counting the bytes read) so the + * comparison reflects end-to-end transport cost, not just time-to-first-byte. + */ +export interface TransportClient { + readonly name: string; + /** Execute a read query and drain its response body. Returns bytes read. */ + query(sql: string): Promise; + /** POST an insert `body` for the given `query` and drain the response. */ + insert(query: string, body: string): Promise; + close(): Promise; +} + +/** + * Wraps `@clickhouse/client` as built from this repository (resolved via the + * npm workspace symlink, not the published npm release), which sends requests + * through the legacy `node:http` / `node:https` modules. `exec()` is used so we + * measure the raw transport stream without any client-side row parsing overhead. + */ +export class SdkTransportClient implements TransportClient { + readonly name = "@clickhouse/client (http/https)"; + private readonly client: ClickHouseClient; + + constructor(url: string) { + this.client = createClient({ + url, + compression: { request: false, response: false }, + }); + } + + async query(sql: string): Promise { + const { stream } = await this.client.exec({ + query: sql, + // The default `decompress_response_stream` is irrelevant here since + // compression is disabled; we just drain the raw bytes. + }); + let bytes = 0; + for await (const chunk of stream) { + bytes += (chunk as Buffer).length; + } + return bytes; + } + + async insert(query: string, body: string): Promise { + const { stream } = await this.client.exec({ + query, + // `values` is sent as the request body while `query` goes in the URL. + values: Readable.from(body), + }); + // Drain the (empty) response so the socket is freed for keep-alive reuse. + for await (const _chunk of stream) { + void _chunk; + } + } + + async close(): Promise { + await this.client.close(); + } +} + +/** + * A deliberately minimal `undici.request()`-based stub: no pooling + * configuration, no retries, no settings handling. Just enough to issue the + * same HTTP requests against ClickHouse so we can compare raw transport + * throughput and latency. + * + * `undici` is the low-level HTTP/1.1 client the issue suggests evaluating. + * Crucially we use `request()` rather than the global `fetch()`: `request()` + * returns the response body as a Node.js `Readable` stream, whereas `fetch()` + * exposes it through the much slower WebStreams (`ReadableStream`) layer. This + * keeps the comparison against `@clickhouse/client` apples-to-apples — both + * drain a native Node stream — and reflects the API a real migration would use. + * See https://github.com/nodejs/undici/issues/1203. + */ +export class UndiciTransportClient implements TransportClient { + readonly name = "undici request() (native stream)"; + private readonly baseUrl: string; + + constructor(url: string) { + this.baseUrl = url.endsWith("/") ? url.slice(0, -1) : url; + } + + async query(sql: string): Promise { + const { statusCode, body } = await request(this.baseUrl + "/", { + method: "POST", + body: sql, + }); + if (statusCode < 200 || statusCode >= 300) { + throw new Error(`Unexpected status ${statusCode}: ${await body.text()}`); + } + let bytes = 0; + for await (const chunk of body) { + bytes += (chunk as Buffer).length; + } + return bytes; + } + + async insert(query: string, body: string): Promise { + const url = this.baseUrl + "/?query=" + encodeURIComponent(query); + const { statusCode, body: resBody } = await request(url, { + method: "POST", + body, + }); + if (statusCode < 200 || statusCode >= 300) { + throw new Error( + `Unexpected status ${statusCode}: ${await resBody.text()}`, + ); + } + // Drain the response body to release the connection back to the pool. + for await (const _chunk of resBody) { + void _chunk; + } + } + + async close(): Promise { + // The global undici dispatcher/agent is shared; nothing to close. + } +} diff --git a/benchmarks/transport/index.ts b/benchmarks/transport/index.ts new file mode 100644 index 000000000..1b6f919e1 --- /dev/null +++ b/benchmarks/transport/index.ts @@ -0,0 +1,192 @@ +import { attachExceptionHandlers } from "../common"; +import { + SdkTransportClient, + UndiciTransportClient, + type TransportClient, +} from "./clients"; +import { + latencyStats, + mibs, + ms, + throughputMiBs, + type LatencyStats, +} from "./stats"; + +/* + * Transport benchmark: `@clickhouse/client` (legacy `http`/`https`) vs a trivial + * `undici.request()` stub. + * + * Motivation: https://github.com/ClickHouse/clickhouse-js/issues/511 proposes + * replacing the legacy `http`/`https` modules with `fetch`/`undici`. We compare + * against `undici.request()` rather than the global `fetch()` deliberately: + * `request()` returns a native Node `Readable`, while `fetch()` routes the body + * through the much slower WebStreams layer (nodejs/undici#1203), which would + * unfairly handicap the transport a real migration would adopt. Before + * committing to such a change we want trustworthy, reproducible numbers for a + * few representative use cases. This benchmark provides exactly that: an + * apples-to-apples comparison over the same HTTP requests against a local + * ClickHouse instance. + * + * Scenarios: + * 1. Single-request latency - many small sequential `SELECT 1` requests. + * 2. Download throughput - streaming a large result set and draining it. + * 3. Upload throughput - POSTing a large insert body to `null()`. + * + * Run instructions and caveats are documented in README.md. + */ + +const url = process.env["CLICKHOUSE_URL"] ?? "http://localhost:8123"; +const latencyRequests = intEnv("LATENCY_REQUESTS", 200); +const downloadRows = intEnv("DOWNLOAD_ROWS", 1_000_000); +const uploadRows = intEnv("UPLOAD_ROWS", 1_000_000); +const iterations = intEnv("ITERATIONS", 10); +const warmup = intEnv("WARMUP", 3); + +function intEnv(name: string, fallback: number): number { + const raw = process.env[name]; + if (raw === undefined) return fallback; + const parsed = Number.parseInt(raw, 10); + if (Number.isNaN(parsed) || parsed < 0) { + throw new Error(`Invalid value for ${name}: ${raw}`); + } + return parsed; +} + +interface ThroughputResult { + totalBytes: number; + elapsedMs: number; + throughput: number; + perRequest: LatencyStats; +} + +async function benchLatency(client: TransportClient): Promise { + for (let i = 0; i < warmup; i++) { + await client.query("SELECT 1 FORMAT TabSeparated"); + } + const durations: number[] = []; + for (let i = 0; i < latencyRequests; i++) { + const start = performance.now(); + await client.query("SELECT 1 FORMAT TabSeparated"); + durations.push(performance.now() - start); + } + return latencyStats(durations); +} + +async function benchDownload( + client: TransportClient, +): Promise { + const query = `SELECT number FROM system.numbers LIMIT ${downloadRows} FORMAT TabSeparated`; + for (let i = 0; i < warmup; i++) { + await client.query(query); + } + const durations: number[] = []; + let totalBytes = 0; + const start = performance.now(); + for (let i = 0; i < iterations; i++) { + const reqStart = performance.now(); + totalBytes += await client.query(query); + durations.push(performance.now() - reqStart); + } + const elapsedMs = performance.now() - start; + return { + totalBytes, + elapsedMs, + throughput: throughputMiBs(totalBytes, elapsedMs), + perRequest: latencyStats(durations), + }; +} + +async function benchUpload(client: TransportClient): Promise { + const query = `INSERT INTO FUNCTION null('n UInt64') FORMAT TabSeparated`; + const body = buildInsertBody(uploadRows); + const bodyBytes = Buffer.byteLength(body); + for (let i = 0; i < warmup; i++) { + await client.insert(query, body); + } + const durations: number[] = []; + const start = performance.now(); + for (let i = 0; i < iterations; i++) { + const reqStart = performance.now(); + await client.insert(query, body); + durations.push(performance.now() - reqStart); + } + const elapsedMs = performance.now() - start; + const totalBytes = bodyBytes * iterations; + return { + totalBytes, + elapsedMs, + throughput: throughputMiBs(totalBytes, elapsedMs), + perRequest: latencyStats(durations), + }; +} + +function buildInsertBody(rows: number): string { + const lines = new Array(rows); + for (let i = 0; i < rows; i++) { + lines[i] = String(i); + } + return lines.join("\n") + "\n"; +} + +function logLatency(label: string, stats: LatencyStats): void { + console.log( + ` ${label.padEnd(10)} samples=${stats.samples} ` + + `min=${ms(stats.min)} mean=${ms(stats.mean)} ` + + `p50=${ms(stats.p50)} p90=${ms(stats.p90)} p99=${ms(stats.p99)} ` + + `max=${ms(stats.max)}`, + ); +} + +function logThroughput(label: string, result: ThroughputResult): void { + const mib = (result.totalBytes / (1024 * 1024)).toFixed(2); + console.log( + ` ${label.padEnd(10)} ${mibs(result.throughput)} ` + + `(${mib} MiB in ${ms(result.elapsedMs)})`, + ); + logLatency("per-req", result.perRequest); +} + +async function run(): Promise { + attachExceptionHandlers(); + + console.log( + "Transport benchmark: @clickhouse/client (http/https) vs undici.request()", + ); + console.log("Configuration:"); + console.log(` url: ${url}`); + console.log(` latencyRequests: ${latencyRequests}`); + console.log(` downloadRows: ${downloadRows}`); + console.log(` uploadRows: ${uploadRows}`); + console.log(` iterations: ${iterations}`); + console.log(` warmup: ${warmup}`); + console.log(` node: ${process.version}`); + console.log(); + + const clients: TransportClient[] = [ + new SdkTransportClient(url), + new UndiciTransportClient(url), + ]; + + try { + for (const client of clients) { + console.log(`=== ${client.name} ===`); + + console.log("[latency] sequential SELECT 1"); + logLatency("latency", await benchLatency(client)); + + console.log("[download] streaming large result set"); + logThroughput("download", await benchDownload(client)); + + console.log("[upload] POST large insert body"); + logThroughput("upload", await benchUpload(client)); + + console.log(); + } + } finally { + for (const client of clients) { + await client.close(); + } + } +} + +void run().then(() => process.exit(0)); diff --git a/benchmarks/transport/stats.ts b/benchmarks/transport/stats.ts new file mode 100644 index 000000000..1edc9169a --- /dev/null +++ b/benchmarks/transport/stats.ts @@ -0,0 +1,54 @@ +/** + * Minimal timing/statistics helpers shared by the transport benchmark. + * Kept dependency-free on purpose so the benchmark can run with a plain + * `tsc` + `node` invocation (see README.md). + */ + +export interface LatencyStats { + samples: number; + min: number; + max: number; + mean: number; + p50: number; + p90: number; + p99: number; +} + +function percentile(sortedAsc: number[], p: number): number { + if (sortedAsc.length === 0) return 0; + const rank = (p / 100) * (sortedAsc.length - 1); + const low = Math.floor(rank); + const high = Math.ceil(rank); + if (low === high) return sortedAsc[low]; + const weight = rank - low; + return sortedAsc[low] * (1 - weight) + sortedAsc[high] * weight; +} + +/** Build latency statistics (in milliseconds) from a list of durations. */ +export function latencyStats(durationsMs: number[]): LatencyStats { + const sorted = [...durationsMs].sort((a, b) => a - b); + const sum = sorted.reduce((acc, v) => acc + v, 0); + return { + samples: sorted.length, + min: sorted.length ? sorted[0] : 0, + max: sorted.length ? sorted[sorted.length - 1] : 0, + mean: sorted.length ? sum / sorted.length : 0, + p50: percentile(sorted, 50), + p90: percentile(sorted, 90), + p99: percentile(sorted, 99), + }; +} + +/** Throughput in mebibytes per second given total bytes and elapsed ms. */ +export function throughputMiBs(totalBytes: number, elapsedMs: number): number { + if (elapsedMs <= 0) return 0; + return totalBytes / (1024 * 1024) / (elapsedMs / 1000); +} + +export function ms(value: number): string { + return `${value.toFixed(2)} ms`; +} + +export function mibs(value: number): string { + return `${value.toFixed(2)} MiB/s`; +} diff --git a/benchmarks/tsconfig.json b/benchmarks/tsconfig.json index 6d8c7f8c5..c936a4c3f 100644 --- a/benchmarks/tsconfig.json +++ b/benchmarks/tsconfig.json @@ -1,6 +1,11 @@ { - "extends": "../tsconfig.json", - "include": ["dev/**/*.ts", "formats/**/*.ts", "leaks/**/*.ts"], + "extends": "../tsconfig.base.json", + "include": [ + "dev/**/*.ts", + "formats/**/*.ts", + "leaks/**/*.ts", + "transport/**/*.ts" + ], "compilerOptions": { "noUnusedLocals": false, "noUnusedParameters": false, diff --git a/codecov.yml b/codecov.yml index c450df625..f5fbfcea2 100644 --- a/codecov.yml +++ b/codecov.yml @@ -2,3 +2,59 @@ coverage: range: 60..90 round: down precision: 2 + +# Coverage is uploaded incrementally from each test job in the Node.js +# (.github/workflows/tests-node.yml) and Web (.github/workflows/tests-web.yml) +# workflows, each with a distinct Codecov flag. To keep the number of uploads +# stable as the test matrices grow, every upload step is gated (via its `if:`) +# to a single canonical combination, so each flag uploads EXACTLY ONCE per +# commit: +# +# - Node.js flags upload only from Node 24 (local integration flags also require +# ClickHouse `latest`, and node-integration-single the default log level). +# - Web flags upload only from Chromium (local integration flags also require +# ClickHouse `latest`). +# +# flag workflow / job +# node-common-unit node / common-unit-tests +# node-unit node / unit-tests +# node-integration-single node / integration-tests-local-single-node +# node-integration-cluster node / integration-tests-local-cluster +# node-integration-cloud node / integration-tests-cloud +# web-common-unit web / common-unit-tests +# web-all-single web / all-tests-local-single-node +# web-integration-cluster web / integration-tests-local-cluster +# web-integration-cloud web / integration-tests-cloud +# => 9 uploads total (one per flag) +# +# `after_n_builds` therefore equals the number of flags (9). When a flag is +# added or removed, update this value and the `individual_flags` list to match. +codecov: + # Wait for the other CI checks to finish before notifying, in addition to the + # upload count below, so statuses/comments are not posted off a partial report. + notify: + wait_for_ci: true + # Total number of expected uploads before Codecov posts the final commit + # status/notification: one upload per flag (see the table above). + after_n_builds: 9 + +comment: + # Wait for all uploads before posting/updating the PR comment. + after_n_builds: 9 + +flag_management: + default_rules: + # Jobs that are conditionally skipped (e.g. cloud jobs on fork PRs) should + # not drop the total coverage; carry forward the last known coverage. Each + # flag uploads exactly once, so per-flag statuses post after a single build. + carryforward: true + individual_flags: + - name: node-common-unit + - name: node-unit + - name: node-integration-single + - name: node-integration-cluster + - name: node-integration-cloud + - name: web-common-unit + - name: web-all-single + - name: web-integration-cluster + - name: web-integration-cloud diff --git a/docs/howto/tracing.md b/docs/howto/tracing.md index 44f75578f..d8e3853e6 100644 --- a/docs/howto/tracing.md +++ b/docs/howto/tracing.md @@ -159,6 +159,75 @@ propagates to the caller of `query` / `command` / `exec` / `insert` / > is never ended. For `command`/`exec`/`insert`/`ping`, a single span ends > when the method returns. +## Adapter recipes: `requireParentSpan` and suppressing nested HTTP spans + +OpenTelemetry auto-instrumentation packages commonly expose two options that +the client deliberately does **not** implement itself - both belong in a thin +tracer adapter, where they compose with your OTEL setup: + +### Only trace when there is an active parent span + +Skip ClickHouse spans when nothing else is being traced (e.g. background +health checks or pings outside any request context). Wrap the tracer and +hand the client a no-op span when there is no active parent: + +```ts +import { context, trace } from "@opentelemetry/api"; +import { + createClient, + type ClickHouseSpan, + type ClickHouseTracer, +} from "@clickhouse/client"; + +const noop = () => undefined; +const noopSpan: ClickHouseSpan = { + setAttributes: noop, + setStatus: noop, + recordException: noop, + end: noop, +}; + +const otelTracer = trace.getTracer("@clickhouse/client"); +const tracer: ClickHouseTracer = { + startActiveSpan: (name, options, fn) => + trace.getSpan(context.active()) === undefined + ? fn(noopSpan) // no active parent span - do not trace this operation + : otelTracer.startActiveSpan(name, options, fn), +}; + +const client = createClient({ tracer }); +``` + +### Suppress nested HTTP spans + +If `@opentelemetry/instrumentation-http` is registered, every ClickHouse +operation span gets a duplicate child HTTP span for the underlying request. +To suppress them, run the operation under a suppressed context using +`suppressTracing` from `@opentelemetry/core`: + +```ts +import { context, trace } from "@opentelemetry/api"; +import { suppressTracing } from "@opentelemetry/core"; +import { createClient, type ClickHouseTracer } from "@clickhouse/client"; + +const otelTracer = trace.getTracer("@clickhouse/client"); +const tracer: ClickHouseTracer = { + startActiveSpan: (name, options, fn) => + otelTracer.startActiveSpan(name, options, (span) => + context.with(suppressTracing(context.active()), () => fn(span)), + ), +}; + +const client = createClient({ tracer }); +``` + +Alternatively, keep the raw tracer and configure the HTTP instrumentation to +ignore requests to your ClickHouse endpoint via its +`ignoreOutgoingRequestHook` option. + +Both recipes are demonstrated end-to-end in +[`examples/node/coding/otel_tracing.ts`](../../examples/node/coding/otel_tracing.ts). + ## Recording-only tracer for tests / debugging ```ts diff --git a/eslint.config.base.mjs b/eslint.config.base.mjs index 41bc9360d..a7bee0e91 100644 --- a/eslint.config.base.mjs +++ b/eslint.config.base.mjs @@ -1,6 +1,40 @@ -import pluginPrettier from "eslint-plugin-prettier"; +import js from "@eslint/js"; +import tseslint from "typescript-eslint"; import pluginExpectType from "eslint-plugin-expect-type/configs/recommended"; +// Every ESLint rule is reported as a warning rather than an error: the only hard +// errors in the pipeline should come from the TypeScript compiler (`npm run +// typecheck`). CI still runs `eslint --max-warnings=0`, so warnings keep failing +// the build, they just are not labelled as ESLint "errors". +export function onlyWarn(configs) { + return configs.map((config) => { + if (!config.rules) { + return config; + } + const rules = {}; + for (const [name, value] of Object.entries(config.rules)) { + const severity = Array.isArray(value) ? value[0] : value; + if (severity === "error" || severity === 2) { + rules[name] = Array.isArray(value) + ? ["warn", ...value.slice(1)] + : "warn"; + } else { + rules[name] = value; + } + } + return { ...config, rules }; + }); +} + +// Shared recommended rule sets, downgraded so that nothing is an error. +export const recommendedWarnConfigs = onlyWarn([ + // Base ESLint recommended rules + js.configs.recommended, + // TypeScript-ESLint recommended rules with type checking + ...tseslint.configs.strict, + ...tseslint.configs.stylistic, +]); + export function typescriptEslintConfig(root) { return { files: ["**/*.ts"], @@ -11,14 +45,13 @@ export function typescriptEslintConfig(root) { }, }, plugins: { - prettier: pluginPrettier, "expect-type": pluginExpectType, }, rules: { - "prettier/prettier": "error", - "@typescript-eslint/no-floating-promises": "error", - eqeqeq: "error", - "no-console": "error", + // Reported as warnings on purpose: only `tsc` should produce errors. + "@typescript-eslint/no-floating-promises": "warn", + eqeqeq: "warn", + "no-console": "warn", // Keep some rules relaxed until addressed in dedicated PRs "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/consistent-type-imports": "warn", diff --git a/examples/node/coding/otel_tracing.ts b/examples/node/coding/otel_tracing.ts index 758c21cc5..54304874a 100644 --- a/examples/node/coding/otel_tracing.ts +++ b/examples/node/coding/otel_tracing.ts @@ -20,14 +20,19 @@ // // See also: // - `../../../docs/howto/tracing.md` - full description of the tracer surface. -import { context, SpanStatusCode } from "@opentelemetry/api"; +import { context, SpanStatusCode, trace } from "@opentelemetry/api"; import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks"; +import { suppressTracing } from "@opentelemetry/core"; import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor, } from "@opentelemetry/sdk-trace-base"; -import { createClient, type ClickHouseTracer } from "@clickhouse/client"; +import { + createClient, + type ClickHouseSpan, + type ClickHouseTracer, +} from "@clickhouse/client"; // 1. Register the AsyncLocalStorageContextManager so that the span started by // `startActiveSpan` stays *active* across the `await` points inside the @@ -89,7 +94,6 @@ for (const span of spans) { span.attributes["clickhouse.request.query_id"], }); } -await provider.shutdown(); const spanNames = spans.map((span) => span.name); if ( @@ -101,3 +105,102 @@ if ( ); } console.info("[OtelTracing] Recorded spans:", spanNames); + +// --------------------------------------------------------------------------- +// Adapter recipes +// +// OTEL auto-instrumentation packages commonly expose two extra options - +// `requireParentSpan` and `suppressInternalInstrumentation`. Both are +// implemented here as thin wrappers around the raw OTEL tracer, composed in +// userland instead of being baked into the client. +// --------------------------------------------------------------------------- + +// Recipe 1: `requireParentSpan` - only trace ClickHouse operations when there +// is already an active parent span; otherwise hand the client a no-op span. +// Useful to suppress noise from background health checks/pings that run +// outside any traced request. +const noop = () => undefined; +const noopSpan: ClickHouseSpan = { + setAttributes: noop, + setStatus: noop, + recordException: noop, + end: noop, +}; +const requireParentSpanTracer: ClickHouseTracer = { + startActiveSpan: (name, options, fn) => + trace.getSpan(context.active()) === undefined + ? fn(noopSpan) // no active parent span - skip tracing this operation + : otelTracer.startActiveSpan(name, options, fn), +}; +const requireParentClient = createClient({ + url: process.env["CLICKHOUSE_URL"], + password: process.env["CLICKHOUSE_PASSWORD"], + tracer: requireParentSpanTracer, +}); + +exporter.reset(); +// Outside any active span: no ClickHouse span is recorded. +await requireParentClient.ping(); +// Inside a parent span: the ClickHouse span is recorded as its child. +await otelTracer.startActiveSpan("parent-request", async (parent) => { + try { + await requireParentClient.ping(); + } finally { + parent.end(); + } +}); +await requireParentClient.close(); +await provider.forceFlush(); +const requireParentSpanNames = exporter + .getFinishedSpans() + .map((span) => span.name); +if ( + requireParentSpanNames.filter((name) => name === "clickhouse.ping").length !== + 1 +) { + throw new Error( + `[OtelTracing] Expected exactly one ping span (the one with a parent), but got: ${requireParentSpanNames.join(", ")}`, + ); +} +console.info( + "[OtelTracing] requireParentSpan recipe spans:", + requireParentSpanNames, +); + +// Recipe 2: suppress nested HTTP spans - if +// `@opentelemetry/instrumentation-http` is registered, each ClickHouse +// operation span gets a duplicate child HTTP span for the underlying request. +// Running the operation under `suppressTracing` (from `@opentelemetry/core`) +// prevents those child spans while keeping the ClickHouse span itself. +// (Alternatively, configure the HTTP instrumentation's +// `ignoreOutgoingRequestHook` for your ClickHouse endpoint.) +const suppressNestedHttpTracer: ClickHouseTracer = { + startActiveSpan: (name, options, fn) => + otelTracer.startActiveSpan(name, options, (span) => + context.with(suppressTracing(context.active()), () => fn(span)), + ), +}; +const suppressNestedHttpClient = createClient({ + url: process.env["CLICKHOUSE_URL"], + password: process.env["CLICKHOUSE_PASSWORD"], + tracer: suppressNestedHttpTracer, +}); + +exporter.reset(); +await suppressNestedHttpClient.ping(); +await suppressNestedHttpClient.close(); +await provider.forceFlush(); +const suppressedSpanNames = exporter + .getFinishedSpans() + .map((span) => span.name); +if (!suppressedSpanNames.includes("clickhouse.ping")) { + throw new Error( + `[OtelTracing] Expected a ping span from the suppressTracing recipe, but got: ${suppressedSpanNames.join(", ")}`, + ); +} +console.info( + "[OtelTracing] suppressTracing recipe spans:", + suppressedSpanNames, +); + +await provider.shutdown(); diff --git a/examples/node/eslint.config.mjs b/examples/node/eslint.config.mjs index 5c1096ae8..b759162f3 100644 --- a/examples/node/eslint.config.mjs +++ b/examples/node/eslint.config.mjs @@ -1,15 +1,37 @@ import js from "@eslint/js"; import { defineConfig } from "eslint/config"; import tseslint from "typescript-eslint"; -import pluginPrettier from "eslint-plugin-prettier"; import pluginExpectType from "eslint-plugin-expect-type/configs/recommended"; +// Report every ESLint rule as a warning; only the TypeScript compiler +// (`npm run typecheck`) should produce hard errors. +function onlyWarn(configs) { + return configs.map((config) => { + if (!config.rules) { + return config; + } + const rules = {}; + for (const [name, value] of Object.entries(config.rules)) { + const severity = Array.isArray(value) ? value[0] : value; + if (severity === "error" || severity === 2) { + rules[name] = Array.isArray(value) + ? ["warn", ...value.slice(1)] + : "warn"; + } else { + rules[name] = value; + } + } + return { ...config, rules }; + }); +} + export default defineConfig( - // Base ESLint recommended rules - js.configs.recommended, - // TypeScript-ESLint recommended rules with type checking - ...tseslint.configs.strict, - ...tseslint.configs.stylistic, + // Recommended rule sets, downgraded to warnings (only tsc reports errors) + ...onlyWarn([ + js.configs.recommended, + ...tseslint.configs.strict, + ...tseslint.configs.stylistic, + ]), { files: ["**/*.ts"], languageOptions: { @@ -19,14 +41,12 @@ export default defineConfig( }, }, plugins: { - prettier: pluginPrettier, "expect-type": pluginExpectType, }, rules: { - "prettier/prettier": "error", - "@typescript-eslint/no-floating-promises": "error", - eqeqeq: "error", - "no-console": "error", + "@typescript-eslint/no-floating-promises": "warn", + eqeqeq: "warn", + "no-console": "warn", // Keep some rules relaxed until addressed in dedicated PRs "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/consistent-type-imports": "warn", diff --git a/examples/node/package-lock.json b/examples/node/package-lock.json index d454e2937..c5d226819 100644 --- a/examples/node/package-lock.json +++ b/examples/node/package-lock.json @@ -14,13 +14,13 @@ "devDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^2.7.1", - "@opentelemetry/sdk-trace-base": "^2.0.0", + "@opentelemetry/core": "^2.8.0", + "@opentelemetry/sdk-trace-base": "^2.8.0", "@types/node": "^25.2.3", "eslint": "^9.39.1", "eslint-config-prettier": "^10.1.8", "eslint-plugin-expect-type": "^0.6.2", - "eslint-plugin-prettier": "^5.5.4", - "tsx": "^4.21.0", + "tsx": "^4.22.4", "typescript": "^5.9.3", "typescript-eslint": "^8.46.4", "vitest": "^4.0.16" @@ -82,9 +82,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -99,9 +99,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -116,9 +116,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -133,9 +133,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -150,9 +150,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -167,9 +167,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -184,9 +184,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -201,9 +201,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -218,9 +218,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -235,9 +235,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -252,9 +252,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -269,9 +269,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -286,9 +286,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -303,9 +303,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -320,9 +320,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -337,9 +337,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -354,9 +354,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -371,9 +371,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -388,9 +388,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -405,9 +405,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -422,9 +422,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -439,9 +439,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -456,9 +456,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -473,9 +473,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -490,9 +490,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -507,9 +507,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -803,14 +803,14 @@ "license": "MIT" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "@tybys/wasm-util": "^0.10.2" }, "funding": { "type": "github", @@ -845,9 +845,9 @@ } }, "node_modules/@opentelemetry/core": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.1.tgz", - "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.8.0.tgz", + "integrity": "sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -861,13 +861,13 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.1.tgz", - "integrity": "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.8.0.tgz", + "integrity": "sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", + "@opentelemetry/core": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -878,14 +878,14 @@ } }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.1.tgz", - "integrity": "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.8.0.tgz", + "integrity": "sha512-mhU4jp+vW0mGbFRd+GeXHvmfA4aDqWjBjLC3pE5XMpLs0IE2ryYb019Ts2AQrOq67gaTF25D91+fgvEHDZEnuQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/resources": "2.7.1", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -906,32 +906,19 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.127.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", - "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", "cpu": [ "arm64" ], @@ -946,9 +933,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", "cpu": [ "arm64" ], @@ -963,9 +950,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", "cpu": [ "x64" ], @@ -980,9 +967,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", "cpu": [ "x64" ], @@ -997,9 +984,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", - "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", "cpu": [ "arm" ], @@ -1014,9 +1001,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", "cpu": [ "arm64" ], @@ -1034,9 +1021,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", "cpu": [ "arm64" ], @@ -1054,9 +1041,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", "cpu": [ "ppc64" ], @@ -1074,9 +1061,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", "cpu": [ "s390x" ], @@ -1094,9 +1081,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", "cpu": [ "x64" ], @@ -1114,9 +1101,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", "cpu": [ "x64" ], @@ -1134,9 +1121,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", "cpu": [ "arm64" ], @@ -1151,9 +1138,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", - "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", "cpu": [ "wasm32" ], @@ -1170,9 +1157,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", "cpu": [ "arm64" ], @@ -1187,9 +1174,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", "cpu": [ "x64" ], @@ -1204,9 +1191,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", - "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, @@ -1218,9 +1205,9 @@ "license": "MIT" }, "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, "license": "MIT", "optional": true, @@ -1838,9 +1825,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1851,32 +1838,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.7", - "@esbuild/android-arm": "0.27.7", - "@esbuild/android-arm64": "0.27.7", - "@esbuild/android-x64": "0.27.7", - "@esbuild/darwin-arm64": "0.27.7", - "@esbuild/darwin-x64": "0.27.7", - "@esbuild/freebsd-arm64": "0.27.7", - "@esbuild/freebsd-x64": "0.27.7", - "@esbuild/linux-arm": "0.27.7", - "@esbuild/linux-arm64": "0.27.7", - "@esbuild/linux-ia32": "0.27.7", - "@esbuild/linux-loong64": "0.27.7", - "@esbuild/linux-mips64el": "0.27.7", - "@esbuild/linux-ppc64": "0.27.7", - "@esbuild/linux-riscv64": "0.27.7", - "@esbuild/linux-s390x": "0.27.7", - "@esbuild/linux-x64": "0.27.7", - "@esbuild/netbsd-arm64": "0.27.7", - "@esbuild/netbsd-x64": "0.27.7", - "@esbuild/openbsd-arm64": "0.27.7", - "@esbuild/openbsd-x64": "0.27.7", - "@esbuild/openharmony-arm64": "0.27.7", - "@esbuild/sunos-x64": "0.27.7", - "@esbuild/win32-arm64": "0.27.7", - "@esbuild/win32-ia32": "0.27.7", - "@esbuild/win32-x64": "0.27.7" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/escape-string-regexp": { @@ -1988,37 +1975,6 @@ "typescript": ">=4" } }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", - "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.1", - "synckit": "^0.11.12" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -2197,13 +2153,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2988,9 +2937,9 @@ } }, "node_modules/postcss": { - "version": "8.5.13", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.13.tgz", - "integrity": "sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "dev": true, "funding": [ { @@ -3008,7 +2957,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -3026,36 +2975,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", - "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -3087,14 +3006,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", - "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.127.0", - "@rolldown/pluginutils": "1.0.0-rc.17" + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { "rolldown": "bin/cli.mjs" @@ -3103,21 +3022,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-x64": "1.0.0-rc.17", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, "node_modules/semver": { @@ -3213,22 +3132,6 @@ "node": ">=8" } }, - "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.9" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -3247,9 +3150,9 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { @@ -3295,14 +3198,13 @@ "optional": true }, "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", + "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" + "esbuild": "~0.28.0" }, "bin": { "tsx": "dist/cli.mjs" @@ -3393,17 +3295,17 @@ } }, "node_modules/vite": { - "version": "8.0.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", - "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.10", - "rolldown": "1.0.0-rc.17", - "tinyglobby": "^0.2.16" + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -3419,7 +3321,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.0", + "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", diff --git a/examples/node/package.json b/examples/node/package.json index f0f5a7034..20dfaacfc 100644 --- a/examples/node/package.json +++ b/examples/node/package.json @@ -22,13 +22,13 @@ "devDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^2.7.1", - "@opentelemetry/sdk-trace-base": "^2.0.0", + "@opentelemetry/core": "^2.8.0", + "@opentelemetry/sdk-trace-base": "^2.8.0", "@types/node": "^25.2.3", "eslint": "^9.39.1", "eslint-config-prettier": "^10.1.8", "eslint-plugin-expect-type": "^0.6.2", - "eslint-plugin-prettier": "^5.5.4", - "tsx": "^4.21.0", + "tsx": "^4.22.4", "typescript": "^5.9.3", "typescript-eslint": "^8.46.4", "vitest": "^4.0.16" diff --git a/examples/node/schema-and-deployments/create_table_cloud.ts b/examples/node/schema-and-deployments/create_table_cloud.ts index a443e10d1..57ba16ed5 100644 --- a/examples/node/schema-and-deployments/create_table_cloud.ts +++ b/examples/node/schema-and-deployments/create_table_cloud.ts @@ -1,31 +1,37 @@ import { createClient } from "@clickhouse/client"; -if (!process.env["CLICKHOUSE_CLOUD_URL"]) { - throw new Error("CLICKHOUSE_CLOUD_URL environment variable is not set"); -} -if (!process.env["CLICKHOUSE_CLOUD_PASSWORD"]) { - throw new Error("CLICKHOUSE_CLOUD_PASSWORD environment variable is not set"); -} +const url = process.env["CLICKHOUSE_CLOUD_URL"]; +const password = process.env["CLICKHOUSE_CLOUD_PASSWORD"]; -const client = createClient({ - url: process.env["CLICKHOUSE_CLOUD_URL"], - password: process.env["CLICKHOUSE_CLOUD_PASSWORD"], -}); -// Note that ENGINE and ON CLUSTER clauses can be omitted entirely here. -// ClickHouse cloud will automatically use ReplicatedMergeTree -// with appropriate settings in this case. -await client.command({ - query: ` - CREATE TABLE IF NOT EXISTS clickhouse_js_example_cloud_table - (id UInt64, name String) - ORDER BY (id) - `, - // Recommended for cluster usage to avoid situations - // where a query processing error occurred after the response code - // and HTTP headers were sent to the client. - // See https://clickhouse.com/docs/en/interfaces/http/#response-buffering - clickhouse_settings: { - wait_end_of_query: 1, - }, -}); -await client.close(); +// This example targets ClickHouse Cloud and requires credentials. When they are +// not provided (e.g. CI runs without cloud secrets, such as Dependabot PRs), +// skip the example instead of failing so the rest of the examples still run. +if (!url || !password) { + console.warn( + "Skipping create_table_cloud example: set CLICKHOUSE_CLOUD_URL and " + + "CLICKHOUSE_CLOUD_PASSWORD to run it against ClickHouse Cloud.", + ); +} else { + const client = createClient({ + url, + password, + }); + // Note that ENGINE and ON CLUSTER clauses can be omitted entirely here. + // ClickHouse cloud will automatically use ReplicatedMergeTree + // with appropriate settings in this case. + await client.command({ + query: ` + CREATE TABLE IF NOT EXISTS clickhouse_js_example_cloud_table + (id UInt64, name String) + ORDER BY (id) + `, + // Recommended for cluster usage to avoid situations + // where a query processing error occurred after the response code + // and HTTP headers were sent to the client. + // See https://clickhouse.com/docs/en/interfaces/http/#response-buffering + clickhouse_settings: { + wait_end_of_query: 1, + }, + }); + await client.close(); +} diff --git a/examples/web/eslint.config.mjs b/examples/web/eslint.config.mjs index a2047a85d..29c779e44 100644 --- a/examples/web/eslint.config.mjs +++ b/examples/web/eslint.config.mjs @@ -1,15 +1,37 @@ import js from "@eslint/js"; import { defineConfig } from "eslint/config"; import tseslint from "typescript-eslint"; -import pluginPrettier from "eslint-plugin-prettier"; import pluginExpectType from "eslint-plugin-expect-type/configs/recommended"; +// Report every ESLint rule as a warning; only the TypeScript compiler +// (`npm run typecheck`) should produce hard errors. +function onlyWarn(configs) { + return configs.map((config) => { + if (!config.rules) { + return config; + } + const rules = {}; + for (const [name, value] of Object.entries(config.rules)) { + const severity = Array.isArray(value) ? value[0] : value; + if (severity === "error" || severity === 2) { + rules[name] = Array.isArray(value) + ? ["warn", ...value.slice(1)] + : "warn"; + } else { + rules[name] = value; + } + } + return { ...config, rules }; + }); +} + export default defineConfig( - // Base ESLint recommended rules - js.configs.recommended, - // TypeScript-ESLint recommended rules with type checking - ...tseslint.configs.strict, - ...tseslint.configs.stylistic, + // Recommended rule sets, downgraded to warnings (only tsc reports errors) + ...onlyWarn([ + js.configs.recommended, + ...tseslint.configs.strict, + ...tseslint.configs.stylistic, + ]), { files: ["**/*.ts"], languageOptions: { @@ -19,13 +41,11 @@ export default defineConfig( }, }, plugins: { - prettier: pluginPrettier, "expect-type": pluginExpectType, }, rules: { - "prettier/prettier": "error", - "@typescript-eslint/no-floating-promises": "error", - eqeqeq: "error", + "@typescript-eslint/no-floating-promises": "warn", + eqeqeq: "warn", // Keep some rules relaxed until addressed in dedicated PRs "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/consistent-type-imports": "warn", diff --git a/examples/web/package-lock.json b/examples/web/package-lock.json index 0764982b4..5be218d46 100644 --- a/examples/web/package-lock.json +++ b/examples/web/package-lock.json @@ -16,9 +16,8 @@ "eslint": "^9.39.1", "eslint-config-prettier": "^10.1.8", "eslint-plugin-expect-type": "^0.6.2", - "eslint-plugin-prettier": "^5.5.4", "playwright": "^1.60.0", - "tsx": "^4.21.0", + "tsx": "^4.22.4", "typescript": "^5.9.3", "typescript-eslint": "^8.46.4", "vitest": "4.1.5" @@ -84,9 +83,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -101,9 +100,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -118,9 +117,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -135,9 +134,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -152,9 +151,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -169,9 +168,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -186,9 +185,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -203,9 +202,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -220,9 +219,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -237,9 +236,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -254,9 +253,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -271,9 +270,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -288,9 +287,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -305,9 +304,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -322,9 +321,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -339,9 +338,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -356,9 +355,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -373,9 +372,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -390,9 +389,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -407,9 +406,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -424,9 +423,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -441,9 +440,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -458,9 +457,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -475,9 +474,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -492,9 +491,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -509,9 +508,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -805,14 +804,14 @@ "license": "MIT" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "@tybys/wasm-util": "^0.10.2" }, "funding": { "type": "github", @@ -824,28 +823,15 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.127.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", - "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, "node_modules/@polka/url": { "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", @@ -854,9 +840,9 @@ "license": "MIT" }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", "cpu": [ "arm64" ], @@ -871,9 +857,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", "cpu": [ "arm64" ], @@ -888,9 +874,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", "cpu": [ "x64" ], @@ -905,9 +891,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", "cpu": [ "x64" ], @@ -922,9 +908,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", - "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", "cpu": [ "arm" ], @@ -939,9 +925,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", "cpu": [ "arm64" ], @@ -959,9 +945,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", "cpu": [ "arm64" ], @@ -979,9 +965,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", "cpu": [ "ppc64" ], @@ -999,9 +985,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", "cpu": [ "s390x" ], @@ -1019,9 +1005,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", "cpu": [ "x64" ], @@ -1039,9 +1025,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", "cpu": [ "x64" ], @@ -1059,9 +1045,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", "cpu": [ "arm64" ], @@ -1076,9 +1062,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", - "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", "cpu": [ "wasm32" ], @@ -1095,9 +1081,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", "cpu": [ "arm64" ], @@ -1112,9 +1098,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", "cpu": [ "x64" ], @@ -1129,9 +1115,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", - "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, @@ -1143,9 +1129,9 @@ "license": "MIT" }, "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, "license": "MIT", "optional": true, @@ -1800,9 +1786,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1813,32 +1799,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.7", - "@esbuild/android-arm": "0.27.7", - "@esbuild/android-arm64": "0.27.7", - "@esbuild/android-x64": "0.27.7", - "@esbuild/darwin-arm64": "0.27.7", - "@esbuild/darwin-x64": "0.27.7", - "@esbuild/freebsd-arm64": "0.27.7", - "@esbuild/freebsd-x64": "0.27.7", - "@esbuild/linux-arm": "0.27.7", - "@esbuild/linux-arm64": "0.27.7", - "@esbuild/linux-ia32": "0.27.7", - "@esbuild/linux-loong64": "0.27.7", - "@esbuild/linux-mips64el": "0.27.7", - "@esbuild/linux-ppc64": "0.27.7", - "@esbuild/linux-riscv64": "0.27.7", - "@esbuild/linux-s390x": "0.27.7", - "@esbuild/linux-x64": "0.27.7", - "@esbuild/netbsd-arm64": "0.27.7", - "@esbuild/netbsd-x64": "0.27.7", - "@esbuild/openbsd-arm64": "0.27.7", - "@esbuild/openbsd-x64": "0.27.7", - "@esbuild/openharmony-arm64": "0.27.7", - "@esbuild/sunos-x64": "0.27.7", - "@esbuild/win32-arm64": "0.27.7", - "@esbuild/win32-ia32": "0.27.7", - "@esbuild/win32-x64": "0.27.7" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/escape-string-regexp": { @@ -1950,37 +1936,6 @@ "typescript": ">=4" } }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", - "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.1", - "synckit": "^0.11.12" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -2159,13 +2114,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2403,10 +2351,20 @@ "license": "ISC" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -2616,9 +2574,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2640,9 +2595,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2664,9 +2616,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2688,9 +2637,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -3017,9 +2963,9 @@ } }, "node_modules/postcss": { - "version": "8.5.13", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.13.tgz", - "integrity": "sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "dev": true, "funding": [ { @@ -3037,7 +2983,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -3055,36 +3001,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", - "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -3116,14 +3032,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", - "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.127.0", - "@rolldown/pluginutils": "1.0.0-rc.17" + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { "rolldown": "bin/cli.mjs" @@ -3132,21 +3048,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-x64": "1.0.0-rc.17", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, "node_modules/semver": { @@ -3257,22 +3173,6 @@ "node": ">=8" } }, - "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.9" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -3291,9 +3191,9 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { @@ -3349,14 +3249,13 @@ "optional": true }, "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", + "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" + "esbuild": "~0.28.0" }, "bin": { "tsx": "dist/cli.mjs" @@ -3440,17 +3339,17 @@ } }, "node_modules/vite": { - "version": "8.0.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", - "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.10", - "rolldown": "1.0.0-rc.17", - "tinyglobby": "^0.2.16" + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -3466,7 +3365,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.0", + "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -3651,9 +3550,9 @@ } }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { diff --git a/examples/web/package.json b/examples/web/package.json index 3e35f2da6..8fa7da036 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -24,9 +24,8 @@ "eslint": "^9.39.1", "eslint-config-prettier": "^10.1.8", "eslint-plugin-expect-type": "^0.6.2", - "eslint-plugin-prettier": "^5.5.4", "playwright": "^1.60.0", - "tsx": "^4.21.0", + "tsx": "^4.22.4", "typescript": "^5.9.3", "typescript-eslint": "^8.46.4", "vitest": "4.1.5" diff --git a/examples/web/schema-and-deployments/create_table_cloud.ts b/examples/web/schema-and-deployments/create_table_cloud.ts index b234a5c6a..e234e1309 100644 --- a/examples/web/schema-and-deployments/create_table_cloud.ts +++ b/examples/web/schema-and-deployments/create_table_cloud.ts @@ -1,33 +1,41 @@ import { createClient } from "@clickhouse/client-web"; -if (typeof CLICKHOUSE_CLOUD_URL === "undefined") { - throw new Error("CLICKHOUSE_CLOUD_URL is required"); -} -if (typeof CLICKHOUSE_CLOUD_PASSWORD === "undefined") { - throw new Error("CLICKHOUSE_CLOUD_PASSWORD is required"); -} +// This example targets ClickHouse Cloud and requires credentials. When they are +// not provided (e.g. CI runs without cloud secrets, such as Dependabot PRs), +// skip the example instead of failing so the rest of the examples still run. +if ( + typeof CLICKHOUSE_CLOUD_URL === "undefined" || + !CLICKHOUSE_CLOUD_URL || + typeof CLICKHOUSE_CLOUD_PASSWORD === "undefined" || + !CLICKHOUSE_CLOUD_PASSWORD +) { + console.warn( + "Skipping create_table_cloud example: set CLICKHOUSE_CLOUD_URL and " + + "CLICKHOUSE_CLOUD_PASSWORD to run it against ClickHouse Cloud.", + ); +} else { + const client = createClient({ + url: CLICKHOUSE_CLOUD_URL, + password: CLICKHOUSE_CLOUD_PASSWORD, + }); -const client = createClient({ - url: CLICKHOUSE_CLOUD_URL, - password: CLICKHOUSE_CLOUD_PASSWORD, -}); + // Note that ENGINE and ON CLUSTER clauses can be omitted entirely here. + // ClickHouse cloud will automatically use ReplicatedMergeTree + // with appropriate settings in this case. + await client.command({ + query: ` + CREATE TABLE IF NOT EXISTS clickhouse_js_example_cloud_table_web + (id UInt64, name String) + ORDER BY (id) + `, + // Recommended for cluster usage to avoid situations + // where a query processing error occurred after the response code + // and HTTP headers were sent to the client. + // See https://clickhouse.com/docs/en/interfaces/http/#response-buffering + clickhouse_settings: { + wait_end_of_query: 1, + }, + }); -// Note that ENGINE and ON CLUSTER clauses can be omitted entirely here. -// ClickHouse cloud will automatically use ReplicatedMergeTree -// with appropriate settings in this case. -await client.command({ - query: ` - CREATE TABLE IF NOT EXISTS clickhouse_js_example_cloud_table_web - (id UInt64, name String) - ORDER BY (id) - `, - // Recommended for cluster usage to avoid situations - // where a query processing error occurred after the response code - // and HTTP headers were sent to the client. - // See https://clickhouse.com/docs/en/interfaces/http/#response-buffering - clickhouse_settings: { - wait_end_of_query: 1, - }, -}); - -await client.close(); + await client.close(); +} diff --git a/package-lock.json b/package-lock.json index 80205b9e6..b072addb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,36 +14,35 @@ ], "devDependencies": { "@eslint/js": "^10.0.1", - "@faker-js/faker": "^10.4.0", + "@faker-js/faker": "^10.5.0", "@opentelemetry/api": "^1.9.1", - "@opentelemetry/auto-instrumentations-node": "^0.76.0", - "@opentelemetry/context-zone": "^2.7.1", - "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0", - "@opentelemetry/instrumentation-document-load": "^0.63.0", - "@opentelemetry/instrumentation-fetch": "^0.218.0", - "@opentelemetry/sdk-trace-web": "^2.5.1", + "@opentelemetry/auto-instrumentations-node": "^0.77.0", + "@opentelemetry/context-zone": "^2.8.0", + "@opentelemetry/exporter-trace-otlp-proto": "^0.219.0", + "@opentelemetry/instrumentation-document-load": "^0.64.0", + "@opentelemetry/instrumentation-fetch": "^0.219.0", + "@opentelemetry/sdk-trace-web": "^2.8.0", "@types/jsonwebtoken": "^9.0.10", - "@types/node": "25.9.2", + "@types/node": "25.9.3", "@types/split2": "^4.2.3", "@types/uuid": "^11.0.0", - "@vitest/browser-playwright": "^4.1.8", + "@vitest/browser-playwright": "^4.1.9", "@vitest/coverage-istanbul": "^4.1.0", "@vitest/coverage-v8": "^4.1.0", "apache-arrow": "^21.0.0", - "eslint": "^10.4.1", - "eslint-config-prettier": "^10.1.8", + "eslint": "^10.5.0", "eslint-plugin-expect-type": "^0.6.2", - "eslint-plugin-prettier": "^5.5.6", "husky": "^9.1.7", "jsonwebtoken": "^9.0.3", "lint-staged": "^17.0.7", "parquet-wasm": "0.7.1", - "playwright": "^1.60.0", + "playwright": "^1.61.0", "prettier": "3.8.4", "split2": "^4.2.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.0", + "typescript-eslint": "^8.61.1", "typescript-language-server": "^5.3.0", + "undici": "^8.5.0", "uuid": "^14.0.0", "vitest": "^4.0.16" }, @@ -507,9 +506,9 @@ } }, "node_modules/@faker-js/faker": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.4.0.tgz", - "integrity": "sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.5.0.tgz", + "integrity": "sha512-bsxD8WLS5lIj7aaoCx1YJkktqYj5vlBUE6HWzu2Q51ksrGJ0H737ECCKlFU7Yf8Br45z9t99frBp/J7kzbMPAg==", "dev": true, "funding": [ { @@ -608,6 +607,24 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -680,14 +697,14 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "@tybys/wasm-util": "^0.10.2" }, "funding": { "type": "github", @@ -709,9 +726,9 @@ } }, "node_modules/@opentelemetry/api-logs": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.218.0.tgz", - "integrity": "sha512-fmEWp5kXlGEc3i/lR698Hz41DfGyN4Tbe4g7L1AxSc7fF8Xeh/FQ9Quqpa9dVA413Q1Ad43QOLzU4JoXgbFPWw==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.219.0.tgz", + "integrity": "sha512-FFx7YnaYJlIjqWW/AG/yAZ0L/NEY724PipXXXQLdtZPbLwBGbUMTGL1i/esI56TWfTUXxhLfpgrnWJCG8aUJyg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -722,60 +739,61 @@ } }, "node_modules/@opentelemetry/auto-instrumentations-node": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.76.0.tgz", - "integrity": "sha512-44KWgqsMuqfV4UhOcwwnDeK8CpB5LT1MmpZj6sKXFXu2q6rjKo622pWgOgn5Ntp5Qal9q1uBX2VS8mvTpsMeyw==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.77.0.tgz", + "integrity": "sha512-LkF930Cs+v+ZO/qV6LolbocvFkJJ812BBDyRNjQpwllBA+rFvGtP/voXPuh24QV3JKl5/3c3GulLHvMn8spqkQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", - "@opentelemetry/instrumentation-amqplib": "^0.65.0", - "@opentelemetry/instrumentation-aws-lambda": "^0.70.0", - "@opentelemetry/instrumentation-aws-sdk": "^0.73.0", - "@opentelemetry/instrumentation-bunyan": "^0.63.0", - "@opentelemetry/instrumentation-cassandra-driver": "^0.63.0", - "@opentelemetry/instrumentation-connect": "^0.61.0", - "@opentelemetry/instrumentation-cucumber": "^0.34.0", - "@opentelemetry/instrumentation-dataloader": "^0.35.0", - "@opentelemetry/instrumentation-dns": "^0.61.0", - "@opentelemetry/instrumentation-express": "^0.66.0", - "@opentelemetry/instrumentation-fs": "^0.37.0", - "@opentelemetry/instrumentation-generic-pool": "^0.61.0", - "@opentelemetry/instrumentation-graphql": "^0.66.0", - "@opentelemetry/instrumentation-grpc": "^0.218.0", - "@opentelemetry/instrumentation-hapi": "^0.64.0", - "@opentelemetry/instrumentation-http": "^0.218.0", - "@opentelemetry/instrumentation-ioredis": "^0.66.0", - "@opentelemetry/instrumentation-kafkajs": "^0.27.0", - "@opentelemetry/instrumentation-knex": "^0.62.0", - "@opentelemetry/instrumentation-koa": "^0.66.0", - "@opentelemetry/instrumentation-lru-memoizer": "^0.62.0", - "@opentelemetry/instrumentation-memcached": "^0.61.0", - "@opentelemetry/instrumentation-mongodb": "^0.71.0", - "@opentelemetry/instrumentation-mongoose": "^0.64.0", - "@opentelemetry/instrumentation-mysql": "^0.64.0", - "@opentelemetry/instrumentation-mysql2": "^0.64.0", - "@opentelemetry/instrumentation-nestjs-core": "^0.64.0", - "@opentelemetry/instrumentation-net": "^0.62.0", - "@opentelemetry/instrumentation-openai": "^0.16.0", - "@opentelemetry/instrumentation-oracledb": "^0.43.0", - "@opentelemetry/instrumentation-pg": "^0.70.0", - "@opentelemetry/instrumentation-pino": "^0.64.0", - "@opentelemetry/instrumentation-redis": "^0.66.0", - "@opentelemetry/instrumentation-restify": "^0.63.0", - "@opentelemetry/instrumentation-router": "^0.62.0", - "@opentelemetry/instrumentation-runtime-node": "^0.31.0", - "@opentelemetry/instrumentation-socket.io": "^0.65.0", - "@opentelemetry/instrumentation-tedious": "^0.37.0", - "@opentelemetry/instrumentation-undici": "^0.28.0", - "@opentelemetry/instrumentation-winston": "^0.62.0", - "@opentelemetry/resource-detector-alibaba-cloud": "^0.33.8", - "@opentelemetry/resource-detector-aws": "^2.18.0", - "@opentelemetry/resource-detector-azure": "^0.26.0", - "@opentelemetry/resource-detector-container": "^0.8.9", - "@opentelemetry/resource-detector-gcp": "^0.53.0", + "@opentelemetry/instrumentation": "^0.219.0", + "@opentelemetry/instrumentation-amqplib": "^0.66.0", + "@opentelemetry/instrumentation-aws-lambda": "^0.71.0", + "@opentelemetry/instrumentation-aws-sdk": "^0.74.0", + "@opentelemetry/instrumentation-bunyan": "^0.64.0", + "@opentelemetry/instrumentation-cassandra-driver": "^0.64.0", + "@opentelemetry/instrumentation-connect": "^0.62.0", + "@opentelemetry/instrumentation-cucumber": "^0.35.0", + "@opentelemetry/instrumentation-dataloader": "^0.36.0", + "@opentelemetry/instrumentation-dns": "^0.62.0", + "@opentelemetry/instrumentation-express": "^0.67.0", + "@opentelemetry/instrumentation-fs": "^0.38.0", + "@opentelemetry/instrumentation-generic-pool": "^0.62.0", + "@opentelemetry/instrumentation-graphql": "^0.67.0", + "@opentelemetry/instrumentation-grpc": "^0.219.0", + "@opentelemetry/instrumentation-hapi": "^0.65.0", + "@opentelemetry/instrumentation-host-metrics": "^0.2.0", + "@opentelemetry/instrumentation-http": "^0.219.0", + "@opentelemetry/instrumentation-ioredis": "^0.67.0", + "@opentelemetry/instrumentation-kafkajs": "^0.28.0", + "@opentelemetry/instrumentation-knex": "^0.63.0", + "@opentelemetry/instrumentation-koa": "^0.67.0", + "@opentelemetry/instrumentation-lru-memoizer": "^0.63.0", + "@opentelemetry/instrumentation-memcached": "^0.62.0", + "@opentelemetry/instrumentation-mongodb": "^0.72.0", + "@opentelemetry/instrumentation-mongoose": "^0.65.0", + "@opentelemetry/instrumentation-mysql": "^0.65.0", + "@opentelemetry/instrumentation-mysql2": "^0.65.0", + "@opentelemetry/instrumentation-nestjs-core": "^0.65.0", + "@opentelemetry/instrumentation-net": "^0.63.0", + "@opentelemetry/instrumentation-openai": "^0.17.0", + "@opentelemetry/instrumentation-oracledb": "^0.44.0", + "@opentelemetry/instrumentation-pg": "^0.71.0", + "@opentelemetry/instrumentation-pino": "^0.65.0", + "@opentelemetry/instrumentation-redis": "^0.67.0", + "@opentelemetry/instrumentation-restify": "^0.64.0", + "@opentelemetry/instrumentation-router": "^0.63.0", + "@opentelemetry/instrumentation-runtime-node": "^0.32.0", + "@opentelemetry/instrumentation-socket.io": "^0.66.0", + "@opentelemetry/instrumentation-tedious": "^0.38.0", + "@opentelemetry/instrumentation-undici": "^0.29.0", + "@opentelemetry/instrumentation-winston": "^0.63.0", + "@opentelemetry/resource-detector-alibaba-cloud": "^0.34.0", + "@opentelemetry/resource-detector-aws": "^2.19.0", + "@opentelemetry/resource-detector-azure": "^0.27.0", + "@opentelemetry/resource-detector-container": "^0.8.10", + "@opentelemetry/resource-detector-gcp": "^0.54.0", "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/sdk-node": "^0.218.0" + "@opentelemetry/sdk-node": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -786,13 +804,13 @@ } }, "node_modules/@opentelemetry/configuration": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/configuration/-/configuration-0.218.0.tgz", - "integrity": "sha512-W8wIz7H2R1pufR5jfjb3gU2XkMpm2x/7b1RJcsuzvd70Il/rWWE+g5/Od7hQKrxRTSrTrOWlru101PWXz5I1EQ==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/configuration/-/configuration-0.219.0.tgz", + "integrity": "sha512-wXZUYv4ngu43nA4WEhuXNacm46LW+17LRM8nKyIhBzroRA24PBYjMnakwzR/w777nFUB5xlgsYTTeuXxumZM1Q==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", + "@opentelemetry/core": "2.8.0", "yaml": "^2.0.0" }, "engines": { @@ -803,9 +821,9 @@ } }, "node_modules/@opentelemetry/context-async-hooks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.1.tgz", - "integrity": "sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.8.0.tgz", + "integrity": "sha512-/3FIraneMcng67SUJCxvyInk/oxzwsxyadufk0wwfOBLf5wqtAGX4MoQASwSbndBPeARzBryUM9Azr5kHIdWLw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -816,13 +834,13 @@ } }, "node_modules/@opentelemetry/context-zone": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-zone/-/context-zone-2.7.1.tgz", - "integrity": "sha512-B42kO3zIMVbJ+wj5nlSkDvLF8cJY+7wDKLomHp10GL00nvUnhY67UQ/soZQgKR4dvPf8zTKbcONDsOiJLyRuXw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-zone/-/context-zone-2.8.0.tgz", + "integrity": "sha512-ddfwDmm6zVVf3J7+ik1SQRRv6Xrn/YpWxuoXvk4vhJK8LKUt8oqFMuofiDY5RbEleOahWfQnsI69uBEWmm00Nw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/context-zone-peer-dep": "2.7.1", + "@opentelemetry/context-zone-peer-dep": "2.8.0", "zone.js": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^0.14.0 || ^0.15.0 || ^0.16.0" }, "engines": { @@ -830,9 +848,9 @@ } }, "node_modules/@opentelemetry/context-zone-peer-dep": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-zone-peer-dep/-/context-zone-peer-dep-2.7.1.tgz", - "integrity": "sha512-QPLvl82Ds+W9Tjz0s4b8UDUK9YkCb3pvaur4JQdgHe+eph6Ii20NbiC+wsdnBtG17DTPhmZcFvWMcQXZFBgeVw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-zone-peer-dep/-/context-zone-peer-dep-2.8.0.tgz", + "integrity": "sha512-SnaZDuBMYJlsDsgVeZ2IgFseAEXHBkYEn3nCon9YR3L2zdP/UpxZVWwbCWu2HOELmV1jy3RWmk2FusFpSrfh5Q==", "dev": true, "license": "Apache-2.0", "engines": { @@ -844,9 +862,9 @@ } }, "node_modules/@opentelemetry/core": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.1.tgz", - "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.8.0.tgz", + "integrity": "sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -860,18 +878,18 @@ } }, "node_modules/@opentelemetry/exporter-logs-otlp-grpc": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.218.0.tgz", - "integrity": "sha512-hoxrNH1l/Xy6F9WTJ5IK+6j1r9nQFlPOmrnTlhYHTySdunfXLmUCPv3bQtKYntxag9h3wLYBZQ2HI6FOx+BT2g==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.219.0.tgz", + "integrity": "sha512-7SvzDCIclHWAcCwZ1MTOLcwn4BVNPGI3QxS/DJraPNe1TTL+4TvUBq5zeQV8tsnYvtDN7wKW2qocVmaCP2l7sQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@grpc/grpc-js": "^1.14.3", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0", - "@opentelemetry/sdk-logs": "0.218.0" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0", + "@opentelemetry/sdk-logs": "0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -881,17 +899,17 @@ } }, "node_modules/@opentelemetry/exporter-logs-otlp-http": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.218.0.tgz", - "integrity": "sha512-Qx+4rpVHzgg89dawcWRHyt+XRXeLnhFz/qBtvggmjkcgPUdr+NAB0/u/eIPA8yAeJV0J80Vz43JZCh/XFvZFGw==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.219.0.tgz", + "integrity": "sha512-mhl2HL6GmZI8b8PwPfqMws/5ovJfbRTxwc9Y5agVVHiQ+e5SL1btsFr/kJDgt7YCexDtsUn5HAreHQO9szFS0A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.218.0", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0", - "@opentelemetry/sdk-logs": "0.218.0" + "@opentelemetry/api-logs": "0.219.0", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0", + "@opentelemetry/sdk-logs": "0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -901,19 +919,19 @@ } }, "node_modules/@opentelemetry/exporter-logs-otlp-proto": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.218.0.tgz", - "integrity": "sha512-1/noQNsp9gXD75HPzgjBrcF1+XTtry7pFAUfxVEJgg7mPv2AawKQuYkhMmJ8qjxz4Ubc3Y8bwvfxevXsKTq4cg==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.219.0.tgz", + "integrity": "sha512-Ayw4Gf71PS9jhBVaYywa4WsajnqfDehMkTdVH3TSAVHqPcsAv/AhH/wTNRYNt99szeYr6Gbd/D6RjZD77wAxHg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.218.0", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-logs": "0.218.0", - "@opentelemetry/sdk-trace-base": "2.7.1" + "@opentelemetry/api-logs": "0.219.0", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-logs": "0.219.0", + "@opentelemetry/sdk-trace-base": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -923,20 +941,20 @@ } }, "node_modules/@opentelemetry/exporter-metrics-otlp-grpc": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.218.0.tgz", - "integrity": "sha512-YapQ9vNMX0NSZF6LK5pWAFfjpJleV2O9uYWfYGeb/5F1Kb9rPGK8tZDMJFa/sOksgdFuflDvYuA0B4qjDB4fjQ==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.219.0.tgz", + "integrity": "sha512-6LaaSrPxK5L55bXevWajvOMxGOpNm0n12tG53TeZaUeNzXwLPg6d2KCC1zAlGsojan+xRG71mA4Qqs9K2VVrKQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@grpc/grpc-js": "^1.14.3", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/exporter-metrics-otlp-http": "0.218.0", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-metrics": "2.7.1" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.219.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-metrics": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -946,17 +964,17 @@ } }, "node_modules/@opentelemetry/exporter-metrics-otlp-http": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.218.0.tgz", - "integrity": "sha512-bV7d2OuMpZu2+gAaxUAhzfZ0h3WVZk8ETQUEE3DNSntbTaMpuITjtm8I0rNyHFdm7Ax57K6ty7SgFXlBmOLIvQ==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.219.0.tgz", + "integrity": "sha512-6CaDRbMVHZSDWzNXwrR8y/H4B/Z1eMNnkHiPQlTx3Ojz2OHY4X/aff/UC4P/3pHUQSuTfi3oh2UsPPZppw+Vrg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-metrics": "2.7.1" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-metrics": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -966,18 +984,18 @@ } }, "node_modules/@opentelemetry/exporter-metrics-otlp-proto": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.218.0.tgz", - "integrity": "sha512-ubLddKjWULhla9YZRCj/rTBeppjJYE4e9w0icx5mTu3eFhWjQzbV75NYjXuIlEG+NJsBl6d+sTFw5Qu+oej4oQ==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.219.0.tgz", + "integrity": "sha512-DUS7XyIiEnoeccQUvuKy0G2/YqeKhpN8FVIrGbrLNIVMj10yeIFLRzRv0tibCI2kXXvlTTABVexGAk78wHk2ug==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/exporter-metrics-otlp-http": "0.218.0", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-metrics": "2.7.1" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.219.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-metrics": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -987,15 +1005,15 @@ } }, "node_modules/@opentelemetry/exporter-prometheus": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.218.0.tgz", - "integrity": "sha512-RT5oEyu1kddZJ1vt7/BUo5wV+P7hpNAESsR3dUd3+8deHuX7gWNoCOZn+SfDT+hJHlIJ5h/AxiCLXIrutswDJg==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.219.0.tgz", + "integrity": "sha512-TxOnJ85eWJY5JyOJsNMXiRTYlkDcOv0u3KbXEzWCc+tUS9sjL/BC6BcdxZ0B9r2OFVqsrZFXUzSD2sZUy42Ucw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-metrics": "2.7.1", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-metrics": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -1006,19 +1024,19 @@ } }, "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.218.0.tgz", - "integrity": "sha512-3fXxVQEj9TNAFaCi79JeFKfeLd0sDtInaR3gaZDVlzNSPHtz8PZuCV34JKWjD4XXzT20IdMe8IpX6mRVNDA4Tw==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.219.0.tgz", + "integrity": "sha512-BkDNv1UD6BscW19MxbAxVmSYSSFuyeqR6buV2/HTYqA7GrR0EbTFzqG6h86T3PtXmpdbsWjMGLDdjG2rikG27Q==", "dev": true, "license": "Apache-2.0", "dependencies": { "@grpc/grpc-js": "^1.14.3", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-trace-base": "2.7.1" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-trace-base": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1028,17 +1046,17 @@ } }, "node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.218.0.tgz", - "integrity": "sha512-8dqezsmPhtKitIK/eTipZhYl9EX2/gNQ5zUMhaz3uxEURwfkNf8IPvo6yNfrzbxdtpAOybS/+h7wmIWYqFSpiw==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.219.0.tgz", + "integrity": "sha512-9t6SvBXXBEjOBcIzgozvBbd3jWrv3Gt3ngGhl1fhdZ/zRc7oZDVOFEqbi2zlBpW9BXhgDMKv422J0DL/3iQWfw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-trace-base": "2.7.1" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-trace-base": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1048,17 +1066,17 @@ } }, "node_modules/@opentelemetry/exporter-trace-otlp-proto": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.218.0.tgz", - "integrity": "sha512-r1Msf8SNLRmwh9J6XQ5uh82D7CdDWMNHnPB7LAVHjzut0TkSeKc5KcIvr4SvHvfk/xwN5gxC+VLKQ1k0o8PSPw==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.219.0.tgz", + "integrity": "sha512-lF/LUBfhOFmxJa+SQsLN7ziV4MHa2pyKgOM6JNehSOfU+npjM4gwm9oIKEJrzrWcexMcqydiyoFy0XCb1Ql3wQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-trace-base": "2.7.1" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-trace-base": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1068,15 +1086,15 @@ } }, "node_modules/@opentelemetry/exporter-zipkin": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.7.1.tgz", - "integrity": "sha512-mfsD9bKAxcKrh5+y08TPodvClBO0CznBE3p79YAGnO81WI4LrdsGA65T53e4iTSbCalW4WaUpkbeJcbpyIUHfg==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.8.0.tgz", + "integrity": "sha512-Mj84UkEa17BK2o903VTXW3wM8CrSZexGs4tRGVZVIMM9ni1T6TuGx5IrRfoWKAbshx42D5/kc7YV+axypLPYyA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-trace-base": "2.7.1", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-trace-base": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -1087,13 +1105,13 @@ } }, "node_modules/@opentelemetry/instrumentation": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.218.0.tgz", - "integrity": "sha512-mIZil8Es+sYDK5m+DQiwAwF57F14TF2YlEqvIjZ/RQWcxDBwRGsKfdK2Tv65OU9meQKCMzSIFS9mxAcnAb6Bkg==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.219.0.tgz", + "integrity": "sha512-X5t7I8GyIO9rmGHwoedZLREpQqrF1WW2nxzNNym6HOKpFiE+rvqV3ngC0xcZVO2YwIGf3KKmRdWrYwdwz3H9RQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.218.0", + "@opentelemetry/api-logs": "0.219.0", "import-in-the-middle": "^3.0.0", "require-in-the-middle": "^8.0.0" }, @@ -1105,14 +1123,14 @@ } }, "node_modules/@opentelemetry/instrumentation-amqplib": { - "version": "0.65.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.65.0.tgz", - "integrity": "sha512-fF7fNHA59n3y23ROfst2EbSxmP+L3E+snZO6aMU4w4xD84mfejAivspIAsqa9arX5HZlBK6dslHz5dWGNp5D0A==", + "version": "0.66.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.66.0.tgz", + "integrity": "sha512-lyJgobzP0Ce+tRGOkdnrb60apfqU89xB9FeMTmo1TJU007KTMLiLFd4iCfTiBEXzBsVplx7kwrVN4FqGBUcD2Q==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.33.0" }, "engines": { @@ -1123,13 +1141,14 @@ } }, "node_modules/@opentelemetry/instrumentation-aws-lambda": { - "version": "0.70.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.70.0.tgz", - "integrity": "sha512-HT74cQxi/iiVEz5dRdNdfGCFzPFbkxSiwHfFPHDwkRcr1JKQqI6hm8qeXEvEiJ+36xIU1KkQMDfeThJ1ifnUiA==", + "version": "0.71.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.71.0.tgz", + "integrity": "sha512-9Sv6flQDeNNF6ZbiLgn+NYJa220yRZdDSIdgDZsqNubpDnYAPF33OHcQDlE8mFiaOq14mngoPS48JnYc8JT+Ug==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", + "@opentelemetry/propagator-aws-xray": "^2.1.4", "@opentelemetry/semantic-conventions": "^1.27.0", "@types/aws-lambda": "^8.10.155" }, @@ -1141,14 +1160,14 @@ } }, "node_modules/@opentelemetry/instrumentation-aws-sdk": { - "version": "0.73.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.73.0.tgz", - "integrity": "sha512-0INPkHbR6o4J3psE+ncwWaE7qtDpb2p+i+qfV82cfwYLCXavYCGosBZ/S4pOErDVJYIyQVIsNAHhaUgaL313SQ==", + "version": "0.74.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.74.0.tgz", + "integrity": "sha512-EMLUGgx2wJSXdwMEFdwd3IaW+mkUF8PENdzDFQ1FRdztzMG1d1XN76ORIjAMsXcKQISlRRcz93AWPQeBPn4EKA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.34.0" }, "engines": { @@ -1159,14 +1178,14 @@ } }, "node_modules/@opentelemetry/instrumentation-bunyan": { - "version": "0.63.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.63.0.tgz", - "integrity": "sha512-z0xPSZ62d3I7sG2sUTyQ5/ES1RdESP2eOETiMLY9gPSp+HZwbsAyj7T/2sdZKYD+O2ajRHZEil+DBoUolf1ocQ==", + "version": "0.64.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.64.0.tgz", + "integrity": "sha512-jrRNFvpREutmpoWhk1T8n9q/RYdxbViXwSUPHN8yQR1bzgtwfOl/y8G/p8Xfudlky9GGsqw5WRc6q6QrfgF3pw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "^0.218.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/api-logs": "^0.219.0", + "@opentelemetry/instrumentation": "^0.219.0", "@types/bunyan": "1.8.11" }, "engines": { @@ -1177,13 +1196,13 @@ } }, "node_modules/@opentelemetry/instrumentation-cassandra-driver": { - "version": "0.63.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.63.0.tgz", - "integrity": "sha512-jnVTOr3h/46UDalEwJ4ITux8UWwHmnsOik5WFs3JB/UrUj8Wad5eI+KpOEBuOUeOfPB9sce11qgVw3WXU2r+hg==", + "version": "0.64.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.64.0.tgz", + "integrity": "sha512-KN+iOsmPI0nkX2lfgNgHBrHNaDuxDwIbwFrlvyrZ4bAT8bTKcCOXhne70O9qihM8+T1F4tjvPXpCfhKZbmsYiw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.37.0" }, "engines": { @@ -1194,14 +1213,14 @@ } }, "node_modules/@opentelemetry/instrumentation-connect": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.61.0.tgz", - "integrity": "sha512-ZTQ0W3Lb7GJsOd+72cG8FJQKA5DqYfELJGLmChrJIezRSLfJIfofwKEGLX5rMtFJmwckpichQkBZWjid5dvnVQ==", + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.62.0.tgz", + "integrity": "sha512-ZGV2sOyeffqMiqoh4RpsPTs/TUI5cCS+cEWvC9wUfvaEekR5omR6P/ClG+QDwasGBlKx2zfFPjSYPpzUo81XAw==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.27.0", "@types/connect": "3.4.38" }, @@ -1213,13 +1232,13 @@ } }, "node_modules/@opentelemetry/instrumentation-cucumber": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.34.0.tgz", - "integrity": "sha512-VK63Cm8osAdsSZpULPk+qnNktQUJzmnIOv2wuh79fV41WuTM38uOFC3s978/24pDkSljhN4EYCbPRLrAhXfKSA==", + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.35.0.tgz", + "integrity": "sha512-H9NsbcFiVOFOcOu40+VOOjxdTeonu0VHI3mte5ie5ka/bazzIPGncQoHpL6su53C3/sgMdKjE6ZuwsB7Y8gQpA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.27.0" }, "engines": { @@ -1230,13 +1249,13 @@ } }, "node_modules/@opentelemetry/instrumentation-dataloader": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.35.0.tgz", - "integrity": "sha512-6x6UPP0tLzrdj15PIEN3qgp/WCcESCavHJfkIKoyLmy4UjGLF1KgEUMyD74xhbKGo426uvMbhvCgZC0ye8nO/A==", + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.36.0.tgz", + "integrity": "sha512-gE0mTk+EnVaBN0mPRM1V6FqzQ9VckTp6ZFIssU5hxy+e3sqspYILBhV/0IHZ33qxGa3B9buLVZnuzVjUISfyoQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1246,13 +1265,13 @@ } }, "node_modules/@opentelemetry/instrumentation-dns": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.61.0.tgz", - "integrity": "sha512-5D8xFaw9GXq9ZIOAvG7NPDivFfZWFAekLGFn1B7ppyhuAYBVHGybFpx4Q9BV1Uup3yzCdiD78KhyH7c3dKOYSw==", + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.62.0.tgz", + "integrity": "sha512-6v0X8wEqhIyv2b7MXhmipyCitJfm0vnF5mLBTWXojovoHp7P1EpN5sb12LgdhVlozhGwRZdzb6OvKUVsxKMD8g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1262,14 +1281,14 @@ } }, "node_modules/@opentelemetry/instrumentation-document-load": { - "version": "0.63.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-document-load/-/instrumentation-document-load-0.63.0.tgz", - "integrity": "sha512-eVQ2IcDeWFMLgnmeVGvgGSMIdomrEat56fDfA9jXYExgr/1xClO0MpHKDDfInGV2o6STtzarcrsBgwrnV8cm7w==", + "version": "0.64.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-document-load/-/instrumentation-document-load-0.64.0.tgz", + "integrity": "sha512-I0fTRpfgY7Qr8qaTJBPgDi+Eo4YjOqHSm3OB9U5JaJmCfm0ryDGFMKef8OBS+DeDqYZvaHWyq/zg7YJqnCWaoA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/sdk-trace-web": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.23.0" }, @@ -1281,14 +1300,14 @@ } }, "node_modules/@opentelemetry/instrumentation-express": { - "version": "0.66.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.66.0.tgz", - "integrity": "sha512-G1xTh5M5shklMgIyUXWDjU2BakulKtcISaM4U5TyanvO7R4xbB3iC7YQ8QKegLXaOs81Ku8RlcIcbYRrz/82wQ==", + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.67.0.tgz", + "integrity": "sha512-1WTWX2YNZIV+jPmEqdf/Vd1gHMT92TKA/0pf/iIItWhV6+RhzhnUUW4kSWQn8L3qVcgWEzQ860/ZOwaIwayi8A==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.27.0" }, "engines": { @@ -1299,15 +1318,15 @@ } }, "node_modules/@opentelemetry/instrumentation-fetch": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fetch/-/instrumentation-fetch-0.218.0.tgz", - "integrity": "sha512-eP/Y5hDupb+6MwZSaMw4ZdsDz8YgfJbJ4Ta86BMVeOmI2EArwXcd0v1nfNIvUzXTPi7nakidwqeuUa3FwRwECg==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fetch/-/instrumentation-fetch-0.219.0.tgz", + "integrity": "sha512-nhjrhJ/tlE+1I1950dJkcl0xCGf7IrZGwWHS0X5J4gZtqP4YD+qp/gVfXkzZZBjFDx+39IaDQLS296E+Pcw5Tw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/instrumentation": "0.218.0", - "@opentelemetry/sdk-trace-web": "2.7.1", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/instrumentation": "0.219.0", + "@opentelemetry/sdk-trace-web": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -1318,14 +1337,14 @@ } }, "node_modules/@opentelemetry/instrumentation-fs": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.37.0.tgz", - "integrity": "sha512-5mxhFuwAK0FFvisUdvuywaZ9ySMZ15HfbN6IpLn0gwRh9s1/QBcpLznQ/A15cZs1QFtBJ+JXIHdwY7WOD0c4Eg==", + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.38.0.tgz", + "integrity": "sha512-6OBofWODg0RcPkl3bA+7yPf0e4Vi3O7ZxlFGY5QHPMMLxWVMnjWPEXQ2NlLBk19Sr8LcvEyyZOStdLJrT5o2dQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1335,13 +1354,13 @@ } }, "node_modules/@opentelemetry/instrumentation-generic-pool": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.61.0.tgz", - "integrity": "sha512-tvp5PWnGRPHY/kz9Kg1IRLBL0qUAxMSNG623f+ZGEsvnCVEjr3tFyw1JGQzM+B3eZKkO+Dp/LYrtOSfb69D5lA==", + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.62.0.tgz", + "integrity": "sha512-IhO2y/MaK1oZ4EbUgdkSVT+XViPq86IAz4lwPe9jaba00M2yDWs8+f9xjcH3tK5IC3dZuAxXmifGmfvuJp92jw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1351,13 +1370,13 @@ } }, "node_modules/@opentelemetry/instrumentation-graphql": { - "version": "0.66.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.66.0.tgz", - "integrity": "sha512-D4PN1tStj6rnOdofnt2xINJjtT1k2ockzaODrn76VEBZeqJ3QsEvKFfunB0EFAohO4xswVp14VAVmKNnGzA1Dw==", + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.67.0.tgz", + "integrity": "sha512-NMUmuhtYvv3AwkK4zsHQbTCXS81QS63hbNZRKfXc7W8f4KbWeKLmqKqvnfjUcqZoGS0eAw2kNKNYcbtbQ7baAg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1367,13 +1386,13 @@ } }, "node_modules/@opentelemetry/instrumentation-grpc": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.218.0.tgz", - "integrity": "sha512-kcDCNrC7IWNXEKQriGrwuh5jjbMFU5exOQzU9ufEY9UkACNcgYIdOd7XpX3IqZ3UPSnZyZtlwgfsbC5SNlEDbA==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.219.0.tgz", + "integrity": "sha512-GyW1Kfbf7uiJXeBZovB/uXPUdkaZYWzB2ZPCdY2CU7+6V207u8wlCM+zVd3UwhEjOBrMbZAGq+m38aBEI/EVtA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "0.218.0", + "@opentelemetry/instrumentation": "0.219.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -1384,14 +1403,14 @@ } }, "node_modules/@opentelemetry/instrumentation-hapi": { - "version": "0.64.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.64.0.tgz", - "integrity": "sha512-PCHgCICCDz7p9BgCU9gQz2smbqu4V4P8QtWJ7DLjL3bmzSdrgy6EGvecDg1YuhjBsoN08SR+y36hgdHkqCgrzQ==", + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.65.0.tgz", + "integrity": "sha512-Whhas9iU0SfK/7XBcgCwfW5c9AaxjxtZpzW21t3Ml8XZ6Irc3hF36JDolMmFa7nUjML9n9bSUAZjwCgrK+2UdQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.27.0" }, "engines": { @@ -1401,15 +1420,32 @@ "@opentelemetry/api": "^1.3.0" } }, + "node_modules/@opentelemetry/instrumentation-host-metrics": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-host-metrics/-/instrumentation-host-metrics-0.2.0.tgz", + "integrity": "sha512-NIttCEOLdg1ebbDiJpCf0Ly1OGIa10isesik+K2dnXy2P99q4muUFjpaLtTnhkENrt9SmR0Zrxzq7B+W/VNWyw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.219.0", + "systeminformation": "^5.31.6" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, "node_modules/@opentelemetry/instrumentation-http": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.218.0.tgz", - "integrity": "sha512-x9djaqdzpT8WAboep1H9nCAQ1E+MMsm08TNfA02TqM3bNNddZeiim+E3KMWVQFaX6JpUy7V0nm/wfN/K2Em+Zw==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.219.0.tgz", + "integrity": "sha512-nNt1fqpyah/OKjNHdEOu8xLwISppRU2qJuF8aR+fCcftVwdFkPgtworBLA+TI1HU2iF508jcQBF2gerWczJAXg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/instrumentation": "0.218.0", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/instrumentation": "0.219.0", "@opentelemetry/semantic-conventions": "^1.29.0", "forwarded-parse": "2.1.2" }, @@ -1421,13 +1457,13 @@ } }, "node_modules/@opentelemetry/instrumentation-ioredis": { - "version": "0.66.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.66.0.tgz", - "integrity": "sha512-UfTAcaBKCzLUZ9opvfOLV4bH46XiNFqUsKykfPCIefDIxJ1iUYtMOucNaiZ+/kjQdPy5i6Ef5tk2IAjxol4X1w==", + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.67.0.tgz", + "integrity": "sha512-dv64vQ4aXbJvRMMAFrMUSzDeJrNv/uQMLjfaav4LHAOar7Xn08W3pkoYoYEnzq/n2+fGgG96rp9S0gQ+VnLDiw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/redis-common": "^0.38.3", "@opentelemetry/semantic-conventions": "^1.33.0" }, @@ -1439,13 +1475,13 @@ } }, "node_modules/@opentelemetry/instrumentation-kafkajs": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.27.0.tgz", - "integrity": "sha512-kl/C2AU4KZGHlMZD12nMFXcMjxSHvu5Q0UPSQ6IJeBfCadYuWgW+sWIa2JZVK/A0qRYm2cncekJyeBHQDyfUUg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.28.0.tgz", + "integrity": "sha512-dztkg70nJds3Uc0Xo3NFlRqL5iYgGYWh8myuuGfRC6NnXJchY0Kw9QnBjTZxBSldXU+P6nv2snDVMmlxuy6fEw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.30.0" }, "engines": { @@ -1456,13 +1492,13 @@ } }, "node_modules/@opentelemetry/instrumentation-knex": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.62.0.tgz", - "integrity": "sha512-XgfhCAWwSqA0YnwaEKdpvQMavc90D3R65frhLCO9JNl867EulNps9tm6pjGIg+GiYuewn00gEzW4HQ5btgYxGQ==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.63.0.tgz", + "integrity": "sha512-XrpRahI/9vTrfSUfkhy8jGX8KMRKecQIPU9GyEZ8gkR030iJwQYsMmKGO5TK9R80cQGUopXwDvV55zmVNEkcPg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.33.1" }, "engines": { @@ -1473,14 +1509,14 @@ } }, "node_modules/@opentelemetry/instrumentation-koa": { - "version": "0.66.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.66.0.tgz", - "integrity": "sha512-04x/z21WTMEfy3lUSr4aTj8WsTN3OZF901hJ+ciOwdwf7AK8UJTpZCXw6KQ3G4Vag56q1HoMihCONeWZLeld1g==", + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.67.0.tgz", + "integrity": "sha512-QOGY4mjqvF85LDcrzwrQXMcsu1wMTALeL1OHyTkLpN/7cnoDtv0W/qMBjHVq4IKYK6yDH4ZDNdwlonJPhwCGcw==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.36.0" }, "engines": { @@ -1491,13 +1527,13 @@ } }, "node_modules/@opentelemetry/instrumentation-lru-memoizer": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.62.0.tgz", - "integrity": "sha512-AlGKIdk6ZT7WmIozfUb2LjOcI3AhQrvAXKX0zi1cVcnw2QlRbVYyV5GTa2Th9ebuczVfWPaoPrmZw61zCp/czw==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.63.0.tgz", + "integrity": "sha512-DlZRNXfiosmREoLbEGbYuxF70cYXjrYqoaO1sJE167i1+ARWXTq0YMPJ97i53Ws/xkZWllJNYU4mpY2LM2yTlA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1507,13 +1543,13 @@ } }, "node_modules/@opentelemetry/instrumentation-memcached": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.61.0.tgz", - "integrity": "sha512-qiCR9Wovf5AHzn6g+LXhvwMmv2I6zhHz2I2tEHZMmBuD8c18bkJzGFxHoSBlxdApRT+SW13r9472dDMm4BRjgQ==", + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.62.0.tgz", + "integrity": "sha512-kAajd/MtdRBh9PCrMM4fnusFRNPJDU1dv5w9cgnKtMfutRE6K03wBbGSeT3FD1M56sMYWVqPhiKUhfSZCMZrLg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.33.0", "@types/memcached": "^2.2.6" }, @@ -1525,13 +1561,13 @@ } }, "node_modules/@opentelemetry/instrumentation-mongodb": { - "version": "0.71.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.71.0.tgz", - "integrity": "sha512-6rwfVjAUY69CKkyGqzL+F5X7Nzw0+Ke9pOxk9xUPJpy8vracZxuQYF7rWu02sV1xOgi4u52449SuVhD+zaSiIA==", + "version": "0.72.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.72.0.tgz", + "integrity": "sha512-WYgGzvlHzdoxHlrhysYtjxE4RC23j/iFZ66hdMJuAoczOWoD/xb6LhRwaz4CM+LKyKtcSIadAjSUyGv2B+SNwg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.33.0" }, "engines": { @@ -1542,14 +1578,14 @@ } }, "node_modules/@opentelemetry/instrumentation-mongoose": { - "version": "0.64.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.64.0.tgz", - "integrity": "sha512-iCIqeUaERN8Uc5Rrtg4zvQ6d7z5JQ5iUmbnr/JHYPxAidDowmRc8/wDMJeMKRfLPTj336Zu0ec7rH/ak/4N9vw==", + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.65.0.tgz", + "integrity": "sha512-P0iT4oKuinEFZlTIKPJC5hhnmiV9De9lEiLkGzSwnNLdkyHIWug8BfRp5ZROrYAQ9mm47H+WLB/ozvUvgzEvEA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.33.0" }, "engines": { @@ -1560,13 +1596,13 @@ } }, "node_modules/@opentelemetry/instrumentation-mysql": { - "version": "0.64.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.64.0.tgz", - "integrity": "sha512-W1w76AJkP7i0uzzAe7nsCMWq4+EMSA550f1lAmxDPdQC5FnreNbRIm/tod2OS9gVrYvRrQXNkFmZJKGo4kzCnw==", + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.65.0.tgz", + "integrity": "sha512-sh1wRjFaTt+8DOhJ0134rFtJoHVUXKI8faIWTbj4zZNw847dzUgmkO8xOluJ9Css0JzT4vCeZofJmq9mQmmESA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.33.0", "@types/mysql": "2.15.27" }, @@ -1578,15 +1614,15 @@ } }, "node_modules/@opentelemetry/instrumentation-mysql2": { - "version": "0.64.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.64.0.tgz", - "integrity": "sha512-yTu0mYh/qJPSE86VmNLQww5uugDyvCS2KJIPfPtIk2ufoEUoHPsV6Iynnvmz588Moq04aBLxfTa/EtE4A2ykWA==", + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.65.0.tgz", + "integrity": "sha512-Om6BJ/bmFBzNkGbAzj/UV5sCKX6jCGzhTl1Gqgtim/O0dnPE7F2zN65u16Fq3JgyypGAwT2iwh13tYdWkc8/RA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.33.0", - "@opentelemetry/sql-common": "^0.41.2" + "@opentelemetry/sql-common": "^0.42.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1596,13 +1632,13 @@ } }, "node_modules/@opentelemetry/instrumentation-nestjs-core": { - "version": "0.64.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.64.0.tgz", - "integrity": "sha512-PW1ArxryMwF8/IXq1nzlQs7tmr/fWd1tf71AHevZT3Fm0hW7jRX9JEfYgIAcKDvmbqcJEr5K1224NEimrRPbuQ==", + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.65.0.tgz", + "integrity": "sha512-/q8fN2M2zGl+gQRaF79dzqvyvVqHAI11c7xAQZy9W1eAtQScNwaQtPm0EUo5+aOgakaTksBrsiHUF0rQS24NsQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.30.0" }, "engines": { @@ -1613,13 +1649,13 @@ } }, "node_modules/@opentelemetry/instrumentation-net": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-net/-/instrumentation-net-0.62.0.tgz", - "integrity": "sha512-Gt2kzpACpmIad+q3LQqe8UNHuoVvdLuFpB6SN/A6xLPKNllb+ksPUYQhj1kXdZOpcFZNGKDXHyN+TUCVCk1TRw==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-net/-/instrumentation-net-0.63.0.tgz", + "integrity": "sha512-fvmVdL4SlsYZf74mq6iLBPd6JJHRAe5utzN7Wt9e4nwa2S3pgExA9poOEmBL1CvIR47MceTA/A8vgVCF23ebbw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.33.0" }, "engines": { @@ -1630,14 +1666,14 @@ } }, "node_modules/@opentelemetry/instrumentation-openai": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-openai/-/instrumentation-openai-0.16.0.tgz", - "integrity": "sha512-I0KKybyqqFOxSBgYKQNdR/EF3LvzSaAUT7Y75xkjbgscY+V8UWDpUbY68POLhUC3SKMlGvZmrTSxcQ+Y0vRhNw==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-openai/-/instrumentation-openai-0.17.0.tgz", + "integrity": "sha512-X3aEZnzj7SJkn1nmqEoD9IljmqENnGrd0vcJngcEApT8uqhFaeimONqKeIzKYvUgC7k4OkAUxC7yfXzxIK1KlA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "^0.218.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/api-logs": "^0.219.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.36.0" }, "engines": { @@ -1648,13 +1684,13 @@ } }, "node_modules/@opentelemetry/instrumentation-oracledb": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-oracledb/-/instrumentation-oracledb-0.43.0.tgz", - "integrity": "sha512-7Z4kOOdnrHX4S5gCeWhnnpWQwEd7weRjDhJA1nSrwTYtAcVWNjk5wsMKHBCTDCN0uJtA9T6PouZ+AKRYiS1Rrg==", + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-oracledb/-/instrumentation-oracledb-0.44.0.tgz", + "integrity": "sha512-ncEfP4rzuZXBHJJtzWLYctK4Pq/FvZRiASxlFY9CJG9kGjaFTfzBUys0NiP27alYPvpjj0uDAMheDk9nihO8ZA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.34.0", "@types/oracledb": "6.5.2" }, @@ -1666,16 +1702,16 @@ } }, "node_modules/@opentelemetry/instrumentation-pg": { - "version": "0.70.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.70.0.tgz", - "integrity": "sha512-g8WXwwOUXfjiEmATwjB/33QKE2AkIpNe4KIuJJh4djtXgCL0Wne+AzAfjuDIAspGvO1txQp8ibKsLd3SBmcvJA==", + "version": "0.71.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.71.0.tgz", + "integrity": "sha512-jAhfyZeOkEKh3cQ5nm1tNWqHg7HFARyAe+p4BSoDHnB79c1woyEvDKqS11Hj/DjtceP+vrurIfcDs7Fqiy11mQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.34.0", - "@opentelemetry/sql-common": "^0.41.2", + "@opentelemetry/sql-common": "^0.42.0", "@types/pg": "8.15.6", "@types/pg-pool": "2.0.7" }, @@ -1687,15 +1723,15 @@ } }, "node_modules/@opentelemetry/instrumentation-pino": { - "version": "0.64.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.64.0.tgz", - "integrity": "sha512-+vDL7tZMZjkp8BpYMx/cL2/HWGsNUqKcRmAIIEaQu/6F44oM6xGDMCSqMKHdKCsH1+WW52EYdHbWkVGTF0KVsQ==", + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.65.0.tgz", + "integrity": "sha512-p6eh+NRmzi1F+/4QG7XDqRk4ICdCNTsM5vdcwUPnpMie2MddgY1/ENmWvCF9r0Kh6QQRA2kkpnhoJFaiRQ5kVw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "^0.218.0", + "@opentelemetry/api-logs": "^0.219.0", "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1705,13 +1741,13 @@ } }, "node_modules/@opentelemetry/instrumentation-redis": { - "version": "0.66.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.66.0.tgz", - "integrity": "sha512-bVShkag6vP2VQO0cpA8CHjOohWbKNYLyjiwGkOnSAwou1TPc6pf9DssFUxwqN2XF1J4oqP0LVSvN9kZUzMecfA==", + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.67.0.tgz", + "integrity": "sha512-TBjO4bPvfGH6bRjJJ+KrJhEqpHg3SWCFZ84MqsTWF639RQZmvkMhT2/DJsBAqqkq33IvHoDJysserqAfZN1s+Q==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/redis-common": "^0.38.3", "@opentelemetry/semantic-conventions": "^1.27.0" }, @@ -1723,14 +1759,14 @@ } }, "node_modules/@opentelemetry/instrumentation-restify": { - "version": "0.63.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.63.0.tgz", - "integrity": "sha512-Z73YxZpt0Y56uRu2pRWOjO5wXHvZqF46K4czoKRTGlUifzzFmUZxyOeAAECACuMRSLZmZ394WJin0MDgU9iW9w==", + "version": "0.64.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.64.0.tgz", + "integrity": "sha512-X+gL4KpfPAx7Y07zKQVtyJPckhCcYJdSlEz0Kq0iR5nkQ8/AVWJ05/txl4voZbZdCuNdn+uLZTtJ60bAQwputQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.27.0" }, "engines": { @@ -1741,13 +1777,13 @@ } }, "node_modules/@opentelemetry/instrumentation-router": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-router/-/instrumentation-router-0.62.0.tgz", - "integrity": "sha512-0w8ok7GbXtYvX7TtLp72qQJKNyI7lD72Fy2NsNKIcQAv6TqGox5javFyXrIrCAtZHCONePxeAwAYj1Qd9si9OQ==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-router/-/instrumentation-router-0.63.0.tgz", + "integrity": "sha512-zIpsZSHGvbaqiEazwUm1X0FkPnLXIwZcL/llu/UplkeGNU58bsw70l2uMqNqTb7J+tzsBC09CLVPty5BhW3X9Q==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.27.0" }, "engines": { @@ -1758,15 +1794,15 @@ } }, "node_modules/@opentelemetry/instrumentation-runtime-node": { - "version": "0.31.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-runtime-node/-/instrumentation-runtime-node-0.31.0.tgz", - "integrity": "sha512-HkLsuEfUDahFiL/xFtEqJDMp7sp8ynOtA045bJi9nAH8CrPvljPW5SgJQb2mQqEYJQopbWYZ2lPqQEfj7bYgJg==", + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-runtime-node/-/instrumentation-runtime-node-0.32.0.tgz", + "integrity": "sha512-Jo1jSgrHlah3lPpGNPsIpF0q52D5uSLRJrztWUoPc1/Tli2ZWZ+cArgNtcdmiLuKhW21MwYbbcrNw1fbOPeR3A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "^0.218.0", + "@opentelemetry/api-logs": "^0.219.0", "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1776,13 +1812,13 @@ } }, "node_modules/@opentelemetry/instrumentation-socket.io": { - "version": "0.65.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.65.0.tgz", - "integrity": "sha512-dNvIbD40h0z69stQ9cIeAWRyy5WyQM1a1XnFthekc/oi/ipX4E6oYJBM4X2xKBxjZMTjdV5VshLoNeYMSBsnjw==", + "version": "0.66.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.66.0.tgz", + "integrity": "sha512-XrZmLkFJktVLd3biQiP8BAhupRwPWLHGIiDCfyDAnWI6borIL0wD6BpwFKKPT/etpu4/5OaeAQ7qs/S+FY9nhQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1792,13 +1828,13 @@ } }, "node_modules/@opentelemetry/instrumentation-tedious": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.37.0.tgz", - "integrity": "sha512-cGLF46UsgeI1334atJxLO36yQlV7WXKg35Mp+e2NXo2vOTfIZTVqoKOzExVOTOwT4AQjfGVEDxyq5wXybUYXIA==", + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.38.0.tgz", + "integrity": "sha512-9sRWyIMBHDqJvxRVZ+eQ7jHJ9Iu+DapO27WLZbQF1nyD8xIvEMuDonQ/HnlQiaRdwnqFknXSQTFusJUT3mNVyQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.33.0", "@types/tedious": "^4.0.14" }, @@ -1810,14 +1846,14 @@ } }, "node_modules/@opentelemetry/instrumentation-undici": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.28.0.tgz", - "integrity": "sha512-7nh4Gw7PhYtQm82FIJtWUhx6iZQJj0bdkKe2RQb3XNIyxu0o9rM1J5Xt083SsG2tCbQZpX9/mlDxhTrK1Z/lVQ==", + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.29.0.tgz", + "integrity": "sha512-SnA+0XgGc595jtnwFVfWy7Vgfr5hle4D5YKIlm0U4z8aK9YoCZVUn1xAkVZ2evaJyykiDF50FBzr1XZ0uj8CPA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.218.0", + "@opentelemetry/instrumentation": "^0.219.0", "@opentelemetry/semantic-conventions": "^1.24.0" }, "engines": { @@ -1828,14 +1864,14 @@ } }, "node_modules/@opentelemetry/instrumentation-winston": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.62.0.tgz", - "integrity": "sha512-pr1U9ZV4RRy23qMVrRzebfxwDWjp44xA7sC0PAdeW9v4HDcfOr0ejdTJmIsBGvhkNHPBajfieaIF9b6/9wjErA==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.63.0.tgz", + "integrity": "sha512-NFMHLYODph0rWGfT/QLv75hCsu1sxVAV79L8HduBCMo181jOTSRZHaqxfrvDtFOsvgYBaiUBa7Ga50w47wM3FA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "^0.218.0", - "@opentelemetry/instrumentation": "^0.218.0" + "@opentelemetry/api-logs": "^0.219.0", + "@opentelemetry/instrumentation": "^0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1845,14 +1881,14 @@ } }, "node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.218.0.tgz", - "integrity": "sha512-ZwqpkNL5W7RyGJPDZ9g06DvKp8KFTWPJPN12anpMQYSKpTSU0z3EIZuPq9vPGpS8siFyOqDYDAuCwlNO9FqgbA==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.219.0.tgz", + "integrity": "sha512-zvIxQX/AZUVKDU+hCuYx+7UkiP7GRdnk1ZbFQRYzHvYp47cAWR4j3IhoPhV9KaeXEv2xdGq3IA6PnpzDmLcmSA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/otlp-transformer": "0.218.0" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/otlp-transformer": "0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1862,16 +1898,16 @@ } }, "node_modules/@opentelemetry/otlp-grpc-exporter-base": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.218.0.tgz", - "integrity": "sha512-H/lCGJ536N98VpYJOaWTQOkv4Dx6TnmStK6Rqfu1W7KkFbPAx04hjdYEMZF/YbnHzPUSIK4kM6OE2GKGBTpV9A==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.219.0.tgz", + "integrity": "sha512-iIk/s8QQu39zpTrRRmsW/Eg3SE2+Hg8tLWepr2FLRgmwUpNd0IpCTLJEHJ77hpt4hgIS8MAh44UYI4xQPZwWlw==", "dev": true, "license": "Apache-2.0", "dependencies": { "@grpc/grpc-js": "^1.14.3", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/otlp-transformer": "0.218.0" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-transformer": "0.219.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1881,18 +1917,18 @@ } }, "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.218.0.tgz", - "integrity": "sha512-CFaKH87WAzjuJ4awowTTLzUvMfaRfiOFG5+qm5S5ncyalRtN4ecQ+YmuANJSCrVPuvZFEkUgKhBPBndxi3rHsQ==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.219.0.tgz", + "integrity": "sha512-aaYKAyXhw9VchKZVGOopD3Gw/kPsyrX2c6IQ0AW32mTjqmZOh5Y6Gf5OYqTNqVktAeBjmFinhyFaCwW6GYK9YQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.218.0", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-logs": "0.218.0", - "@opentelemetry/sdk-metrics": "2.7.1", - "@opentelemetry/sdk-trace-base": "2.7.1" + "@opentelemetry/api-logs": "0.219.0", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-logs": "0.219.0", + "@opentelemetry/sdk-metrics": "2.8.0", + "@opentelemetry/sdk-trace-base": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1901,14 +1937,27 @@ "@opentelemetry/api": "^1.3.0" } }, + "node_modules/@opentelemetry/propagator-aws-xray": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-aws-xray/-/propagator-aws-xray-2.2.0.tgz", + "integrity": "sha512-Yjvt2EjL+tfpkVOdKbhTPgpM4SIAez9nG6Q/QjQ3yfcJcjIWp59ph70SLfvmkSL6++3DCnuBG3iWcB18PwWavQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, "node_modules/@opentelemetry/propagator-b3": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-2.7.1.tgz", - "integrity": "sha512-RJid6E2CKyeGfKBzXKF21ejabGMHypFkPAh3qZ+NvI+SGjuIye79t3PmiqcDgtRzdKH6ynXzbfslQ8DfpRUg2A==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-2.8.0.tgz", + "integrity": "sha512-SazlvuSKi5533rPHTW2TwBwdMakhjZST4SYs0YauuvfGDkT13KbG1gJS75hV0uWVeevhtVP9sAIlaZLTHdSbMg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1" + "@opentelemetry/core": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1918,13 +1967,13 @@ } }, "node_modules/@opentelemetry/propagator-jaeger": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.7.1.tgz", - "integrity": "sha512-KMjVBHzP4N60bOzxja76M1F1hZZ43lGPga5ix+mkv9+kk1nx9SbkxSvJsMbuVUxdPQmsPTqGShmhN8ulrMOg6Q==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.8.0.tgz", + "integrity": "sha512-Xnz9zZvvQzUw+9DrOn0MomR7BxFCkA2pcfXBQuHC28ndJpSbjLs7knzYb05kw5SyCjSsEWombkZMgGcJSk8JVg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1" + "@opentelemetry/core": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1944,9 +1993,9 @@ } }, "node_modules/@opentelemetry/resource-detector-alibaba-cloud": { - "version": "0.33.8", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.33.8.tgz", - "integrity": "sha512-RnSB/uxkElny0/WBFEtIG2HRG0cpSNTRdE+YSB7Poa+uljK+ddCacEZYz/PMgZh+cs586XstJQxdyjz0jtcAug==", + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.34.0.tgz", + "integrity": "sha512-hUs4CK7MbRfffw8y5zR4Mo37MJRR3Zt8Ub4rgMkIk7gL8jozjV7k+zwIk9grz5kGAuD406BDDIghaY8090K4Zw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1961,9 +2010,9 @@ } }, "node_modules/@opentelemetry/resource-detector-aws": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-2.18.0.tgz", - "integrity": "sha512-wyMM4UoRuHvI2KjqnTzvyW8Yv7MKRGA+I78Xti6gTEw7hBhqXU1SRo+f9KrsQfeeiOn+TkDuvxavuaAQbD3i6g==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-2.19.0.tgz", + "integrity": "sha512-ELKQCtbc7g2ghbteLftKzXvI3MkIfENrRjAaYd2h9cWNj8g/Dx3oDzpxfcv9mBigtwwWCZwQRr8R//uxREpdrg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1979,9 +2028,9 @@ } }, "node_modules/@opentelemetry/resource-detector-azure": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-azure/-/resource-detector-azure-0.26.0.tgz", - "integrity": "sha512-7KxF7mlwI2nKja/iEdwPqOaS0QAJbhT9ye4DeYZnXdOS/4phfonk5nSmyGDBYhBL7J30MPL91oZNuGYRKXZAXA==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-azure/-/resource-detector-azure-0.27.0.tgz", + "integrity": "sha512-m6HCEmK12QpEcWbKtvGpQtoDVceXtpB14AaaW/t5f6gHeLuGq1QivkuohkvKMkxgAdwIHxEQ8qof3whWBpd8JA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1997,9 +2046,9 @@ } }, "node_modules/@opentelemetry/resource-detector-container": { - "version": "0.8.9", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-container/-/resource-detector-container-0.8.9.tgz", - "integrity": "sha512-Xd2C4HjW9hl75iqZT7tQNy2yRBUqNucq2O9+e0FJRNkbiItInYVMzc0S0KDXcx/vZBwNmlrKS3R0uLCU9ULsGA==", + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-container/-/resource-detector-container-0.8.10.tgz", + "integrity": "sha512-aMU2wG4ktcqy6zEotdbIkkX5ACKRxEZLX1ZlMH0dea0M2+2KfabJc1lHPqAIFaa+CD37fCION55e69QmYwqX4A==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2014,9 +2063,9 @@ } }, "node_modules/@opentelemetry/resource-detector-gcp": { - "version": "0.53.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.53.0.tgz", - "integrity": "sha512-RCV31v23ZwZfYR3LPkuORHTHIOvfm3hZBT7hAzSO0+oAIrG/Dm0ld5tV4lYNO05GjI7sHQdRcbSqzEYAvQcQuw==", + "version": "0.54.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.54.0.tgz", + "integrity": "sha512-u+6sBzQO03QQGFhxjzFa7uNbH6iQpWTcrpWyomxuppH3AN/+1mm3DRVseS1CiRq9VBKrFO0UosWAdD7fWVUrrg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2032,13 +2081,13 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.1.tgz", - "integrity": "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.8.0.tgz", + "integrity": "sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", + "@opentelemetry/core": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -2049,15 +2098,15 @@ } }, "node_modules/@opentelemetry/sdk-logs": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.218.0.tgz", - "integrity": "sha512-QvnNdugatFTVCJXH0Mcu7GOOJSylA9j127kIezOE4YwTI4YbowRons2K4WZTv5FMS8T4q9P0NdaRHdkSmeAIag==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.219.0.tgz", + "integrity": "sha512-s6lTKRakaPClvKoWHRChxnXjDMkM/TQ30ff78jN6EBGf7MI7VzANE5PU3f4z9qDUudWjvZjOLHG0rBnBKYvoXA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.218.0", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/resources": "2.7.1", + "@opentelemetry/api-logs": "0.219.0", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -2068,14 +2117,14 @@ } }, "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.7.1.tgz", - "integrity": "sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.8.0.tgz", + "integrity": "sha512-UDBGaj6W0Rgy5rTTaoxs8gVGF/aGkAKyjurJv7se6wjRxJu7FoquTLT/vt54DZfo4crbprYfhX/SOK9+BPw1qg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/resources": "2.7.1" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -2085,36 +2134,37 @@ } }, "node_modules/@opentelemetry/sdk-node": { - "version": "0.218.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.218.0.tgz", - "integrity": "sha512-tPMjHrLV5gsfNdYqoRHjeGbCAZBXXD9c1Qo/2ut7VwnUABDNh76xNxrT0SEhkIIJuCN45bbN1vZnYL1gY0IkOg==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.219.0.tgz", + "integrity": "sha512-NWLpWLEb8gV3+JBHYoIrktbM385wyHpRJoh3J/4Q52d4PR+AlPMNGJT3DzBUrDSUEVbKAXoHR+EDAPxtiNcj8g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.218.0", - "@opentelemetry/configuration": "0.218.0", - "@opentelemetry/context-async-hooks": "2.7.1", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/exporter-logs-otlp-grpc": "0.218.0", - "@opentelemetry/exporter-logs-otlp-http": "0.218.0", - "@opentelemetry/exporter-logs-otlp-proto": "0.218.0", - "@opentelemetry/exporter-metrics-otlp-grpc": "0.218.0", - "@opentelemetry/exporter-metrics-otlp-http": "0.218.0", - "@opentelemetry/exporter-metrics-otlp-proto": "0.218.0", - "@opentelemetry/exporter-prometheus": "0.218.0", - "@opentelemetry/exporter-trace-otlp-grpc": "0.218.0", - "@opentelemetry/exporter-trace-otlp-http": "0.218.0", - "@opentelemetry/exporter-trace-otlp-proto": "0.218.0", - "@opentelemetry/exporter-zipkin": "2.7.1", - "@opentelemetry/instrumentation": "0.218.0", - "@opentelemetry/otlp-exporter-base": "0.218.0", - "@opentelemetry/propagator-b3": "2.7.1", - "@opentelemetry/propagator-jaeger": "2.7.1", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-logs": "0.218.0", - "@opentelemetry/sdk-metrics": "2.7.1", - "@opentelemetry/sdk-trace-base": "2.7.1", - "@opentelemetry/sdk-trace-node": "2.7.1", + "@opentelemetry/api-logs": "0.219.0", + "@opentelemetry/configuration": "0.219.0", + "@opentelemetry/context-async-hooks": "2.8.0", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/exporter-logs-otlp-grpc": "0.219.0", + "@opentelemetry/exporter-logs-otlp-http": "0.219.0", + "@opentelemetry/exporter-logs-otlp-proto": "0.219.0", + "@opentelemetry/exporter-metrics-otlp-grpc": "0.219.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.219.0", + "@opentelemetry/exporter-metrics-otlp-proto": "0.219.0", + "@opentelemetry/exporter-prometheus": "0.219.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.219.0", + "@opentelemetry/exporter-trace-otlp-http": "0.219.0", + "@opentelemetry/exporter-trace-otlp-proto": "0.219.0", + "@opentelemetry/exporter-zipkin": "2.8.0", + "@opentelemetry/instrumentation": "0.219.0", + "@opentelemetry/otlp-exporter-base": "0.219.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.219.0", + "@opentelemetry/propagator-b3": "2.8.0", + "@opentelemetry/propagator-jaeger": "2.8.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/sdk-logs": "0.219.0", + "@opentelemetry/sdk-metrics": "2.8.0", + "@opentelemetry/sdk-trace-base": "2.8.0", + "@opentelemetry/sdk-trace-node": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -2125,14 +2175,14 @@ } }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.1.tgz", - "integrity": "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.8.0.tgz", + "integrity": "sha512-mhU4jp+vW0mGbFRd+GeXHvmfA4aDqWjBjLC3pE5XMpLs0IE2ryYb019Ts2AQrOq67gaTF25D91+fgvEHDZEnuQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/resources": "2.7.1", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -2143,15 +2193,15 @@ } }, "node_modules/@opentelemetry/sdk-trace-node": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.7.1.tgz", - "integrity": "sha512-pCpQxU68lV+I9s9svqMyVu5iHdDDUnqUpSxqwyCU8A9ejEsSnMPCbearwsUO4yk08ZJzAIUCFuReMdVQvHrdvg==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.8.0.tgz", + "integrity": "sha512-nZt9OGufioAc3AfoLTqA9bsAeaMJAictYDdI2VcNQ+PmT+3rfKjAZDZvgPfd8VPX0O5Bw1hdQF6kDK8VSpZiWg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/context-async-hooks": "2.7.1", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/sdk-trace-base": "2.7.1" + "@opentelemetry/context-async-hooks": "2.8.0", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/sdk-trace-base": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -2161,14 +2211,14 @@ } }, "node_modules/@opentelemetry/sdk-trace-web": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-2.7.1.tgz", - "integrity": "sha512-K806OouCSOjMd8Nr7+ZCq3QT22tdAzzS/7h8vprfiKjkgFQ99/dvwU8d12WJANA6D5Qtme65hyBAqAu9CkQuxQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-2.8.0.tgz", + "integrity": "sha512-P3ZM8BGJ5mwjtyfAxRyxsCyWHvaj+xahdhLoS3YiPsEyTHcWTVzx2691C8SrGkpvro3tNFCsWuNNrvM+spKODg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/sdk-trace-base": "2.7.1" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/sdk-trace-base": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -2188,9 +2238,9 @@ } }, "node_modules/@opentelemetry/sql-common": { - "version": "0.41.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.41.2.tgz", - "integrity": "sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==", + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.42.0.tgz", + "integrity": "sha512-nwUwUU+8O8a4bnLqk6CodWeegGMEANgC94KTAhXcpGWLrW/2/hek/0ajNbjXnSOoNuCX+nteUPs46HFHhou9Xw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2213,17 +2263,15 @@ "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@pkgr/core": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", - "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", + "optional": true, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" + "node": ">=14" } }, "node_modules/@polka/url": { @@ -2278,13 +2326,6 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz", - "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", @@ -2399,6 +2440,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2416,6 +2460,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2433,6 +2480,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2450,6 +2500,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2467,6 +2520,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2484,6 +2540,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2599,9 +2658,9 @@ } }, "node_modules/@types/aws-lambda": { - "version": "8.10.161", - "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.161.tgz", - "integrity": "sha512-rUYdp+MQwSFocxIOcSsYSF3YYYC/uUpMbCY/mbO21vGqfrEYvNSoPyKYDj6RhXXpPfS0KstW9RwG3qXh9sL7FQ==", + "version": "8.10.162", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.162.tgz", + "integrity": "sha512-Fn658grtLOci1oxi1391vvDWJRKNGWRSqfxRkmN/Iy3c0tQH1USMKEXcPYHLvope+ZgTFocx9FRQJx1muBL6qw==", "dev": true, "license": "MIT" }, @@ -2717,9 +2776,9 @@ } }, "node_modules/@types/node": { - "version": "25.9.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.2.tgz", - "integrity": "sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==", + "version": "25.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", + "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", "dev": true, "license": "MIT", "dependencies": { @@ -2797,17 +2856,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.0.tgz", - "integrity": "sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.1.tgz", + "integrity": "sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.61.0", - "@typescript-eslint/type-utils": "8.61.0", - "@typescript-eslint/utils": "8.61.0", - "@typescript-eslint/visitor-keys": "8.61.0", + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/type-utils": "8.61.1", + "@typescript-eslint/utils": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -2820,7 +2879,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.61.0", + "@typescript-eslint/parser": "^8.61.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -2836,16 +2895,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.0.tgz", - "integrity": "sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.1.tgz", + "integrity": "sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.61.0", - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/typescript-estree": "8.61.0", - "@typescript-eslint/visitor-keys": "8.61.0", + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", "debug": "^4.4.3" }, "engines": { @@ -2861,14 +2920,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.0.tgz", - "integrity": "sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.1.tgz", + "integrity": "sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.61.0", - "@typescript-eslint/types": "^8.61.0", + "@typescript-eslint/tsconfig-utils": "^8.61.1", + "@typescript-eslint/types": "^8.61.1", "debug": "^4.4.3" }, "engines": { @@ -2883,14 +2942,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.0.tgz", - "integrity": "sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.1.tgz", + "integrity": "sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/visitor-keys": "8.61.0" + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2901,9 +2960,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.0.tgz", - "integrity": "sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.1.tgz", + "integrity": "sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==", "dev": true, "license": "MIT", "engines": { @@ -2918,15 +2977,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.0.tgz", - "integrity": "sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.1.tgz", + "integrity": "sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/typescript-estree": "8.61.0", - "@typescript-eslint/utils": "8.61.0", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/utils": "8.61.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -2943,9 +3002,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.0.tgz", - "integrity": "sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.1.tgz", + "integrity": "sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==", "dev": true, "license": "MIT", "engines": { @@ -2957,16 +3016,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.0.tgz", - "integrity": "sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.1.tgz", + "integrity": "sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.61.0", - "@typescript-eslint/tsconfig-utils": "8.61.0", - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/visitor-keys": "8.61.0", + "@typescript-eslint/project-service": "8.61.1", + "@typescript-eslint/tsconfig-utils": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2985,16 +3044,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.0.tgz", - "integrity": "sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.1.tgz", + "integrity": "sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.61.0", - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/typescript-estree": "8.61.0" + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3009,13 +3068,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.0.tgz", - "integrity": "sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.1.tgz", + "integrity": "sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/types": "8.61.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -3027,15 +3086,15 @@ } }, "node_modules/@vitest/browser": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.8.tgz", - "integrity": "sha512-u21VzX07HzlJYpFgkxmjEXar/tG2UqWGgyGG/46SrrPc7rSdCTPw5vuowopO9CIqF8UCUQzDFdbVnNpw6N0BfQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.9.tgz", + "integrity": "sha512-j1BKtWmPcqpMhmx/L9EPLgAJpCb0zKfwoWLmqBbxaogCXHjOwHFSEoHCBfnGtx93xKQwilZ26m+UOsHqHMkRNg==", "dev": true, "license": "MIT", "dependencies": { "@blazediff/core": "1.9.1", - "@vitest/mocker": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/mocker": "4.1.9", + "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pngjs": "^7.0.0", "sirv": "^3.0.2", @@ -3046,18 +3105,18 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "4.1.8" + "vitest": "4.1.9" } }, "node_modules/@vitest/browser-playwright": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.8.tgz", - "integrity": "sha512-SR7FqgegaexEg73xvf3ArtygXegagMdXnL0EZMpxrWvvhQxvicD/E8p0ib0J91riPRtQUViyh67Xjw3NqvyhVg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.9.tgz", + "integrity": "sha512-Bq1rOGf9waevzG3EOkO/dene6bvKTUsZMVg8S1i+WH3JcMjuXEjiahP9rAqZRELUqjBySOJsvvSWqK/B3wjKQw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/browser": "4.1.8", - "@vitest/mocker": "4.1.8", + "@vitest/browser": "4.1.9", + "@vitest/mocker": "4.1.9", "tinyrainbow": "^3.1.0" }, "funding": { @@ -3065,7 +3124,7 @@ }, "peerDependencies": { "playwright": "*", - "vitest": "4.1.8" + "vitest": "4.1.9" }, "peerDependenciesMeta": { "playwright": { @@ -3074,9 +3133,9 @@ } }, "node_modules/@vitest/coverage-istanbul": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-4.1.8.tgz", - "integrity": "sha512-/h514nMZMKI6foh21mVgO1zlCH6pdDamwKMbla1uLU2GMxTlfp0PQMxovWozmzQdCIQYZ2XXEzg2zNZom2zAOg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-4.1.9.tgz", + "integrity": "sha512-4a7DsIwycTf4eYwEDtnMfMV8H80KSKH9PuMHhqL5SwPZzDyUKq2X/TPCVZ7NqIuSz7UbZckmEmkip6iZBI/gEA==", "dev": true, "license": "MIT", "dependencies": { @@ -3095,18 +3154,18 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "4.1.8" + "vitest": "4.1.9" } }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.8.tgz", - "integrity": "sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz", + "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.9", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", @@ -3120,8 +3179,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.8", - "vitest": "4.1.8" + "@vitest/browser": "4.1.9", + "vitest": "4.1.9" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -3130,16 +3189,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", - "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -3148,13 +3207,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", - "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.8", + "@vitest/spy": "4.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -3175,9 +3234,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", - "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", "dev": true, "license": "MIT", "dependencies": { @@ -3188,13 +3247,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", - "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.9", "pathe": "^2.0.3" }, "funding": { @@ -3202,14 +3261,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", - "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -3218,9 +3277,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", - "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", "dev": true, "license": "MIT", "funding": { @@ -3228,13 +3287,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", - "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", + "@vitest/pretty-format": "4.1.9", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -3417,6 +3476,13 @@ "dev": true, "license": "MIT" }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/baseline-browser-mapping": { "version": "2.10.8", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.8.tgz", @@ -3650,6 +3716,38 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cliui/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3663,6 +3761,24 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3790,6 +3906,13 @@ "node": ">=8" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -3808,9 +3931,9 @@ "license": "ISC" }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, "license": "MIT" }, @@ -3858,11 +3981,14 @@ } }, "node_modules/eslint": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.1.tgz", - "integrity": "sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.5.0.tgz", + "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", "dev": true, "license": "MIT", + "workspaces": [ + "packages/*" + ], "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", @@ -3913,22 +4039,6 @@ } } }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", - "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "funding": { - "url": "https://opencollective.com/eslint-config-prettier" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, "node_modules/eslint-plugin-expect-type": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/eslint-plugin-expect-type/-/eslint-plugin-expect-type-0.6.2.tgz", @@ -3949,37 +4059,6 @@ "typescript": ">=4" } }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.6.tgz", - "integrity": "sha512-ifetmTcxWfz+4qRW3pH/ujdTq2jQIj59AxJMIN26K5avYgU8dxycUETQonWiW+wPrYXA0j3Try0l1CnwVQtDqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.1", - "synckit": "^0.11.13" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-scope": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", @@ -4117,13 +4196,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -4238,6 +4310,23 @@ "dev": true, "license": "ISC" }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -4289,29 +4378,30 @@ } }, "node_modules/gaxios": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", - "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz", + "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", - "node-fetch": "^3.3.2" + "node-fetch": "^3.3.2", + "rimraf": "^5.0.1" }, "engines": { "node": ">=18" } }, "node_modules/gcp-metadata": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", - "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.3.tgz", + "integrity": "sha512-ziTrzUhhpL9Zk5k0HHzgP/KIpWDJT0VMBC/ynt/QIBvTW+UUcSivQRl6VlwTf/EilDxtSWklHoRsKy1c4k+59w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", + "gaxios": "7.1.3", + "google-logging-utils": "1.1.3", "json-bigint": "^1.0.0" }, "engines": { @@ -4364,6 +4454,28 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -4377,6 +4489,32 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/google-logging-utils": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", @@ -4562,6 +4700,22 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4861,6 +5015,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4882,6 +5039,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4903,6 +5063,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4924,6 +5087,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5318,6 +5484,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/module-details-from-path": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", @@ -5499,6 +5675,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parquet-wasm": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/parquet-wasm/-/parquet-wasm-0.7.1.tgz", @@ -5526,6 +5709,30 @@ "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -5588,13 +5795,13 @@ } }, "node_modules/playwright": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", - "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.0.tgz", + "integrity": "sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0" + "playwright-core": "1.61.0" }, "bin": { "playwright": "cli.js" @@ -5607,9 +5814,9 @@ } }, "node_modules/playwright-core": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", - "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.0.tgz", + "integrity": "sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5742,23 +5949,10 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", - "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/protobufjs": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.2.tgz", - "integrity": "sha512-N9EiLovGEQOJSPF26Ij7qUGvahfEnq0eeYZ02aigIedkmz1qZSwjnP9SBITHJuF/6MYbIW4HDN8zdYjsjqJKXQ==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.4.tgz", + "integrity": "sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw==", "dev": true, "hasInstallScript": true, "license": "BSD-3-Clause", @@ -5769,7 +5963,6 @@ "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", @@ -5848,6 +6041,22 @@ "dev": true, "license": "MIT" }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rolldown": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", @@ -6060,6 +6269,25 @@ } }, "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", @@ -6074,7 +6302,7 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/ansi-regex": { + "node_modules/string-width-cjs/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", @@ -6084,7 +6312,14 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/is-fullwidth-code-point": { + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", @@ -6094,7 +6329,7 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/strip-ansi": { + "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -6123,6 +6358,30 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6136,20 +6395,31 @@ "node": ">=8" } }, - "node_modules/synckit": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", - "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", + "node_modules/systeminformation": { + "version": "5.31.7", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.7.tgz", + "integrity": "sha512-/8NC53e5nP9nmhn42/ncdOkyJnOoue/Vy+tJOyUGd1Yv66G069wK4rrziwhrqDETgk78CudTQupw5z19S5uoZw==", "dev": true, "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.3.6" + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos", + "android" + ], + "bin": { + "systeminformation": "lib/cli.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": ">=8.0.0" }, "funding": { - "url": "https://opencollective.com/synckit" + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" } }, "node_modules/table-layout": { @@ -6286,16 +6556,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.0.tgz", - "integrity": "sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.1.tgz", + "integrity": "sha512-V7PayAfJokV3pEHgN7/v03D1SpujhRfQtYLbLIiBfDDncdg4PAiRBfoS4cnCANK4jmAPncczi59QO3afiXUlNw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.61.0", - "@typescript-eslint/parser": "8.61.0", - "@typescript-eslint/typescript-estree": "8.61.0", - "@typescript-eslint/utils": "8.61.0" + "@typescript-eslint/eslint-plugin": "8.61.1", + "@typescript-eslint/parser": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/utils": "8.61.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6332,6 +6602,16 @@ "node": ">=12.17" } }, + "node_modules/undici": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.5.0.tgz", + "integrity": "sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -6483,19 +6763,19 @@ } }, "node_modules/vitest": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", - "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.8", - "@vitest/mocker": "4.1.8", - "@vitest/pretty-format": "4.1.8", - "@vitest/runner": "4.1.8", - "@vitest/snapshot": "4.1.8", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -6523,12 +6803,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.8", - "@vitest/browser-preview": "4.1.8", - "@vitest/browser-webdriverio": "4.1.8", - "@vitest/coverage-istanbul": "4.1.8", - "@vitest/coverage-v8": "4.1.8", - "@vitest/ui": "4.1.8", + "@vitest/browser-playwright": "4.1.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -6636,6 +6916,25 @@ } }, "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", @@ -6653,7 +6952,7 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", @@ -6663,7 +6962,39 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -6676,6 +7007,19 @@ "node": ">=8" } }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/ws": { "version": "8.21.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", @@ -6770,6 +7114,61 @@ "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -6792,16 +7191,16 @@ }, "packages/client-common": { "name": "@clickhouse/client-common", - "version": "1.21.0", + "version": "1.22.0", "license": "Apache-2.0", "devDependencies": {} }, "packages/client-node": { "name": "@clickhouse/client", - "version": "1.21.0", + "version": "1.22.0", "license": "Apache-2.0", "dependencies": { - "@clickhouse/client-common": "1.21.0" + "@clickhouse/client-common": "1.22.0" }, "devDependencies": { "simdjson": "^0.9.2" @@ -6812,15 +7211,15 @@ }, "packages/client-web": { "name": "@clickhouse/client-web", - "version": "1.21.0", + "version": "1.22.0", "license": "Apache-2.0", "dependencies": { - "@clickhouse/client-common": "1.21.0" + "@clickhouse/client-common": "1.22.0" } }, "tests/clickhouse-test-runner": { "name": "@clickhouse/clickhouse-test-runner", - "version": "1.21.0", + "version": "1.22.0", "dependencies": { "@clickhouse/client": "*" }, @@ -6829,12 +7228,11 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@types/node": "25.9.2", - "eslint": "^10.4.1", - "eslint-plugin-prettier": "^5.5.6", + "@types/node": "25.9.3", + "eslint": "^10.5.0", "prettier": "3.8.4", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.0", + "typescript-eslint": "^8.61.1", "vitest": "^4.0.16" }, "engines": { diff --git a/package.json b/package.json index 06bdbcf7c..0001af256 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "lint:fix": "npm --workspaces run lint:fix", "build": "npm run --workspaces build", "prettify": "prettier --write .", + "prettier:check": "prettier --check .", "test": "echo -e \"Please specify a test script to run. See \\033[1mnpm run\\033[0m for reference.\" && exit 1", "test:common:unit:node": "CLICKHOUSE_TEST_SKIP_INIT=1 TEST_MODE=common vitest -c vitest.node.config.ts", "test:common:unit:bun": "CLICKHOUSE_TEST_SKIP_INIT=1 TEST_MODE=common bun --bun vitest -c vitest.node.config.ts", @@ -32,6 +33,7 @@ "test:node:unit:bun": "CLICKHOUSE_TEST_SKIP_INIT=1 TEST_MODE=unit bun --bun vitest -c vitest.node.config.ts", "test:node:integration:tls": "TEST_MODE=tls vitest -c vitest.node.config.ts", "test:node:integration": "TEST_MODE=integration vitest -c vitest.node.config.ts", + "test:node:oss-dependents": "TEST_MODE=oss-dependents vitest -c vitest.node.config.ts", "test:node:integration:local_cluster": "CLICKHOUSE_TEST_ENVIRONMENT=local_cluster TEST_MODE=integration vitest -c vitest.node.config.ts", "test:node:integration:cloud": "CLICKHOUSE_TEST_ENVIRONMENT=cloud TEST_MODE=integration vitest -c vitest.node.config.ts", "test:node:all": "TEST_MODE=all vitest -c vitest.node.config.ts", @@ -49,36 +51,35 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@faker-js/faker": "^10.4.0", + "@faker-js/faker": "^10.5.0", "@opentelemetry/api": "^1.9.1", - "@opentelemetry/auto-instrumentations-node": "^0.76.0", - "@opentelemetry/context-zone": "^2.7.1", - "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0", - "@opentelemetry/instrumentation-document-load": "^0.63.0", - "@opentelemetry/instrumentation-fetch": "^0.218.0", - "@opentelemetry/sdk-trace-web": "^2.5.1", + "@opentelemetry/auto-instrumentations-node": "^0.77.0", + "@opentelemetry/context-zone": "^2.8.0", + "@opentelemetry/exporter-trace-otlp-proto": "^0.219.0", + "@opentelemetry/instrumentation-document-load": "^0.64.0", + "@opentelemetry/instrumentation-fetch": "^0.219.0", + "@opentelemetry/sdk-trace-web": "^2.8.0", "@types/jsonwebtoken": "^9.0.10", - "@types/node": "25.9.2", + "@types/node": "25.9.3", "@types/split2": "^4.2.3", "@types/uuid": "^11.0.0", - "@vitest/browser-playwright": "^4.1.8", + "@vitest/browser-playwright": "^4.1.9", "@vitest/coverage-istanbul": "^4.1.0", "@vitest/coverage-v8": "^4.1.0", "apache-arrow": "^21.0.0", - "eslint": "^10.4.1", - "eslint-config-prettier": "^10.1.8", + "eslint": "^10.5.0", "eslint-plugin-expect-type": "^0.6.2", - "eslint-plugin-prettier": "^5.5.6", "husky": "^9.1.7", "jsonwebtoken": "^9.0.3", "lint-staged": "^17.0.7", "parquet-wasm": "0.7.1", - "playwright": "^1.60.0", + "playwright": "^1.61.0", "prettier": "3.8.4", "split2": "^4.2.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.0", + "typescript-eslint": "^8.61.1", "typescript-language-server": "^5.3.0", + "undici": "^8.5.0", "uuid": "^14.0.0", "vitest": "^4.0.16" }, @@ -91,8 +92,7 @@ ], "lint-staged": { "*.ts": [ - "prettier --write", - "npm run lint:fix" + "prettier --write" ], "*.json": [ "prettier --write" diff --git a/packages/client-common/__tests__/unit/config.test.ts b/packages/client-common/__tests__/unit/config.test.ts index 15330438c..71a1e806c 100644 --- a/packages/client-common/__tests__/unit/config.test.ts +++ b/packages/client-common/__tests__/unit/config.test.ts @@ -365,8 +365,8 @@ describe("config", () => { request_timeout: 30_000, max_open_connections: 10, compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, auth: { username: "default", @@ -387,6 +387,56 @@ describe("config", () => { }); }); + it("resolves the object compression codec form to connection params", () => { + const res = getConnectionParams( + { + url: new URL("https://my.host:8443/"), + compression: { + request: { codec: "zstd" }, + response: { codec: "gzip" }, + }, + }, + logger, + ); + expect(res.compression).toEqual({ + compress_request: { codec: "zstd" }, + decompress_response: { codec: "gzip" }, + }); + }); + + it("carries the request compression level on the codec object", () => { + const res = getConnectionParams( + { + url: new URL("https://my.host:8443/"), + compression: { + request: { codec: "zstd", level: 19 }, + }, + }, + logger, + ); + expect(res.compression).toEqual({ + compress_request: { codec: "zstd", level: 19 }, + decompress_response: undefined, + }); + }); + + it("carries the brotli request quality on the codec object", () => { + const res = getConnectionParams( + { + url: new URL("https://my.host:8443/"), + compression: { + request: { codec: "br", quality: 6 }, + response: { codec: "br" }, + }, + }, + logger, + ); + expect(res.compression).toEqual({ + compress_request: { codec: "br", quality: 6 }, + decompress_response: { codec: "br" }, + }); + }); + it("should set connection params from the config", async () => { const res = getConnectionParams( { @@ -416,8 +466,8 @@ describe("config", () => { request_timeout: 42_000, max_open_connections: 144, compression: { - compress_request: true, - decompress_response: false, + compress_request: { codec: "gzip" }, + decompress_response: undefined, }, auth: { username: "bob", @@ -496,8 +546,8 @@ describe("config", () => { request_timeout: 30_000, max_open_connections: 10, compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, auth: { access_token: "secret-token", diff --git a/packages/client-common/eslint.config.mjs b/packages/client-common/eslint.config.mjs index 578dc9cff..0a540ee80 100644 --- a/packages/client-common/eslint.config.mjs +++ b/packages/client-common/eslint.config.mjs @@ -1,14 +1,12 @@ -import js from "@eslint/js"; import { defineConfig } from "eslint/config"; -import tseslint from "typescript-eslint"; -import { typescriptEslintConfig } from "../../eslint.config.base.mjs"; +import { + recommendedWarnConfigs, + typescriptEslintConfig, +} from "../../eslint.config.base.mjs"; export default defineConfig( - // Base ESLint recommended rules - js.configs.recommended, - // TypeScript-ESLint recommended rules with type checking - ...tseslint.configs.strict, - ...tseslint.configs.stylistic, + // Recommended rule sets, downgraded to warnings (only tsc reports errors) + ...recommendedWarnConfigs, typescriptEslintConfig(import.meta.dirname), // Ignore build artifacts and externals { diff --git a/packages/client-common/package.json b/packages/client-common/package.json index 0e3193dee..99aaecd3d 100644 --- a/packages/client-common/package.json +++ b/packages/client-common/package.json @@ -2,7 +2,7 @@ "name": "@clickhouse/client-common", "description": "Official JS client for ClickHouse DB - common types", "homepage": "https://clickhouse.com", - "version": "1.21.0", + "version": "1.22.0", "license": "Apache-2.0", "keywords": [ "clickhouse", diff --git a/packages/client-common/src/config.ts b/packages/client-common/src/config.ts index 5c256b89f..44f4c645f 100644 --- a/packages/client-common/src/config.ts +++ b/packages/client-common/src/config.ts @@ -1,5 +1,11 @@ import type { InsertValues, ResponseHeaders } from "./clickhouse_types"; -import type { Connection, ConnectionParams } from "./connection"; +import type { + CompressionMethod, + Connection, + ConnectionParams, + RequestCompression, + ResponseCompression, +} from "./connection"; import type { DataFormat } from "./data_formatter"; import type { Logger } from "./logger"; import { ClickHouseLogLevel, LogWriter } from "./logger"; @@ -8,6 +14,38 @@ import type { BaseResultSet } from "./result"; import type { ClickHouseSettings } from "./settings"; import type { ClickHouseSpan, ClickHouseTracer } from "./tracing"; +/** Normalizes the public request compression option into the internal codec + * object, or `undefined` when disabled. `true` keeps gzip for backwards + * compatibility; the object form (carrying its per-codec option) is passed + * through verbatim, so untyped JS supplying an unknown codec still reaches the + * Node guard, which rejects it with a clear error. */ +function normalizeRequestCompression( + value: boolean | RequestCompression | undefined, +): RequestCompression | undefined { + if (!value) { + return undefined; + } + if (value === true) { + return { codec: "gzip" }; + } + return value; +} + +/** Normalizes the public response compression option + * (`false | true | { codec }`) into the internal codec object, or `undefined` + * when disabled. `true` keeps gzip for backwards compatibility. */ +function normalizeResponseCompression( + value: boolean | { codec: CompressionMethod } | undefined, +): ResponseCompression | undefined { + if (!value) { + return undefined; + } + if (value === true) { + return { codec: "gzip" }; + } + return { codec: value.codec }; +} + export interface BaseClickHouseClientConfigOptions { /** @deprecated since version 1.0.0. Use {@link url} instead.
* A ClickHouse instance URL. @@ -31,14 +69,29 @@ export interface BaseClickHouseClientConfigOptions { max_open_connections?: number; /** Request and response compression settings. */ compression?: { - /** `response: true` instructs ClickHouse server to respond with compressed response body.
- * This will add `Accept-Encoding: gzip` header in the request and `enable_http_compression=1` ClickHouse HTTP setting. + /** Instructs the ClickHouse server to respond with a compressed response body. + * `true` requests `gzip`; pass `{ codec }` to select the codec explicitly, + * e.g. `{ codec: "zstd" }` or `{ codec: "br" }`. This adds the matching + * `Accept-Encoding` header and the `enable_http_compression=1` ClickHouse HTTP + * setting. Decompression takes no codec options (the server chose them). + * `"zstd"` requires Node.js >= 22.15.0; `"br"` works on any supported Node.js. + * On `@clickhouse/client-web`, `zstd` is rejected at client creation; `gzip` + * and `br` responses are decompressed by the browser. *

Warning: Response compression can't be enabled for a user with readonly=1, as ClickHouse will not allow settings modifications for such user.

* @default false */ - response?: boolean; - /** `request: true` enabled compression on the client request body. + response?: boolean | { codec: CompressionMethod }; + /** Enables compression of the outgoing request (insert) body. + * `true` uses `gzip` with defaults; pass a per-codec object to select the + * codec and tune it: `{ codec: "gzip", level }`, `{ codec: "zstd", level }`, + * or `{ codec: "br", quality }`. Each codec exposes its own option (a `level` + * for gzip/zstd, a `quality` for Brotli); when omitted, a sensible default is + * used (gzip/zstd use zlib's defaults, `br` defaults to quality 4 since + * zlib's brotli default of 11 is far too slow for a streaming insert body). + * `"zstd"` requires Node.js >= 22.15.0; `"br"` works on any supported Node.js. + * Request-body compression is performed only by `@clickhouse/client` (Node.js); + * `@clickhouse/client-web` sends request bodies uncompressed. * @default false */ - request?: boolean; + request?: boolean | RequestCompression; }; /** The name of the user on whose behalf requests are made. * Should not be set if {@link access_token} is provided. @@ -318,8 +371,12 @@ export function getConnectionParams( request_timeout, max_open_connections: config.max_open_connections ?? 10, compression: { - decompress_response: config.compression?.response ?? false, - compress_request: config.compression?.request ?? false, + decompress_response: normalizeResponseCompression( + config.compression?.response, + ), + compress_request: normalizeRequestCompression( + config.compression?.request, + ), }, database: config.database ?? "default", log_writer: new LogWriter(logger, "Connection", log_level), diff --git a/packages/client-common/src/connection.ts b/packages/client-common/src/connection.ts index 2a23ea65a..5644dc5a4 100644 --- a/packages/client-common/src/connection.ts +++ b/packages/client-common/src/connection.ts @@ -29,9 +29,35 @@ export interface ConnectionParams { use_multipart_params_auto?: boolean; } +/** Compression codecs supported for the HTTP request (insert) and response + * (read) bodies. `zstd` requires Node.js >= 22.15.0 (zstd support in the + * built-in `zlib` module); `br` (Brotli) is available on every supported + * Node.js version. Request-body compression is performed only by + * `@clickhouse/client` (Node.js); on the web client, response decompression is + * handled by the browser and only `zstd` is rejected. */ +export type CompressionMethod = "gzip" | "zstd" | "br"; + +/** Normalized request (insert) body compression, discriminated by codec so each + * codec carries its own tuning option: a `level` for gzip/zstd, a `quality` for + * Brotli. */ +export type RequestCompression = + | { codec: "gzip"; level?: number } + | { codec: "zstd"; level?: number } + | { codec: "br"; quality?: number }; + +/** Normalized response (read) body compression. The compression options are + * chosen by the ClickHouse server, so none are carried here. */ +export type ResponseCompression = + | { codec: "gzip" } + | { codec: "zstd" } + | { codec: "br" }; + export interface CompressionSettings { - decompress_response: boolean; - compress_request: boolean; + /** Response decompression codec, or `undefined` to disable. */ + decompress_response: ResponseCompression | undefined; + /** Request compression codec (with an optional codec-specific level), or + * `undefined` to disable. */ + compress_request: RequestCompression | undefined; } export interface ConnBaseQueryParams { diff --git a/packages/client-common/src/index.ts b/packages/client-common/src/index.ts index 1788a479b..3b86b3989 100644 --- a/packages/client-common/src/index.ts +++ b/packages/client-common/src/index.ts @@ -168,6 +168,9 @@ export { LogWriter, DefaultLogger, type LogWriterParams } from "./logger"; export { getCurrentStackTrace, enhanceStackTrace } from "./error"; export type { CompressionSettings, + CompressionMethod, + RequestCompression, + ResponseCompression, Connection, ConnectionParams, ConnInsertResult, diff --git a/packages/client-common/src/utils/connection.ts b/packages/client-common/src/utils/connection.ts index e737d5b5f..847cedcbf 100644 --- a/packages/client-common/src/utils/connection.ts +++ b/packages/client-common/src/utils/connection.ts @@ -1,3 +1,4 @@ +import type { CompressionMethod } from "../connection"; import type { ClickHouseSettings } from "../settings"; export type HttpHeader = number | string | string[]; @@ -5,23 +6,29 @@ export type HttpHeaders = Record; export function withCompressionHeaders({ headers, - enable_request_compression, - enable_response_compression, + request_compression_codec, + response_compression_codec, }: { headers: HttpHeaders; - enable_request_compression: boolean | undefined; - enable_response_compression: boolean | undefined; + // The codec name is also the `Content-Encoding` / `Accept-Encoding` value; + // `undefined` disables the corresponding header. + request_compression_codec: CompressionMethod | undefined; + response_compression_codec: CompressionMethod | undefined; }): Record { return { ...headers, - ...(enable_response_compression ? { "Accept-Encoding": "gzip" } : {}), - ...(enable_request_compression ? { "Content-Encoding": "gzip" } : {}), + ...(response_compression_codec + ? { "Accept-Encoding": response_compression_codec } + : {}), + ...(request_compression_codec + ? { "Content-Encoding": request_compression_codec } + : {}), }; } export function withHttpSettings( clickhouse_settings?: ClickHouseSettings, - compression?: boolean, + compression?: { codec: CompressionMethod } | undefined, ): ClickHouseSettings { return { ...(compression diff --git a/packages/client-common/src/version.ts b/packages/client-common/src/version.ts index a38a7bdc5..cbfb1f9da 100644 --- a/packages/client-common/src/version.ts +++ b/packages/client-common/src/version.ts @@ -1 +1 @@ -export default "1.21.0"; +export default "1.22.0"; diff --git a/packages/client-node/__tests__/integration/node_compression.test.ts b/packages/client-node/__tests__/integration/node_compression.test.ts index e1eba2439..8d44f944d 100644 --- a/packages/client-node/__tests__/integration/node_compression.test.ts +++ b/packages/client-node/__tests__/integration/node_compression.test.ts @@ -1,7 +1,20 @@ import { describe, it, beforeEach, afterEach, expect } from "vitest"; -import { createTestClient } from "@test/utils/client"; +import { + type ClickHouseClient, + type ResponseJSON, +} from "@clickhouse/client-common"; +import { createTestClient, guid } from "@test/utils"; +import { createSimpleTable } from "@test/fixtures/simple_table"; +import { isClickHouseVersionAtLeast } from "@test/utils/server_version"; import http from "http"; import { type AddressInfo } from "net"; +import Zlib from "zlib"; + +// zstd HTTP transport is supported by the ClickHouse server since 22.10, and the +// client's zstd codec needs the built-in `zlib` zstd APIs (Node.js >= 22.15.0). +const zstdSupported = + typeof Zlib.createZstdCompress === "function" && + typeof Zlib.createZstdDecompress === "function"; describe("[Node.js] Compression", () => { describe("Malformed compression response", () => { @@ -85,3 +98,53 @@ describe("[Node.js] Compression", () => { return res.end(); } }); + +describe.skipIf(!zstdSupported)("[Node.js] zstd compression", () => { + let client: ClickHouseClient; + afterEach(async () => { + await client.close(); + }); + + it("round-trips an insert with zstd request compression", async ({ + skip, + }) => { + client = createTestClient({ + compression: { request: { codec: "zstd" } }, + }); + if (!(await isClickHouseVersionAtLeast(client, 22, 10))) { + skip(); + } + + const tableName = `zstd_request_compression_test_${guid()}`; + await createSimpleTable(client, tableName); + + const dataToInsert = new Array(1_000) + .fill(0) + .map((_v, idx) => [idx, `${idx + 5}`, [idx + 1, idx + 2]]); + await client.insert({ table: tableName, values: dataToInsert }); + + const rs = await client.query({ + query: `SELECT * FROM ${tableName}`, + format: "JSON", + }); + const result = await rs.json(); + expect(result.data.length).toBe(1_000); + }); + + it("decompresses a zstd-compressed response", async ({ skip }) => { + client = createTestClient({ + compression: { response: { codec: "zstd" } }, + }); + if (!(await isClickHouseVersionAtLeast(client, 22, 10))) { + skip(); + } + + const rs = await client.query({ + query: `SELECT number FROM system.numbers LIMIT 20000`, + format: "JSONEachRow", + }); + const response = await rs.json<{ number: string }>(); + expect(response.length).toBe(20000); + expect(response[response.length - 1].number).toBe("19999"); + }); +}); diff --git a/packages/client-node/__tests__/integration/node_socket_handling.test.ts b/packages/client-node/__tests__/integration/node_socket_handling.test.ts index 7277ff02c..6d8da0f1e 100644 --- a/packages/client-node/__tests__/integration/node_socket_handling.test.ts +++ b/packages/client-node/__tests__/integration/node_socket_handling.test.ts @@ -183,19 +183,31 @@ describe("Resource is not available", () => { let server: http.Server | undefined; const port = 18125; beforeAll(async () => { - // Client has request timeout set to lower than the server's "sleep" time + // The down-server failures here are ECONNREFUSED (returned immediately, + // independent of the timeout), so the tight ClientTimeout is unnecessary. + // The final ping is a real connect + round-trip to a freshly started server, + // which can exceed a few ms on a loaded CI runner; use a generous timeout so + // it is not flaky. client = createTestClient({ url: `http://127.0.0.1:${port}`, - request_timeout: ClientTimeout, + request_timeout: 2_000, max_open_connections: MaxOpenConnections, keep_alive: { enable: true, }, } as NodeClickHouseClientConfigOptions); }); + afterEach(async () => { + // Free the fixed port between retries: otherwise a retry would find the + // server started by the previous attempt still listening, and the + // "should fail" pings would unexpectedly succeed. + if (server) { + await closeServer(server); + server = undefined; + } + }); afterAll(async () => { await client.close(); - await closeServer(server!); }); it("should fail with a connection error, but then reach out to the server", async () => { diff --git a/packages/client-node/__tests__/oss-dependents/arkime.test.ts b/packages/client-node/__tests__/oss-dependents/arkime.test.ts new file mode 100644 index 000000000..f41e8bcf3 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/arkime.test.ts @@ -0,0 +1,97 @@ +/** + * arkime/arkime — ClickHouse JS client usage example + * ================================================== + * + * Repo: https://github.com/arkime/arkime (~7k★) + * Package: @clickhouse/client ^1.12.1 + * Lives in: cont3xt/integrations/clickhouse + * Analysed at: dc5bd802e1b071d4a54993ceb2fd2b42677c917b + * + * How the client is used + * ---------------------- + * Arkime is a large-scale network-capture/indexing system. The JS client + * appears in Cont3xt, Arkime's threat-intel enrichment UI, as a pluggable + * `ClickHouseIntegration` — analysts configure a query that ClickHouse runs to + * enrich an indicator (IP/domain/etc.). + * + * Key patterns: + * - Upstream is CommonJS: `const { createClient } = require('@clickhouse/client')`. + * Reproduced here with an ESM import (the runtime surface is identical). + * - `class ClickHouseIntegration extends Integration` — implements the + * integration contract and runs user-configured queries. + * + * References (pinned to ref=dc5bd802e1b071d4a54993ceb2fd2b42677c917b): + * - Integration: https://github.com/arkime/arkime/blob/dc5bd802e1b071d4a54993ceb2fd2b42677c917b/cont3xt/integrations/clickhouse/index.js + * - Dependency: https://github.com/arkime/arkime/blob/dc5bd802e1b071d4a54993ceb2fd2b42677c917b/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +// Minimal stand-in for Cont3xt's Integration base class. +abstract class Integration { + abstract fetch( + query: string, + params: Record, + ): Promise; +} + +describe("oss-dependents / arkime", () => { + const table = `oss_arkime_${guid()}`; + + class ClickHouseIntegration extends Integration { + private client: ClickHouseClient; + constructor() { + super(); + this.client = createTestClient(); + } + + // Runs the analyst-configured enrichment query for an indicator. + async fetch( + query: string, + params: Record, + ): Promise { + const result = await this.client.query({ + query, + query_params: params, + format: "JSONEachRow", + }); + return result.json(); + } + + async seed(): Promise { + await this.client.command({ + query: `CREATE TABLE ${table} (indicator String, score UInt32) ENGINE = MergeTree ORDER BY indicator`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + await this.client.insert({ + table, + values: [{ indicator: "1.2.3.4", score: 42 }], + format: "JSONEachRow", + }); + } + + async close(): Promise { + await this.client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await this.client.close(); + } + } + + let integration: ClickHouseIntegration; + afterEach(async () => { + await integration.close(); + }); + + it("integration class runs a parameterised enrichment query", async () => { + integration = new ClickHouseIntegration(); + await integration.seed(); + const rows = await integration.fetch( + `SELECT indicator, score FROM ${table} WHERE indicator = {indicator:String}`, + { indicator: "1.2.3.4" }, + ); + expect(rows).toEqual([{ indicator: "1.2.3.4", score: 42 }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/beekeeper-studio.test.ts b/packages/client-node/__tests__/oss-dependents/beekeeper-studio.test.ts new file mode 100644 index 000000000..a8495b7af --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/beekeeper-studio.test.ts @@ -0,0 +1,109 @@ +/** + * beekeeper-studio/beekeeper-studio — ClickHouse JS client usage example + * ====================================================================== + * + * Repo: https://github.com/beekeeper-studio/beekeeper-studio (~23k★) + * Package: @clickhouse/client ^1.8.1 + * Lives in: apps/studio + * Analysed at: 2839d29c544a7a0c5c7e85f6431f7187cf311759 + * + * How the client is used + * ---------------------- + * Beekeeper Studio is a cross-platform SQL GUI; ClickHouse is one of its + * supported engines. The client powers a DATABASE DRIVER plus a custom knex + * dialect so the app can introspect schemas, run queries and insert data. + * + * Key patterns: + * - `import { createClient, InsertParams } from '@clickhouse/client'`. + * - A bespoke knex-clickhouse layer (TableBuilder, ViewCompiler, + * QueryCompiler) wrapping the driver (omitted here). + * - TLS handling: one-way and mutual TLS based on configured cert/key files. + * + * References (pinned to ref=2839d29c544a7a0c5c7e85f6431f7187cf311759): + * - DB client: https://github.com/beekeeper-studio/beekeeper-studio/blob/2839d29c544a7a0c5c7e85f6431f7187cf311759/apps/studio/src-commercial/backend/lib/db/clients/clickhouse.ts + * - knex dialect: https://github.com/beekeeper-studio/beekeeper-studio/blob/2839d29c544a7a0c5c7e85f6431f7187cf311759/apps/studio/src/shared/lib/knex-clickhouse/index.ts + * - Dependency: https://github.com/beekeeper-studio/beekeeper-studio/blob/2839d29c544a7a0c5c7e85f6431f7187cf311759/apps/studio/package.json + * + * Reproduction note: the TLS config-builder below is kept (and type-checked) + * because TLS is a defining part of the upstream driver, but the running client + * connects over plain HTTP (TLS has its own dedicated test env). The + * `InsertParams`-typed insert and query surface are exercised live. + */ + +import type { Readable } from "node:stream"; +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient, type InsertParams } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +interface DriverTLS { + ca_cert: Buffer; + cert?: Buffer; + key?: Buffer; +} + +describe("oss-dependents / beekeeper-studio", () => { + let client: ClickHouseClient; + const table = `oss_beekeeper_${guid()}`; + + // Type-checked stand-in for the driver's one-way / mutual TLS builder. Exercises + // the shape the upstream driver passes to createClient({ tls }). + function buildTls(files?: { + caFile: Buffer; + certFile?: Buffer; + keyFile?: Buffer; + }): DriverTLS | undefined { + if (!files) return undefined; + const tls: DriverTLS = { ca_cert: files.caFile }; + if (files.certFile && files.keyFile) { + tls.cert = files.certFile; // mutual TLS + tls.key = files.keyFile; + } + return tls; + } + + function createDriver(): ClickHouseClient { + // In a TLS deployment the result of buildTls() would be passed as `tls`. + void buildTls; + return createTestClient(); + } + + // GUI "insert rows" action maps to InsertParams. + async function insertRows( + c: ClickHouseClient, + rows: unknown[], + ): Promise { + const params: InsertParams = { + table, + values: rows, + format: "JSONEachRow", + }; + await c.insert(params); + } + + afterEach(async () => { + await client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await client.close(); + }); + + it("InsertParams-typed insert + SHOW TABLES introspection", async () => { + client = createDriver(); + await client.command({ + query: `CREATE TABLE ${table} (id UInt32) ENGINE = MergeTree ORDER BY id`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + await insertRows(client, [{ id: 1 }]); + + const tables = await ( + await client.query({ query: "SHOW TABLES", format: "JSONEachRow" }) + ).json<{ name: string }>(); + expect(tables.some((t) => t.name === table)).toBe(true); + + const rows = await ( + await client.query({ + query: `SELECT id FROM ${table}`, + format: "JSONEachRow", + }) + ).json<{ id: number }>(); + expect(rows).toEqual([{ id: 1 }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/civitai.test.ts b/packages/client-node/__tests__/oss-dependents/civitai.test.ts new file mode 100644 index 000000000..aa87d5175 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/civitai.test.ts @@ -0,0 +1,121 @@ +/** + * civitai/civitai — ClickHouse JS client usage example + * ==================================================== + * + * Repo: https://github.com/civitai/civitai (~7k★) + * Package: @clickhouse/client ^0.2.2 (notably old — pre-1.0) + * Lives in: src/server/clickhouse/client.ts + * Analysed at: dfbd42ac3b2809610e12e749f24f35159d057bfa + * + * How the client is used + * ---------------------- + * Civitai uses ClickHouse for METRICS, REWARDS and event tracking. A + * `CustomClickHouseClient` wraps `createClient`; downstream modules build + * metrics, rewards and event jobs on top of it. + * + * Key patterns: + * - `import { createClient, type ClickHouseClient } from '@clickhouse/client'`. + * - A `CustomClickHouseClient` augmentation reused across metrics/rewards. + * - Error handling via `ClickHouseError`. + * + * Outlier: upstream is still on @clickhouse/client@^0.2.2, so it predates a large + * amount of the current API surface — a good migration candidate. This example + * targets the CURRENT (1.x) API on purpose, so the integration test reflects + * where civitai would land after upgrading. + * + * References (pinned to ref=dfbd42ac3b2809610e12e749f24f35159d057bfa): + * - Client wrapper: https://github.com/civitai/civitai/blob/dfbd42ac3b2809610e12e749f24f35159d057bfa/src/server/clickhouse/client.ts + * - Metrics base: https://github.com/civitai/civitai/blob/dfbd42ac3b2809610e12e749f24f35159d057bfa/src/server/metrics/base.metrics.ts + * - Error handling: https://github.com/civitai/civitai/blob/dfbd42ac3b2809610e12e749f24f35159d057bfa/src/server/jobs/images-created-events.ts + * - Dependency: https://github.com/civitai/civitai/blob/dfbd42ac3b2809610e12e749f24f35159d057bfa/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { ClickHouseError, type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / civitai", () => { + const table = `oss_civitai_${guid()}`; + + // CustomClickHouseClient augments the base client with domain helpers reused by + // metrics and rewards modules. + class CustomClickHouseClient { + private client: ClickHouseClient; + lastError: ClickHouseError | null = null; + constructor() { + this.client = createTestClient(); + } + + async createSchema(): Promise { + await this.client.command({ + query: `CREATE TABLE ${table} (type String, userId UInt32) ENGINE = MergeTree ORDER BY type`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + } + + async trackEvent( + target: string, + event: { type: string; userId: number }, + ): Promise { + try { + await this.client.insert({ + table: target, + values: [event], + format: "JSONEachRow", + }); + return true; + } catch (err) { + // Civitai narrows ClickHouse-specific failures from generic ones. + if (err instanceof ClickHouseError) { + this.lastError = err; + return false; + } + throw err; + } + } + + async count(): Promise { + const rows = await ( + await this.client.query({ + query: `SELECT count() AS n FROM ${table}`, + format: "JSONEachRow", + }) + ).json<{ n: string }>(); + return rows[0]!.n; + } + + async close(): Promise { + await this.client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await this.client.close(); + } + } + + let ch: CustomClickHouseClient; + afterEach(async () => { + await ch.close(); + }); + + it("tracks events and narrows ClickHouseError on failure", async () => { + ch = new CustomClickHouseClient(); + await ch.createSchema(); + + // Happy path. + expect( + await ch.trackEvent(table, { type: "image.created", userId: 1 }), + ).toBe(true); + expect(await ch.count()).toBe("1"); + + // Failure path: inserting into a missing table surfaces a ClickHouseError, + // which the wrapper catches and narrows (instanceof) rather than crashing. + expect( + await ch.trackEvent(`missing_${guid()}`, { + type: "image.created", + userId: 2, + }), + ).toBe(false); + expect(ch.lastError).toBeInstanceOf(ClickHouseError); + expect(typeof ch.lastError?.code).toBe("string"); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/cube.test.ts b/packages/client-node/__tests__/oss-dependents/cube.test.ts new file mode 100644 index 000000000..11a0b48e8 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/cube.test.ts @@ -0,0 +1,100 @@ +/** + * cube-js/cube — ClickHouse JS client usage example + * ================================================= + * + * Repo: https://github.com/cube-js/cube (~20k★) + * Package: @clickhouse/client ^1.12.0 + * Lives in: packages/cubejs-clickhouse-driver + * Analysed at: f8851968710e332121d2ad8399f9d788660275f1 + * + * How the client is used + * ---------------------- + * Cube ships a first-party CLICKHOUSE DRIVER. It migrated from the legacy + * `apla-clickhouse` package to the official `@clickhouse/client` (#8928), and + * keeps the version bumped via dependency PRs (e.g. 1.7.0 -> 1.12.0, #9829). + * + * Key patterns: + * - `import { ClickHouseClient, createClient }` + types `ClickHouseSettings`, + * `ResponseJSON`. + * - Query results consumed as `ResponseJSON`; large result sets streamed via + * `node:stream` `Readable`. + * - Used as a devDependency in cubejs-schema-compiler tests with + * `testcontainers` (ClickHouseDbRunner.ts). + * + * References (pinned to ref=f8851968710e332121d2ad8399f9d788660275f1): + * - Driver: https://github.com/cube-js/cube/blob/f8851968710e332121d2ad8399f9d788660275f1/packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts + * - Test runner: https://github.com/cube-js/cube/blob/f8851968710e332121d2ad8399f9d788660275f1/packages/cubejs-schema-compiler/test/integration/clickhouse/ClickHouseDbRunner.ts + * - Dependency: https://github.com/cube-js/cube/blob/f8851968710e332121d2ad8399f9d788660275f1/packages/cubejs-clickhouse-driver/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { + type ClickHouseClient, + type ClickHouseSettings, + type ResponseJSON, +} from "@clickhouse/client"; +import { createTestClient } from "@test/utils"; + +describe("oss-dependents / cube", () => { + let driver: ClickHouseDriver; + + class ClickHouseDriver { + private client: ClickHouseClient; + + constructor() { + const clickhouse_settings: ClickHouseSettings = { + // Cube reads numeric ids as strings to avoid precision loss. + output_format_json_quote_64bit_integers: 1, + }; + this.client = createTestClient({ clickhouse_settings }); + } + + // Query results consumed as ResponseJSON (format: 'JSON'). + async query( + query: string, + params: Record, + ): Promise { + const result = await this.client.query({ + query, + query_params: params, + format: "JSON", + }); + const response: ResponseJSON = await result.json(); + return response.data; + } + + // Large result sets are streamed. + async stream(query: string): Promise { + const result = await this.client.query({ query, format: "JSONEachRow" }); + const stream = result.stream(); + let rows = 0; + for await (const chunk of stream) { + rows += (chunk as unknown[]).length; + } + return rows; + } + + async release(): Promise { + await this.client.close(); + } + } + + afterEach(async () => { + await driver.release(); + }); + + it("typed query -> ResponseJSON.data and streamed reads", async () => { + driver = new ClickHouseDriver(); + const rows = await driver.query<{ n: string }>("SELECT {n:UInt64} AS n", { + n: 42, + }); + expect(rows).toEqual([{ n: "42" }]); + + const streamed = await driver.stream( + "SELECT number FROM system.numbers LIMIT 10", + ); + expect(streamed).toBe(10); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/daytona.test.ts b/packages/client-node/__tests__/oss-dependents/daytona.test.ts new file mode 100644 index 000000000..7f1a7085a --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/daytona.test.ts @@ -0,0 +1,116 @@ +/** + * daytonaio/daytona — ClickHouse JS client usage example + * ====================================================== + * + * Repo: https://github.com/daytonaio/daytona (~72k★) + * Package: @clickhouse/client ^1.16.0 + * Lives in: apps/api/src/clickhouse + * Analysed at: 8be4772fbff159856b99ca595622a7fb1e64e63a + * + * How the client is used + * ---------------------- + * A NestJS `ClickHouseService` wraps the client for usage analytics. The client + * is LAZILY instantiated from config (returns `null` when ClickHouse is not + * configured), and properly closed on module destroy. + * + * Key patterns: + * - `createClient({ url, username, password, database })`. + * - Reads via `client.query({ query, query_params, format: 'JSONEachRow', + * clickhouse_settings: { date_time_input_format: 'best_effort' } })` then + * `result.json()`. + * - A thin `query()` / `queryOne()` typed wrapper. + * - `await this.client.close()` in `onModuleDestroy()`. + * + * References (pinned to ref=8be4772fbff159856b99ca595622a7fb1e64e63a): + * - Service: https://github.com/daytonaio/daytona/blob/8be4772fbff159856b99ca595622a7fb1e64e63a/apps/api/src/clickhouse/clickhouse.service.ts + * - Dependency: https://github.com/daytonaio/daytona/blob/8be4772fbff159856b99ca595622a7fb1e64e63a/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / daytona", () => { + const table = `oss_daytona_${guid()}`; + + // Mirrors the NestJS service: lazy client, typed query helpers, clean shutdown. + // `configured` stands in for the presence of a CLICKHOUSE_URL in upstream. + class ClickHouseService { + private client: ClickHouseClient | null = null; + constructor(private readonly configured: boolean) {} + + private getClient(): ClickHouseClient | null { + if (this.client) return this.client; + if (!this.configured) return null; + this.client = createTestClient(); + return this.client; + } + + async query( + query: string, + query_params?: Record, + ): Promise { + const client = this.getClient(); + if (!client) return []; + const result = await client.query({ + query, + query_params, + format: "JSONEachRow", + clickhouse_settings: { date_time_input_format: "best_effort" }, + }); + return result.json(); + } + + async queryOne( + query: string, + query_params?: Record, + ): Promise { + const rows = await this.query(query, query_params); + return rows[0] ?? null; + } + + // onModuleDestroy() + async close(): Promise { + await this.client?.close(); + } + } + + let service: ClickHouseService; + afterEach(async () => { + // Each test closes its own service; drop the table via a throwaway client. + const cleanup = createTestClient(); + await cleanup.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await cleanup.close(); + }); + + it("returns empty results when not configured", async () => { + service = new ClickHouseService(false); + expect(await service.query("SELECT 1")).toEqual([]); + expect(await service.queryOne("SELECT 1")).toBeNull(); + await service.close(); + }); + + it("typed query/queryOne with {table:Identifier} param", async () => { + service = new ClickHouseService(true); + const setup = createTestClient(); + await setup.command({ + query: `CREATE TABLE ${table} (id UInt32) ENGINE = MergeTree ORDER BY id`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + await setup.insert({ + table, + values: [{ id: 1 }, { id: 2 }, { id: 3 }], + format: "JSONEachRow", + }); + await setup.close(); + + const row = await service.queryOne<{ total: string }>( + "SELECT count() AS total FROM {table:Identifier}", + { table }, + ); + expect(row?.total).toBe("3"); + await service.close(); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/dbgate.test.ts b/packages/client-node/__tests__/oss-dependents/dbgate.test.ts new file mode 100644 index 000000000..5aa05df86 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/dbgate.test.ts @@ -0,0 +1,80 @@ +/** + * dbgate/dbgate — ClickHouse JS client usage example + * ================================================== + * + * Repo: https://github.com/dbgate/dbgate (~7k★) + * Package: @clickhouse/client ^1.5.0 + * Lives in: plugins/dbgate-plugin-clickhouse + * Analysed at: 6bacb1c81e8e330ca0ee163ec06202b68a1e0591 + * + * How the client is used + * ---------------------- + * DbGate is a cross-platform database manager; ClickHouse support ships as a + * DRIVER PLUGIN. The plugin backend uses the client for querying, schema + * analysis and bulk inserts. + * + * Key patterns: + * - Upstream is CommonJS: `const { createClient } = require('@clickhouse/client')` + * implementing DbGate's `EngineDriver`. Reproduced here with an ESM import. + * - A custom `createBulkInsertStream` for efficient bulk loading — reproduced + * using the client's streaming insert (an async row generator as `values`). + * - The client is listed in `volatilePackages` so it is never webpack-bundled + * (loaded at runtime as a native dependency). + * + * References (pinned to ref=6bacb1c81e8e330ca0ee163ec06202b68a1e0591): + * - Driver: https://github.com/dbgate/dbgate/blob/6bacb1c81e8e330ca0ee163ec06202b68a1e0591/plugins/dbgate-plugin-clickhouse/src/backend/driver.js + * - volatilePackages: https://github.com/dbgate/dbgate/blob/6bacb1c81e8e330ca0ee163ec06202b68a1e0591/common/volatilePackages.js + * - Dependency: https://github.com/dbgate/dbgate/blob/6bacb1c81e8e330ca0ee163ec06202b68a1e0591/plugins/dbgate-plugin-clickhouse/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { Readable } from "node:stream"; +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / dbgate", () => { + let client: ClickHouseClient; + const table = `oss_dbgate_${guid()}`; + + // Querying surface used by the GUI grid. + async function runQuery( + c: ClickHouseClient, + query: string, + ): Promise { + const result = await c.query({ query, format: "JSONEachRow" }); + return result.json(); + } + + // createBulkInsertStream — efficient bulk loading from a streamed row source. + async function bulkInsert( + c: ClickHouseClient, + rows: Readable, + ): Promise { + await c.insert({ table, values: rows, format: "JSONEachRow" }); + } + + async function* sampleRows(): AsyncGenerator> { + for (let i = 0; i < 1000; i++) { + yield { id: i, name: `row_${i}` }; + } + } + + afterEach(async () => { + await client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await client.close(); + }); + + it("streaming bulk insert from an async row generator", async () => { + client = createTestClient(); + await client.command({ + query: `CREATE TABLE ${table} (id UInt32, name String) ENGINE = MergeTree ORDER BY id`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + await bulkInsert(client, Readable.from(sampleRows())); + + const result = await runQuery(client, `SELECT count() AS n FROM ${table}`); + expect(result).toEqual([{ n: "1000" }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/effect.test.ts b/packages/client-node/__tests__/oss-dependents/effect.test.ts new file mode 100644 index 000000000..9f25d313e --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/effect.test.ts @@ -0,0 +1,72 @@ +/** + * Effect-TS/effect — ClickHouse JS client usage example + * ===================================================== + * + * Repo: https://github.com/Effect-TS/effect (~14k★) + * Package: @clickhouse/client ^1.6.0 + * Lives in: packages/sql-clickhouse + * Analysed at: 18762540d77a79006a1cf88a78ef92c7e072b8e2 + * + * How the client is used + * ---------------------- + * `@effect/sql-clickhouse` is the official ClickHouse adapter for Effect's + * `@effect/sql` abstraction. It wraps the whole client module to expose an + * Effect-native, resource-safe SQL client with streaming. + * + * Key patterns: + * - `import * as Clickhouse from "@clickhouse/client"` (whole-module import + * wrapped behind an Effect `Client`). + * - Integrates @effect/sql/SqlClient, @effect/platform-node/NodeStream and + * @effect/experimental/Reactivity (omitted — we reproduce the + * acquire/use/release lifecycle the adapter manages). + * - The client lifecycle is managed as an Effect resource (scoped + * acquire/release). + * + * References (pinned to ref=18762540d77a79006a1cf88a78ef92c7e072b8e2): + * - Adapter: https://github.com/Effect-TS/effect/blob/18762540d77a79006a1cf88a78ef92c7e072b8e2/packages/sql-clickhouse/src/ClickhouseClient.ts + * - Dependency: https://github.com/Effect-TS/effect/blob/18762540d77a79006a1cf88a78ef92c7e072b8e2/packages/sql-clickhouse/package.json + * + * Reproduction note: the adapter acquires via `Clickhouse.createClient`; here the + * scoped resource is acquired through the test helper so it targets the test + * server. The whole-module import and acquire/use/release lifecycle are exercised. + */ + +import { describe, expect, it } from "vitest"; +// Whole-module import, exactly as the @effect/sql adapter does. +import * as Clickhouse from "@clickhouse/client"; +import { createTestClient } from "@test/utils"; + +describe("oss-dependents / effect", () => { + // The adapter manages the client as a scoped resource (acquire/release). + function acquire(): Clickhouse.ClickHouseClient { + return createTestClient(); + } + + async function release(client: Clickhouse.ClickHouseClient): Promise { + await client.close(); + } + + // `use` runs work within the resource scope, guaranteeing release. + async function scoped( + use: (client: Clickhouse.ClickHouseClient) => Promise, + ): Promise { + const client = acquire(); + try { + return await use(client); + } finally { + await release(client); + } + } + + it("whole-module import + scoped acquire/use/release", async () => { + expect(typeof Clickhouse.createClient).toBe("function"); + const rows = await scoped(async (client) => { + const result = await client.query({ + query: "SELECT 1 AS one", + format: "JSONEachRow", + }); + return result.json<{ one: number }>(); + }); + expect(rows).toEqual([{ one: 1 }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/firecrawl.test.ts b/packages/client-node/__tests__/oss-dependents/firecrawl.test.ts new file mode 100644 index 000000000..a0d8aaa88 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/firecrawl.test.ts @@ -0,0 +1,97 @@ +/** + * firecrawl/firecrawl — ClickHouse JS client usage example + * ======================================================== + * + * Repo: https://github.com/firecrawl/firecrawl (~112k★) + * Package: @clickhouse/client ^1.8.1 + * Lives in: apps/api/src/lib/clickhouse-client.ts (the scraping API service) + * Analysed at: df88fb6d5e6a328b1f8c05fcb341b78fe581dfc7 + * + * How the client is used + * ---------------------- + * ClickHouse is an OPTIONAL analytics sink. A single module creates the client + * only when the `CLICKHOUSE_ANALYTICS_URL` env var is set, otherwise it stays + * `null` and analytics writes are skipped — a defensive pattern for self-hosters + * who do not run ClickHouse. + * + * Key patterns: + * - `createClient({ url })` guarded by an env var; client may be `null`. + * - Every call site null-checks the client before inserting analytics rows. + * + * References (pinned to ref=df88fb6d5e6a328b1f8c05fcb341b78fe581dfc7): + * - Client factory: https://github.com/firecrawl/firecrawl/blob/df88fb6d5e6a328b1f8c05fcb341b78fe581dfc7/apps/api/src/lib/clickhouse-client.ts + * - Dependency: https://github.com/firecrawl/firecrawl/blob/df88fb6d5e6a328b1f8c05fcb341b78fe581dfc7/apps/api/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +interface ScrapeEvent { + url: string; + status: number; + ts: string; +} + +describe("oss-dependents / firecrawl", () => { + const table = `oss_firecrawl_${guid()}`; + + // The client is created only when analytics is configured, otherwise `null`. + function buildClient(analyticsConfigured: boolean): ClickHouseClient | null { + return analyticsConfigured ? createTestClient() : null; + } + + // Analytics writes are skipped entirely when ClickHouse is not configured. + async function logScrape( + client: ClickHouseClient | null, + event: ScrapeEvent, + ): Promise { + if (!client) return; + await client.insert({ table, values: [event], format: "JSONEachRow" }); + } + + let client: ClickHouseClient | null = null; + afterEach(async () => { + if (client) { + await client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await client.close(); + client = null; + } + }); + + it("is a no-op when analytics is disabled (null client)", async () => { + client = buildClient(false); + expect(client).toBeNull(); + await expect( + logScrape(client, { + url: "https://example.com", + status: 200, + ts: "2026-01-01 00:00:00", + }), + ).resolves.toBeUndefined(); + }); + + it("inserts analytics rows when configured", async () => { + client = buildClient(true); + expect(client).not.toBeNull(); + await client!.command({ + query: `CREATE TABLE ${table} (url String, status UInt16, ts DateTime) ENGINE = MergeTree ORDER BY ts`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + await logScrape(client, { + url: "https://example.com", + status: 200, + ts: "2026-01-01 00:00:00", + }); + + const rows = await ( + await client!.query({ + query: `SELECT url, status FROM ${table}`, + format: "JSONEachRow", + }) + ).json<{ url: string; status: number }>(); + expect(rows).toEqual([{ url: "https://example.com", status: 200 }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/growthbook.test.ts b/packages/client-node/__tests__/oss-dependents/growthbook.test.ts new file mode 100644 index 000000000..b964ccf4e --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/growthbook.test.ts @@ -0,0 +1,80 @@ +/** + * growthbook/growthbook — ClickHouse JS client usage example + * ========================================================== + * + * Repo: https://github.com/growthbook/growthbook (~8k★) + * Package: @clickhouse/client ^1.0.1 + * Lives in: packages/back-end/src/integrations/ClickHouse.ts + * Analysed at: 50f46e2a978e5ef4e321be3a8d11f551d00815b8 + * + * How the client is used + * ---------------------- + * GrowthBook (feature flags + experimentation) treats ClickHouse as a queryable + * DATA-SOURCE INTEGRATION. A single integration class issues SQL for experiment + * results and feature-usage aggregation. + * + * Key patterns: + * - `import { createClient, ResponseJSON } from '@clickhouse/client'`. + * - Queries return `ResponseJSON`; results feed feature-usage diagnostics. + * - `date-fns` used to build time-windowed queries (omitted here). + * + * References (pinned to ref=50f46e2a978e5ef4e321be3a8d11f551d00815b8): + * - Integration: https://github.com/growthbook/growthbook/blob/50f46e2a978e5ef4e321be3a8d11f551d00815b8/packages/back-end/src/integrations/ClickHouse.ts + * - Dependency: https://github.com/growthbook/growthbook/blob/50f46e2a978e5ef4e321be3a8d11f551d00815b8/packages/back-end/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient, type ResponseJSON } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / growthbook", () => { + const table = `oss_growthbook_${guid()}`; + + // Mirrors GrowthBook's data-source integration class. + class ClickHouseIntegration { + private client: ClickHouseClient; + constructor() { + this.client = createTestClient(); + } + + // Run experiment / feature-usage SQL and return the full ResponseJSON. + async runQuery(sql: string): Promise> { + const result = await this.client.query({ query: sql, format: "JSON" }); + return result.json(); + } + + async seed(): Promise { + await this.client.command({ + query: `CREATE TABLE ${table} (user_id String) ENGINE = MergeTree ORDER BY user_id`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + await this.client.insert({ + table, + values: [{ user_id: "u_1" }, { user_id: "u_1" }, { user_id: "u_2" }], + format: "JSONEachRow", + }); + } + + async close(): Promise { + await this.client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await this.client.close(); + } + } + + let integration: ClickHouseIntegration; + afterEach(async () => { + await integration.close(); + }); + + it("format: 'JSON' returns ResponseJSON with rows + data", async () => { + integration = new ClickHouseIntegration(); + await integration.seed(); + const response = await integration.runQuery<{ users: string }>( + `SELECT uniqExact(user_id) AS users FROM ${table}`, + ); + expect(response.rows).toBe(1); + expect(response.data).toEqual([{ users: "2" }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/hyperdx.test.ts b/packages/client-node/__tests__/oss-dependents/hyperdx.test.ts new file mode 100644 index 000000000..c6683c01e --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/hyperdx.test.ts @@ -0,0 +1,109 @@ +/** + * hyperdxio/hyperdx — ClickHouse JS client usage example + * ====================================================== + * + * Repo: https://github.com/hyperdxio/hyperdx (~9k★) + * Packages: @clickhouse/client, @clickhouse/client-web, @clickhouse/client-common + * — all ^1.12.1 + * Lives in: packages/common-utils/src/clickhouse + * Analysed at: 34aa906f0a102acbb66a49e91b1a5267070d3546 + * Test partner: release-test branch clickhouse-js-client-release-test + * (https://github.com/hyperdxio/hyperdx/pull/1553) + * + * How the client is used + * ---------------------- + * HyperDX is an observability UI over ClickHouse and is the ONLY repo in this + * set that uses the BROWSER client (@clickhouse/client-web). The `common-utils` + * package deliberately decouples node and browser implementations behind a + * shared base, using common types from @clickhouse/client-common. + * + * Key patterns: + * - clickhouse/node.ts -> createClient from @clickhouse/client + * - clickhouse/browser.ts -> createClient from @clickhouse/client-web + * - index.ts unifies both (NodeClickHouseClient vs WebClickHouseClient) using + * shared types from @clickhouse/client-common. + * - A `getJSNativeCreateClient` indirection so app/api packages don't import + * the client directly. + * + * References (pinned to ref=34aa906f0a102acbb66a49e91b1a5267070d3546): + * - Node client: https://github.com/hyperdxio/hyperdx/blob/34aa906f0a102acbb66a49e91b1a5267070d3546/packages/common-utils/src/clickhouse/node.ts + * - Browser client: https://github.com/hyperdxio/hyperdx/blob/34aa906f0a102acbb66a49e91b1a5267070d3546/packages/common-utils/src/clickhouse/browser.ts + * - Unified index: https://github.com/hyperdxio/hyperdx/blob/34aa906f0a102acbb66a49e91b1a5267070d3546/packages/common-utils/src/clickhouse/index.ts + * - Dependency: https://github.com/hyperdxio/hyperdx/blob/34aa906f0a102acbb66a49e91b1a5267070d3546/packages/common-utils/package.json + * + * Reproduction note: the node path runs through the shared `createTestClient` + * (works on every test environment). The browser path is constructed from the + * public `@clickhouse/client-web` surface and, on local environments, also runs a + * trivial query (the web client works under Node via global `fetch`). + */ + +import { afterEach, describe, expect, it } from "vitest"; +// Shared, environment-agnostic types come from the -common package. +import type { ClickHouseSettings } from "@clickhouse/client-common"; +import { type ClickHouseClient as NodeClickHouseClient } from "@clickhouse/client"; +import { + createClient as createWebClient, + type ClickHouseClient as WebClickHouseClient, +} from "@clickhouse/client-web"; +import { + createTestClient, + getClickHouseTestEnvironment, + TestEnv, +} from "@test/utils"; + +interface BaseClientOptions { + url: string; + database?: string; + clickhouse_settings?: ClickHouseSettings; +} + +describe("oss-dependents / hyperdx", () => { + let nodeClient: NodeClickHouseClient; + let webClient: WebClickHouseClient | undefined; + + // clickhouse/node.ts — node path uses the shared test client. + function createNodeClickHouseClient(): NodeClickHouseClient { + return createTestClient(); + } + + // clickhouse/browser.ts — browser path uses @clickhouse/client-web. + function createBrowserClickHouseClient( + options: BaseClientOptions, + ): WebClickHouseClient { + return createWebClient(options); + } + + afterEach(async () => { + await nodeClient.close(); + await webClient?.close(); + }); + + it("unifies node + browser clients behind a shared surface", async () => { + // Node path (runs on every environment). + nodeClient = createNodeClickHouseClient(); + const nodeRows = await ( + await nodeClient.query({ query: "SELECT 1 AS ok", format: "JSONEachRow" }) + ).json<{ ok: number }>(); + expect(nodeRows).toEqual([{ ok: 1 }]); + + // Browser path: construct from the public web surface to guard its exports. + const env = getClickHouseTestEnvironment(); + const url = + env === TestEnv.LocalCluster + ? "http://127.0.0.1:8127" + : "http://127.0.0.1:8123"; + webClient = createBrowserClickHouseClient({ url }); + expect(webClient).toBeDefined(); + + // The web client also runs under Node, so exercise it on local environments. + if (env !== TestEnv.Cloud) { + const webRows = await ( + await webClient.query({ + query: "SELECT 2 AS ok", + format: "JSONEachRow", + }) + ).json<{ ok: number }>(); + expect(webRows).toEqual([{ ok: 2 }]); + } + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/infisical.test.ts b/packages/client-node/__tests__/oss-dependents/infisical.test.ts new file mode 100644 index 000000000..e0d53ae23 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/infisical.test.ts @@ -0,0 +1,107 @@ +/** + * Infisical/infisical — ClickHouse JS client usage example + * ======================================================== + * + * Repo: https://github.com/Infisical/infisical (~26k★) + * Package: @clickhouse/client ^1.17.0 + * Lives in: backend/src + * Analysed at: 3d47c85f52fa33c7337ad9f328359db806073d4f + * + * How the client is used + * ---------------------- + * ClickHouse is used as the AUDIT-LOG store and is also exposed as a + * DYNAMIC-SECRET provider. The client is built from config (returns `null` when + * unconfigured), wired into the Fastify app, and has its own migration runner. + * + * Key patterns: + * - `import { type ClickHouseClient, createClient }` in a config builder + * (`buildClickHouseFromConfig`). + * - Audit-log DAL + queue for buffered writes. + * - DDL migrations (e.g. `CREATE TABLE ... generateUUIDv7()`). + * - Dynamic-secret provider creates short-lived CH credentials. + * + * References (pinned to ref=3d47c85f52fa33c7337ad9f328359db806073d4f): + * - Config builder: https://github.com/Infisical/infisical/blob/3d47c85f52fa33c7337ad9f328359db806073d4f/backend/src/lib/config/clickhouse.ts + * - Audit-log DAL: https://github.com/Infisical/infisical/blob/3d47c85f52fa33c7337ad9f328359db806073d4f/backend/src/ee/services/audit-log/audit-log-clickhouse-dal.ts + * - Migration runner: https://github.com/Infisical/infisical/blob/3d47c85f52fa33c7337ad9f328359db806073d4f/backend/src/db/clickhouse-migration-runner.ts + * - Dynamic secret: https://github.com/Infisical/infisical/blob/3d47c85f52fa33c7337ad9f328359db806073d4f/backend/src/ee/services/dynamic-secret/providers/clickhouse.ts + * - Dependency: https://github.com/Infisical/infisical/blob/3d47c85f52fa33c7337ad9f328359db806073d4f/backend/package.json + * + * Reproduction note: upstream defaults ids with `generateUUIDv7()`; we use + * `generateUUIDv4()` for broad server-version support. The `null`-when- + * unconfigured guard and the command/insert surface are what is exercised. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +interface ClickHouseConfig { + // When falsy, the audit-log store is considered unconfigured. + url?: string; +} + +describe("oss-dependents / infisical", () => { + let client: ClickHouseClient | null = null; + const table = `oss_infisical_${guid()}`; + + // buildClickHouseFromConfig — returns null when unconfigured. When configured, + // upstream calls createClient(...); here connection params come from the test + // helper, so the `url` value only drives the configured/unconfigured branch. + function buildClickHouseFromConfig( + config: ClickHouseConfig, + ): ClickHouseClient | null { + if (!config.url) return null; + return createTestClient(); + } + + // DDL migration runner. + async function runMigrations(c: ClickHouseClient): Promise { + await c.command({ + query: ` + CREATE TABLE IF NOT EXISTS ${table} ( + id UUID DEFAULT generateUUIDv4(), + actor String, + event String, + timestamp DateTime DEFAULT now() + ) ENGINE = MergeTree ORDER BY (timestamp, id) + `, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + } + + // Audit-log DAL: buffered write of audit events. + async function pushAuditLogs( + c: ClickHouseClient, + events: { actor: string; event: string }[], + ): Promise { + await c.insert({ table, values: events, format: "JSONEachRow" }); + } + + afterEach(async () => { + if (client) { + await client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await client.close(); + client = null; + } + }); + + it("returns null when unconfigured", () => { + expect(buildClickHouseFromConfig({ url: undefined })).toBeNull(); + }); + + it("migration runner + audit-log insert", async () => { + client = buildClickHouseFromConfig({ url: "configured" }); + expect(client).not.toBeNull(); + await runMigrations(client!); + await pushAuditLogs(client!, [{ actor: "user_1", event: "secret.read" }]); + + const rows = await ( + await client!.query({ + query: `SELECT actor, event FROM ${table}`, + format: "JSONEachRow", + }) + ).json<{ actor: string; event: string }>(); + expect(rows).toEqual([{ actor: "user_1", event: "secret.read" }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/langfuse.test.ts b/packages/client-node/__tests__/oss-dependents/langfuse.test.ts new file mode 100644 index 000000000..d99855edf --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/langfuse.test.ts @@ -0,0 +1,149 @@ +/** + * langfuse/langfuse — ClickHouse JS client usage example + * ====================================================== + * + * Repo: https://github.com/langfuse/langfuse (~26k★) + * Package: @clickhouse/client ^1.18.5 + * Lives in: packages/shared/src/server + * Analysed at: dee4118e8e9e672bc59a844a0ee3addd6a34a144 + * Test partner: beta release-test branch peter_leonov_ch_clickhouse_client_beta_test + * (https://github.com/langfuse/langfuse/pull/12341) + * + * How the client is used + * ---------------------- + * The DEEPEST integration in this set. ClickHouse is langfuse's analytical + * backbone for traces, observations, scores, events and sessions. The shared + * package builds a heavily-instrumented custom client and a repository layer on + * top. + * + * Key patterns: + * - `createClient({ ... })` with `ClickHouseSettings`. + * - Custom LOGGER implementing the client `Logger` interface, mapping + * ClickHouse log levels to Winston (`mapLogLevel`). + * - OpenTelemetry spans wrapped around every query (omitted here). + * - Read/write/command wrappers; `commandClickhouse` for DDL; `InsertResult`. + * - Unit tests that `vi.mock('@clickhouse/client')`. + * - Upstream also deep-imports `@clickhouse/client/dist/config` + * (NodeClickHouseClientConfigOptions), which makes it sensitive to the + * client's published file layout — flagged but intentionally NOT reproduced + * here (we depend on the public export surface only). + * + * References (pinned to ref=dee4118e8e9e672bc59a844a0ee3addd6a34a144): + * - Client factory: https://github.com/langfuse/langfuse/blob/dee4118e8e9e672bc59a844a0ee3addd6a34a144/packages/shared/src/server/clickhouse/client.ts + * - Custom logger: https://github.com/langfuse/langfuse/blob/dee4118e8e9e672bc59a844a0ee3addd6a34a144/packages/shared/src/server/clickhouse/clickhouse-logger.ts + * - Repository base: https://github.com/langfuse/langfuse/blob/dee4118e8e9e672bc59a844a0ee3addd6a34a144/packages/shared/src/server/repositories/clickhouse.ts + * - Seeder: https://github.com/langfuse/langfuse/blob/dee4118e8e9e672bc59a844a0ee3addd6a34a144/packages/shared/scripts/seeder/utils/clickhouse-builder.ts + * - Dependency: https://github.com/langfuse/langfuse/blob/dee4118e8e9e672bc59a844a0ee3addd6a34a144/packages/shared/package.json + * + * The reproduction below targets the CURRENT 1.x client API and runs against the + * test ClickHouse via the shared `createTestClient` helper (which forwards the + * langfuse-specific `clickhouse_settings` / `log` options to `createClient`). + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { + ClickHouseLogLevel, + type ClickHouseClient, + type ClickHouseSettings, + type ErrorLogParams, + type InsertResult, + type LogParams, + type Logger, +} from "@clickhouse/client"; +import { createTestClient, guid, validateUUID } from "@test/utils"; + +// Custom logger implementing the client Logger interface (maps to Winston in +// the real codebase via `mapLogLevel`). We just record what was logged. +class LangfuseClickHouseLogger implements Logger { + readonly entries: string[] = []; + trace({ module, message }: LogParams): void { + this.entries.push(`trace [${module}] ${message}`); + } + debug({ module, message }: LogParams): void { + this.entries.push(`debug [${module}] ${message}`); + } + info({ module, message }: LogParams): void { + this.entries.push(`info [${module}] ${message}`); + } + warn({ module, message }: LogParams): void { + this.entries.push(`warn [${module}] ${message}`); + } + error({ module, message }: ErrorLogParams): void { + this.entries.push(`error [${module}] ${message}`); + } +} + +function getClickhouseClient(): ClickHouseClient { + const clickhouse_settings: ClickHouseSettings = { + async_insert: 1, + wait_for_async_insert: 1, + }; + return createTestClient({ + clickhouse_settings, + log: { + level: ClickHouseLogLevel.INFO, + LoggerClass: LangfuseClickHouseLogger, + }, + }); +} + +// Repository base — read/write/command wrappers. +async function queryClickhouse( + client: ClickHouseClient, + query: string, + params?: Record, +): Promise { + const result = await client.query({ + query, + query_params: params, + format: "JSONEachRow", + }); + return result.json(); +} + +async function commandClickhouse( + client: ClickHouseClient, + query: string, +): Promise { + await client.command({ + query, + clickhouse_settings: { wait_end_of_query: 1 }, + }); +} + +// Seeder uses InsertResult. +async function insertTraces( + client: ClickHouseClient, + table: string, + rows: unknown[], +): Promise { + return client.insert({ table, values: rows, format: "JSONEachRow" }); +} + +describe("oss-dependents / langfuse", () => { + let client: ClickHouseClient; + const table = `oss_langfuse_${guid()}`; + + afterEach(async () => { + await client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await client.close(); + }); + + it("custom Logger + async_insert: command DDL, InsertResult, typed query", async () => { + client = getClickhouseClient(); + await commandClickhouse( + client, + `CREATE TABLE ${table} (id String, name String) ENGINE = MergeTree ORDER BY id`, + ); + const result = await insertTraces(client, table, [ + { id: "t_1", name: "generation" }, + ]); + expect(validateUUID(result.query_id)).toBeTruthy(); + + const rows = await queryClickhouse<{ id: string }>( + client, + `SELECT id FROM ${table} ORDER BY id`, + ); + expect(rows).toEqual([{ id: "t_1" }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/mastra.test.ts b/packages/client-node/__tests__/oss-dependents/mastra.test.ts new file mode 100644 index 000000000..4ff6d8998 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/mastra.test.ts @@ -0,0 +1,110 @@ +/** + * mastra-ai/mastra — ClickHouse JS client usage example + * ===================================================== + * + * Repo: https://github.com/mastra-ai/mastra (~23k★) + * Package: @clickhouse/client ^1.20.0 + * Lives in: stores/clickhouse + * Analysed at: 02087e1fbc54aa07f3071f7a200df1bf5be601a8 + * + * How the client is used + * ---------------------- + * ClickHouse is one of Mastra's pluggable STORAGE ADAPTERS. The + * `stores/clickhouse` package implements the framework's storage interface + * across several domains: memory (threads/messages), observability (traces, + * logs, metrics, scores, feedback), workflows and background tasks. + * + * Key patterns: + * - `import type { ClickHouseClient, ClickHouseClientConfigOptions }`. + * - A central DB module creates the client; domain modules issue typed + * reads/writes. + * - "v-next" observability domain mirrors OTel-style tracing tables. + * + * References (pinned to ref=02087e1fbc54aa07f3071f7a200df1bf5be601a8): + * - Storage entry: https://github.com/mastra-ai/mastra/blob/02087e1fbc54aa07f3071f7a200df1bf5be601a8/stores/clickhouse/src/storage/index.ts + * - DB/client module: https://github.com/mastra-ai/mastra/blob/02087e1fbc54aa07f3071f7a200df1bf5be601a8/stores/clickhouse/src/storage/db/index.ts + * - Observability: https://github.com/mastra-ai/mastra/blob/02087e1fbc54aa07f3071f7a200df1bf5be601a8/stores/clickhouse/src/storage/domains/observability/v-next/index.ts + * - Dependency: https://github.com/mastra-ai/mastra/blob/02087e1fbc54aa07f3071f7a200df1bf5be601a8/stores/clickhouse/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { + type ClickHouseClient, + type ClickHouseClientConfigOptions, +} from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / mastra", () => { + const table = `oss_mastra_messages_${guid()}`; + + // Central DB module: builds the client shared by all storage domains. + class ClickHouseStore { + private client: ClickHouseClient; + + constructor() { + // Exercise the Node config-options type, then hand it to the test helper. + const options: ClickHouseClientConfigOptions = { + clickhouse_settings: { + // Mastra relies on best-effort datetime parsing for OTel timestamps. + date_time_input_format: "best_effort", + }, + }; + this.client = createTestClient(options); + } + + // Memory domain: persist a thread message. + async saveMessage(message: { + threadId: string; + role: string; + content: string; + }): Promise { + await this.client.insert({ + table, + values: [message], + format: "JSONEachRow", + }); + } + + // Memory domain read with a parameterised filter. + async getMessages(threadId: string) { + const result = await this.client.query({ + query: `SELECT threadId, role, content FROM ${table} WHERE threadId = {threadId:String}`, + query_params: { threadId }, + format: "JSONEachRow", + }); + return result.json<{ threadId: string; role: string; content: string }>(); + } + + async createSchema(): Promise { + await this.client.command({ + query: `CREATE TABLE ${table} (threadId String, role String, content String) ENGINE = MergeTree ORDER BY threadId`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + } + + async close(): Promise { + await this.client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await this.client.close(); + } + } + + let store: ClickHouseStore; + afterEach(async () => { + await store.close(); + }); + + it("ClickHouseClientConfigOptions + best_effort, insert + parameterised read", async () => { + store = new ClickHouseStore(); + await store.createSchema(); + await store.saveMessage({ + threadId: "th_1", + role: "user", + content: "hello", + }); + expect(await store.getMessages("th_1")).toEqual([ + { threadId: "th_1", role: "user", content: "hello" }, + ]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/nango.test.ts b/packages/client-node/__tests__/oss-dependents/nango.test.ts new file mode 100644 index 000000000..3afb1ee54 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/nango.test.ts @@ -0,0 +1,77 @@ +/** + * NangoHQ/nango — ClickHouse JS client usage example + * ================================================== + * + * Repo: https://github.com/NangoHQ/nango (~7k★) + * Package: @clickhouse/client 1.18.2 (pinned, exact) + * Lives in: packages/usage/lib/clickhouse + * Analysed at: 32a588d5d4a02cba6a869654a3c849ea16d741b0 + * + * How the client is used + * ---------------------- + * Nango (integrations platform) uses ClickHouse in a dedicated `usage` package + * for METERING / BILLING. A small `config.ts` creates the client and exposes the + * `ClickHouseClient` type to the rest of the package. + * + * Key patterns: + * - `import { createClient } from '@clickhouse/client'` + `import type + * { ClickHouseClient }`. + * - Configuration driven by env parsing (reproduced with process.env here). + * - Pinned to an exact client version (1.18.2). + * + * References (pinned to ref=32a588d5d4a02cba6a869654a3c849ea16d741b0): + * - Client config: https://github.com/NangoHQ/nango/blob/32a588d5d4a02cba6a869654a3c849ea16d741b0/packages/usage/lib/clickhouse/config.ts + * - Dependency: https://github.com/NangoHQ/nango/blob/32a588d5d4a02cba6a869654a3c849ea16d741b0/packages/usage/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import type { ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / nango", () => { + const table = `oss_nango_${guid()}`; + + // config.ts — single factory consuming parsed env vars. + function createUsageClient(): ClickHouseClient { + return createTestClient(); + } + + // Metering write: record a billable usage record. + async function recordUsage( + client: ClickHouseClient, + record: { accountId: string; metric: string; value: number }, + ): Promise { + await client.insert({ table, values: [record], format: "JSONEachRow" }); + } + + let client: ClickHouseClient; + afterEach(async () => { + await client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await client.close(); + }); + + it("usage-metering insert via the config factory", async () => { + client = createUsageClient(); + await client.command({ + query: `CREATE TABLE ${table} (accountId String, metric String, value UInt64) ENGINE = MergeTree ORDER BY (accountId, metric)`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + await recordUsage(client, { + accountId: "acc_1", + metric: "records_synced", + value: 1000, + }); + + const rows = await ( + await client.query({ + query: `SELECT accountId, metric, value FROM ${table}`, + format: "JSONEachRow", + }) + ).json<{ accountId: string; metric: string; value: string }>(); + expect(rows).toEqual([ + { accountId: "acc_1", metric: "records_synced", value: "1000" }, + ]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/novu.test.ts b/packages/client-node/__tests__/oss-dependents/novu.test.ts new file mode 100644 index 000000000..b26528799 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/novu.test.ts @@ -0,0 +1,121 @@ +/** + * novuhq/novu — ClickHouse JS client usage example + * ================================================ + * + * Repo: https://github.com/novuhq/novu (~39k★) + * Package: @clickhouse/client ^1.20.0 + * Lives in: libs/application-generic/src/services/analytic-logs + * Analysed at: 215418079c02fec5fbea1304835fd75985b26ae8 + * + * How the client is used + * ---------------------- + * ClickHouse powers Novu's ANALYTIC LOGS (workflow runs, step runs, request + * logs, delivery-trend counts). The shared `application-generic` lib exposes a + * NestJS `ClickHouseService` plus a batch service, and re-exports `createClient` + * as `createClickHouseClient`. + * + * Key patterns: + * - `import { ClickHouseClient, ClickHouseSettings, createClient, PingResult }`. + * - `PingResult` used for health checks; `BeforeApplicationShutdown` lifecycle + * to close. + * - An `InsertOptions` type exposing `asyncInsert` — writes use ClickHouse + * async inserts. + * - A dedicated batch service and a seeding script with an `inserter`. + * + * References (pinned to ref=215418079c02fec5fbea1304835fd75985b26ae8): + * - Service: https://github.com/novuhq/novu/blob/215418079c02fec5fbea1304835fd75985b26ae8/libs/application-generic/src/services/analytic-logs/clickhouse.service.ts + * - Barrel: https://github.com/novuhq/novu/blob/215418079c02fec5fbea1304835fd75985b26ae8/libs/application-generic/src/services/analytic-logs/index.ts + * - Seeder: https://github.com/novuhq/novu/blob/215418079c02fec5fbea1304835fd75985b26ae8/apps/api/scripts/clickhouse-seeder/inserter.ts + * - Dependency: https://github.com/novuhq/novu/blob/215418079c02fec5fbea1304835fd75985b26ae8/libs/application-generic/package.json + * + * Reproduction note: upstream fires async inserts with `wait_for_async_insert: 0` + * (fire-and-forget); the test sets `1` so the written row is immediately + * queryable for the assertion. The async-insert + ping surface is unchanged. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { + createClient as createClickHouseClient, + type ClickHouseClient, + type ClickHouseSettings, + type PingResult, +} from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +// Barrel re-export: `createClient` is surfaced as `createClickHouseClient`. +export { createClickHouseClient }; + +interface WorkflowRunLog { + workflowId: string; + status: string; + timestamp: string; +} + +describe("oss-dependents / novu", () => { + const table = `oss_novu_${guid()}`; + + class ClickHouseService { + readonly client: ClickHouseClient; + constructor() { + this.client = createTestClient(); + } + + // Health check using PingResult. + async health(): Promise { + const result: PingResult = await this.client.ping(); + return result.success; + } + + // Writes go through ClickHouse async inserts. + async insertLogs(rows: WorkflowRunLog[]): Promise { + const clickhouse_settings: ClickHouseSettings = { + async_insert: 1, + wait_for_async_insert: 1, + }; + await this.client.insert({ + table, + values: rows, + format: "JSONEachRow", + clickhouse_settings, + }); + } + + // beforeApplicationShutdown() + async onShutdown(): Promise { + await this.client.close(); + } + } + + let service: ClickHouseService; + afterEach(async () => { + await service.client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await service.onShutdown(); + }); + + it("re-exports createClient, ping health check, async insert", async () => { + expect(typeof createClickHouseClient).toBe("function"); + + service = new ClickHouseService(); + expect(await service.health()).toBe(true); + + await service.client.command({ + query: `CREATE TABLE ${table} (workflowId String, status String, timestamp DateTime) ENGINE = MergeTree ORDER BY (workflowId, timestamp)`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + await service.insertLogs([ + { + workflowId: "wf_1", + status: "completed", + timestamp: "2026-01-01 00:00:00", + }, + ]); + + const rows = await ( + await service.client.query({ + query: `SELECT workflowId, status FROM ${table}`, + format: "JSONEachRow", + }) + ).json<{ workflowId: string; status: string }>(); + expect(rows).toEqual([{ workflowId: "wf_1", status: "completed" }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/posthog.test.ts b/packages/client-node/__tests__/oss-dependents/posthog.test.ts new file mode 100644 index 000000000..59eb16a13 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/posthog.test.ts @@ -0,0 +1,98 @@ +/** + * PostHog/posthog — ClickHouse JS client usage example + * ==================================================== + * + * Repo: https://github.com/PostHog/posthog (~33k★) + * Package: @clickhouse/client ^1.12.0 + * Lives in: nodejs/ (the TypeScript services; ClickHouse is core to PostHog) + * Analysed at: 000d0abdab8c45eb5456741c68a361562a5b8fc8 + * + * How the client is used + * ---------------------- + * ClickHouse is PostHog's primary analytics database. Within the NODE.JS + * services the JS client is used by the CDP (customer-data-platform) workers and + * the session-replay recording API to query/stream events. (The main query path + * historically goes through the Python/Django backend; the JS client covers the + * Node service surface.) + * + * Key patterns: + * - `import { ClickHouseClient, createClient as createClickHouseClient }`. + * - Custom `https` agent passed to `createClient` for connection tuning. + * - `ExecResult` + `node:stream` `Readable` in test helpers for streaming reads. + * - `jest.mock('@clickhouse/client')` with `query`/`close` stubs in unit tests. + * + * References (pinned to ref=000d0abdab8c45eb5456741c68a361562a5b8fc8): + * - Session-replay API: https://github.com/PostHog/posthog/blob/000d0abdab8c45eb5456741c68a361562a5b8fc8/nodejs/src/session-replay/recording-api/recording-api.ts + * - CDP rerun worker: https://github.com/PostHog/posthog/blob/000d0abdab8c45eb5456741c68a361562a5b8fc8/nodejs/src/cdp/consumers/cdp-rerun-worker.consumer.ts + * - Test helper: https://github.com/PostHog/posthog/blob/000d0abdab8c45eb5456741c68a361562a5b8fc8/nodejs/tests/helpers/clickhouse.ts + * - Dependency: https://github.com/PostHog/posthog/blob/000d0abdab8c45eb5456741c68a361562a5b8fc8/nodejs/package.json + * + * Reproduction note: upstream tunes connections with a `node:https` Agent (their + * endpoint is TLS). The test ClickHouse is plain HTTP, so we pass a `node:http` + * Agent here — the point under test is the `http_agent` / `keep_alive` config + * surface plus `query(...).stream()` consumed as a `Readable`. + */ + +import { Agent } from "node:http"; +import type { Readable } from "node:stream"; +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / posthog", () => { + // A custom http agent tunes connection pooling for the Node services. + const httpAgent = new Agent({ keepAlive: true, maxSockets: 10 }); + let client: ClickHouseClient; + const table = `oss_posthog_${guid()}`; + + function createConnection(): ClickHouseClient { + return createTestClient({ + http_agent: httpAgent, + // PostHog disables the client keep-alive in favour of the custom agent. + keep_alive: { enabled: false }, + }); + } + + // Session-replay recording API: stream rows for a recording. + async function streamRecording( + c: ClickHouseClient, + sessionId: string, + ): Promise { + const result = await c.query({ + query: `SELECT * FROM ${table} WHERE session_id = {sessionId:String}`, + query_params: { sessionId }, + format: "JSONEachRow", + }); + return result.stream() as unknown as Readable; + } + + afterEach(async () => { + await client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await client.close(); + httpAgent.destroy(); + }); + + it("custom http_agent + disabled keep_alive, streamed reads", async () => { + client = createConnection(); + await client.command({ + query: `CREATE TABLE ${table} (session_id String, seq UInt32) ENGINE = MergeTree ORDER BY (session_id, seq)`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + await client.insert({ + table, + values: [ + { session_id: "sess_1", seq: 1 }, + { session_id: "sess_1", seq: 2 }, + { session_id: "sess_2", seq: 1 }, + ], + format: "JSONEachRow", + }); + + const stream = await streamRecording(client, "sess_1"); + let rowCount = 0; + for await (const rows of stream) { + rowCount += (rows as unknown[]).length; // each chunk is an array of Row objects + } + expect(rowCount).toBe(2); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/rybbit.test.ts b/packages/client-node/__tests__/oss-dependents/rybbit.test.ts new file mode 100644 index 000000000..1b590c75e --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/rybbit.test.ts @@ -0,0 +1,98 @@ +/** + * rybbit-io/rybbit — ClickHouse JS client usage example + * ===================================================== + * + * Repo: https://github.com/rybbit-io/rybbit (~12k★) + * Package: @clickhouse/client 1.11.1 (pinned, exact) + * Lives in: server/src/db/clickhouse + * Analysed at: d92e3f274121f1910c9259747c8045bd74a21792 + * + * How the client is used + * ---------------------- + * Rybbit is an open-source web/product-analytics platform; ClickHouse is its + * event store. A single `clickhouse.ts` module creates the client and an + * `initializeClickhouse()` routine bootstraps the ENTIRE SCHEMA — base tables, + * `ALTER TABLE` migrations, and a large set of MATERIALIZED VIEWS (streaming and + * `REFRESH EVERY` refreshable MVs) that power the dashboard. + * + * Key patterns: + * - `createClient({ url, database, password, request_timeout: 300_000 })` — + * long request timeout for heavy queries. + * - Schema/DDL applied entirely through `client.exec({ query, + * clickhouse_settings })`. + * - `ResultSet` type used in query utilities; deployment flags (IS_CLOUD, + * LITE_DASHBOARD) toggle which MVs are created. + * + * References (pinned to ref=d92e3f274121f1910c9259747c8045bd74a21792): + * - Client + bootstrap: https://github.com/rybbit-io/rybbit/blob/d92e3f274121f1910c9259747c8045bd74a21792/server/src/db/clickhouse/clickhouse.ts + * - Query utils: https://github.com/rybbit-io/rybbit/blob/d92e3f274121f1910c9259747c8045bd74a21792/server/src/api/analytics/utils/utils.ts + * - Dependency: https://github.com/rybbit-io/rybbit/blob/d92e3f274121f1910c9259747c8045bd74a21792/server/package.json + * + * Reproduction note: upstream uses a `REFRESH EVERY ...` refreshable MV (an + * experimental feature). To keep the test portable across server versions we use + * a standard incremental MV (`POPULATE`); the surface under test — DDL via + * `exec`, `request_timeout`, and `ResultSet` — is unchanged. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient, type ResultSet } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / rybbit", () => { + let client: ClickHouseClient; + const events = `oss_rybbit_events_${guid()}`; + const mv = `oss_rybbit_events_hourly_${guid()}`; + + // initializeClickhouse() — all DDL applied via client.exec(). + async function initializeClickhouse(): Promise { + const ddl = [ + `CREATE TABLE IF NOT EXISTS ${events} ( + site_id UInt32, type String, timestamp DateTime + ) ENGINE = MergeTree ORDER BY (site_id, timestamp)`, + // A materialized view powering the dashboard. + `CREATE MATERIALIZED VIEW IF NOT EXISTS ${mv} + ENGINE = SummingMergeTree ORDER BY (site_id, hour) POPULATE AS + SELECT site_id, toStartOfHour(timestamp) AS hour, count() AS hits + FROM ${events} GROUP BY site_id, hour`, + ]; + for (const query of ddl) { + const { stream } = await client.exec({ + query, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + stream.destroy(); + } + } + + // Query utility typed against ResultSet. + async function rawQuery(query: string): Promise> { + return client.query({ query, format: "JSONEachRow" }); + } + + afterEach(async () => { + await client.command({ query: `DROP VIEW IF EXISTS ${mv}` }); + await client.command({ query: `DROP TABLE IF EXISTS ${events}` }); + await client.close(); + }); + + it("exec-based DDL + materialized view, ResultSet query util", async () => { + client = createTestClient({ request_timeout: 300_000 }); + await initializeClickhouse(); + + await client.insert({ + table: events, + values: [ + { site_id: 1, type: "pageview", timestamp: "2026-01-01 00:00:00" }, + { site_id: 1, type: "pageview", timestamp: "2026-01-01 00:30:00" }, + ], + format: "JSONEachRow", + }); + + const result = await rawQuery(`SELECT count() AS n FROM ${events}`); + expect(await result.json<{ n: string }>()).toEqual([{ n: "2" }]); + + // The MV aggregated both events into a single hourly bucket. + const hourly = await rawQuery(`SELECT sum(hits) AS hits FROM ${mv}`); + expect(await hourly.json<{ hits: string }>()).toEqual([{ hits: "2" }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/tooljet.test.ts b/packages/client-node/__tests__/oss-dependents/tooljet.test.ts new file mode 100644 index 000000000..ca3fca4b3 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/tooljet.test.ts @@ -0,0 +1,80 @@ +/** + * ToolJet/ToolJet — ClickHouse JS client usage example + * ==================================================== + * + * Repo: https://github.com/ToolJet/ToolJet (~38k★) + * Package: @clickhouse/client ^1.14.0 + * Lives in: plugins/packages/clickhouse + * Analysed at: 2eb07546370d1c4959f16ab16a4d96cbea79a7e1 + * + * How the client is used + * ---------------------- + * ClickHouse is a first-party DATA-SOURCE CONNECTOR plugin for ToolJet's + * low-code builder. The plugin implements the `QueryService` interface so app + * builders can run arbitrary ClickHouse queries from the visual editor. + * + * Key patterns: + * - `import { createClient } from '@clickhouse/client'`. + * - Implements `QueryService` with `run()` and a `testConnection()` + * (`ConnectionTestResult`). + * - Uses `node-sql-parser` alongside the client to inspect/route SQL (omitted + * here — the connector contract is what matters for the test). + * + * References (pinned to ref=2eb07546370d1c4959f16ab16a4d96cbea79a7e1): + * - Plugin entry: https://github.com/ToolJet/ToolJet/blob/2eb07546370d1c4959f16ab16a4d96cbea79a7e1/plugins/packages/clickhouse/lib/index.ts + * - Dependency: https://github.com/ToolJet/ToolJet/blob/2eb07546370d1c4959f16ab16a4d96cbea79a7e1/plugins/packages/clickhouse/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient } from "@test/utils"; + +interface ConnectionTestResult { + status: "ok" | "failed"; + message?: string; +} + +describe("oss-dependents / tooljet", () => { + // Mirrors ToolJet's QueryService contract for the ClickHouse connector plugin. + // The service holds one pooled client for its lifetime; `run`/`testConnection` + // exercise the query/ping surface and the client is closed once on teardown. + class ClickhouseQueryService { + private client: ClickHouseClient | undefined; + private getConnection(): ClickHouseClient { + if (!this.client) this.client = createTestClient(); + return this.client; + } + + async run(query: string): Promise { + const result = await this.getConnection().query({ + query, + format: "JSONEachRow", + }); + return result.json(); + } + + async testConnection(): Promise { + const ping = await this.getConnection().ping(); + return ping.success + ? { status: "ok" } + : { status: "failed", message: ping.error.message }; + } + + async close(): Promise { + await this.client?.close(); + } + } + + let service: ClickhouseQueryService; + afterEach(async () => { + await service.close(); + }); + + it("QueryService contract: testConnection + run", async () => { + service = new ClickhouseQueryService(); + expect(await service.testConnection()).toEqual({ status: "ok" }); + expect(await service.run("SELECT 1 AS ok")).toEqual([{ ok: 1 }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/trigger-dev.test.ts b/packages/client-node/__tests__/oss-dependents/trigger-dev.test.ts new file mode 100644 index 000000000..c670393ed --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/trigger-dev.test.ts @@ -0,0 +1,93 @@ +/** + * triggerdotdev/trigger.dev — ClickHouse JS client usage example + * ============================================================== + * + * Repo: https://github.com/triggerdotdev/trigger.dev (~15k★) + * Package: @clickhouse/client ^1.12.1 + * Lives in: internal-packages/clickhouse + * Analysed at: ae08c9cb600b00256440bccb336745f01acdf60b + * + * How the client is used + * ---------------------- + * trigger.dev wraps the client in a dedicated internal package that backs the + * RUN/EVENT store and analytics surfaces (run list, metrics, data export). The + * package exposes a high-level `ClickHouse` class split into reader and writer + * roles, and a TSQL layer that sanitises errors and maps schema values. + * + * Key patterns: + * - A `ClickHouse` class with `reader`/`writer` and an injected `Logger`. + * - `ClickhouseCommonConfig` (url/readerUrl) to split read vs write endpoints. + * - TSQL helpers with ClickHouse-internals-to-user-friendly error sanitisation. + * + * References (pinned to ref=ae08c9cb600b00256440bccb336745f01acdf60b): + * - Package entry: https://github.com/triggerdotdev/trigger.dev/blob/ae08c9cb600b00256440bccb336745f01acdf60b/internal-packages/clickhouse/src/index.ts + * - TSQL layer: https://github.com/triggerdotdev/trigger.dev/blob/ae08c9cb600b00256440bccb336745f01acdf60b/internal-packages/clickhouse/src/client/tsql.ts + * - Webapp factory: https://github.com/triggerdotdev/trigger.dev/blob/ae08c9cb600b00256440bccb336745f01acdf60b/apps/webapp/app/services/clickhouse/clickhouseFactory.server.ts + * - Dependency: https://github.com/triggerdotdev/trigger.dev/blob/ae08c9cb600b00256440bccb336745f01acdf60b/internal-packages/clickhouse/package.json + * + * Reproduction note: reader and writer both point at the test server (the + * read-replica split is the surface under test, not a separate endpoint). + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / trigger.dev", () => { + const table = `oss_trigger_dev_${guid()}`; + + // Reader/writer split so reads can target a replica. + class ClickHouse { + readonly reader: ClickHouseClient; + readonly writer: ClickHouseClient; + + constructor() { + this.writer = createTestClient(); + this.reader = createTestClient(); + } + + async createSchema(): Promise { + await this.writer.command({ + query: `CREATE TABLE ${table} (runId String, event String) ENGINE = MergeTree ORDER BY runId`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + } + + async insertRunEvents( + rows: { runId: string; event: string }[], + ): Promise { + await this.writer.insert({ table, values: rows, format: "JSONEachRow" }); + } + + async listRuns(): Promise<{ runId: string }[]> { + const result = await this.reader.query({ + query: `SELECT runId FROM ${table} ORDER BY runId`, + format: "JSONEachRow", + }); + return result.json<{ runId: string }>(); + } + + async close(): Promise { + await this.writer.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await Promise.all([this.reader.close(), this.writer.close()]); + } + } + + let ch: ClickHouse; + afterEach(async () => { + await ch.close(); + }); + + it("reader/writer split: write via writer, read via reader", async () => { + ch = new ClickHouse(); + await ch.createSchema(); + await ch.insertRunEvents([ + { runId: "run_1", event: "started" }, + { runId: "run_2", event: "started" }, + ]); + expect(await ch.listRuns()).toEqual([ + { runId: "run_1" }, + { runId: "run_2" }, + ]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/twenty.test.ts b/packages/client-node/__tests__/oss-dependents/twenty.test.ts new file mode 100644 index 000000000..ec35baec4 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/twenty.test.ts @@ -0,0 +1,95 @@ +/** + * twentyhq/twenty — ClickHouse JS client usage example + * ==================================================== + * + * Repo: https://github.com/twentyhq/twenty (~45k★) + * Package: @clickhouse/client ^1.18.1 + * Lives in: packages/twenty-server/src/database/clickHouse + * Analysed at: f96e36d3e67510eaf81ee130d8d56c3db563ec3f + * + * How the client is used + * ---------------------- + * ClickHouse backs the CRM's EVENT-LOG analytics. A dedicated + * `clickHouse.service.ts` creates the client; there is a full lifecycle around + * it: migrations runner, seed runner, and integration test suites that write + * object / workspace events. + * + * Key patterns: + * - `import { type ClickHouseClient, ClickHouseLogLevel, createClient }`. + * - `ClickHouseLogLevel` passed to `createClient` to control client logging. + * - Migrations (`run-migrations.ts`) and seeds (`run-seeds.ts`) share the same + * import surface. + * - Service is mocked in unit tests via `jest.mock('@clickhouse/client')`. + * + * References (pinned to ref=f96e36d3e67510eaf81ee130d8d56c3db563ec3f): + * - Service: https://github.com/twentyhq/twenty/blob/f96e36d3e67510eaf81ee130d8d56c3db563ec3f/packages/twenty-server/src/database/clickHouse/clickHouse.service.ts + * - Migrations: https://github.com/twentyhq/twenty/blob/f96e36d3e67510eaf81ee130d8d56c3db563ec3f/packages/twenty-server/src/database/clickHouse/migrations/run-migrations.ts + * - Seeds: https://github.com/twentyhq/twenty/blob/f96e36d3e67510eaf81ee130d8d56c3db563ec3f/packages/twenty-server/src/database/clickHouse/seeds/run-seeds.ts + * - Dependency: https://github.com/twentyhq/twenty/blob/f96e36d3e67510eaf81ee130d8d56c3db563ec3f/packages/twenty-server/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse. + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { ClickHouseLogLevel, type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / twenty", () => { + let client: ClickHouseClient; + const table = `oss_twenty_${guid()}`; + + function createCrmClient(): ClickHouseClient { + return createTestClient({ + // Control client logging verbosity via the exported enum. + log: { level: ClickHouseLogLevel.WARN }, + }); + } + + // run-migrations.ts — shares the same import surface as the service. + async function runMigrations(c: ClickHouseClient): Promise { + await c.command({ + query: ` + CREATE TABLE IF NOT EXISTS ${table} ( + workspaceId String, + name String, + timestamp DateTime + ) ENGINE = MergeTree ORDER BY (workspaceId, timestamp) + `, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + } + + // run-seeds.ts — write some workspace/object events. + async function runSeeds(c: ClickHouseClient): Promise { + await c.insert({ + table, + values: [ + { + workspaceId: "ws_1", + name: "company.created", + timestamp: "2026-01-01 00:00:00", + }, + ], + format: "JSONEachRow", + }); + } + + afterEach(async () => { + await client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await client.close(); + }); + + it("ClickHouseLogLevel config, command migrations + insert seeds", async () => { + client = createCrmClient(); + await runMigrations(client); + await runSeeds(client); + + const rows = await ( + await client.query({ + query: `SELECT workspaceId, name FROM ${table}`, + format: "JSONEachRow", + }) + ).json<{ workspaceId: string; name: string }>(); + expect(rows).toEqual([{ workspaceId: "ws_1", name: "company.created" }]); + }); +}); diff --git a/packages/client-node/__tests__/oss-dependents/umami.test.ts b/packages/client-node/__tests__/oss-dependents/umami.test.ts new file mode 100644 index 000000000..e56d0ff51 --- /dev/null +++ b/packages/client-node/__tests__/oss-dependents/umami.test.ts @@ -0,0 +1,110 @@ +/** + * umami-software/umami — ClickHouse JS client usage example + * ========================================================= + * + * Repo: https://github.com/umami-software/umami (~36k★) + * Package: @clickhouse/client ^1.18.2 + * Lives in: src/lib/clickhouse.ts + * Analysed at: c0ea3aefbee7a3429ee2f824b06dc4a9dbe0b7e1 + * + * How the client is used + * ---------------------- + * Umami is a privacy-focused web-analytics app; ClickHouse is its optional + * high-volume event store (alternative to Postgres/MySQL). A single + * `src/lib/clickhouse.ts` module builds the client and exposes typed query + * helpers that translate Umami's `QueryFilters`/`QueryOptions` into ClickHouse + * SQL. + * + * Key patterns: + * - `import { type ClickHouseClient, createClient } from '@clickhouse/client'`. + * - Centralised filter -> SQL translation (FILTER_COLUMNS, OPERATORS) feeding + * `query`/`insert`. + * - Timezone handling via `date-fns-tz` around ClickHouse `DateTime` values + * (omitted here — the query/insert surface is what the test exercises). + * + * References (pinned to ref=c0ea3aefbee7a3429ee2f824b06dc4a9dbe0b7e1): + * - ClickHouse layer: https://github.com/umami-software/umami/blob/c0ea3aefbee7a3429ee2f824b06dc4a9dbe0b7e1/src/lib/clickhouse.ts + * - Dependency: https://github.com/umami-software/umami/blob/c0ea3aefbee7a3429ee2f824b06dc4a9dbe0b7e1/package.json + * + * Reproduction targets the current 1.x API and runs against the test ClickHouse + * via the shared `createTestClient` helper (the lazy singleton below). + */ + +import { afterEach, describe, expect, it } from "vitest"; +import { type ClickHouseClient } from "@clickhouse/client"; +import { createTestClient, guid } from "@test/utils"; + +describe("oss-dependents / umami", () => { + // Mirrors umami's lazy module-level singleton. + let client: ClickHouseClient | undefined; + function getClient(): ClickHouseClient { + if (!client) { + client = createTestClient(); + } + return client; + } + + const table = `oss_umami_${guid()}`; + + interface WebsiteEvent { + website_id: string; + session_id: string; + event_name: string; + created_at: string; + } + + async function saveEvent(event: WebsiteEvent): Promise { + await getClient().insert({ table, values: [event], format: "JSONEachRow" }); + } + + // Typed read helper translating analytics filters into parameterised SQL. + async function getPageViews( + websiteId: string, + startAt: string, + endAt: string, + ) { + const result = await getClient().query({ + query: ` + SELECT event_name, count() AS views + FROM ${table} + WHERE website_id = {websiteId:String} + AND created_at BETWEEN {startAt:DateTime} AND {endAt:DateTime} + GROUP BY event_name + `, + query_params: { websiteId, startAt, endAt }, + format: "JSONEachRow", + }); + return result.json<{ event_name: string; views: string }>(); + } + + afterEach(async () => { + if (client) { + await client.command({ query: `DROP TABLE IF EXISTS ${table}` }); + await client.close(); + client = undefined; + } + }); + + it("parameterised query (String + DateTime) + insert", async () => { + await getClient().command({ + query: `CREATE TABLE ${table} ( + website_id String, session_id String, event_name String, created_at DateTime + ) ENGINE = MergeTree ORDER BY (website_id, created_at)`, + clickhouse_settings: { wait_end_of_query: 1 }, + }); + + await saveEvent({ + website_id: "w_1", + session_id: "s_1", + event_name: "pageview", + created_at: "2026-01-01 00:00:00", + }); + + const rows = await getPageViews( + "w_1", + "2026-01-01 00:00:00", + "2026-12-31 23:59:59", + ); + expect(rows).toEqual([{ event_name: "pageview", views: "1" }]); + }); +}); diff --git a/packages/client-node/__tests__/unit/node_client.test.ts b/packages/client-node/__tests__/unit/node_client.test.ts index 013170788..1b2c15b1c 100644 --- a/packages/client-node/__tests__/unit/node_client.test.ts +++ b/packages/client-node/__tests__/unit/node_client.test.ts @@ -53,8 +53,8 @@ describe("[Node.js] createClient", () => { request_timeout: 42_000, max_open_connections: 10, compression: { - compress_request: false, - decompress_response: false, + compress_request: undefined, + decompress_response: undefined, }, auth: { username: "bob", password: "secret", type: "Credentials" }, database: "analytics", diff --git a/packages/client-node/__tests__/unit/node_config.test.ts b/packages/client-node/__tests__/unit/node_config.test.ts index 02e4c3fda..8f20b339c 100644 --- a/packages/client-node/__tests__/unit/node_config.test.ts +++ b/packages/client-node/__tests__/unit/node_config.test.ts @@ -8,6 +8,7 @@ import { ClickHouseLogLevel, LogWriter } from "@clickhouse/client-common"; import { TestLogger } from "../../../client-common/__tests__/utils/test_logger"; import { Buffer } from "buffer"; import http from "http"; +import Zlib from "zlib"; import type { NodeClickHouseClientConfigOptions } from "../../src/config"; import { NodeConfigImpl } from "../../src/config"; import { @@ -70,8 +71,8 @@ describe("[Node.js] Config implementation details", () => { request_timeout: 1000, max_open_connections: 10, compression: { - compress_request: true, - decompress_response: true, + compress_request: { codec: "gzip" }, + decompress_response: { codec: "gzip" }, }, auth: { username: "alice", @@ -97,6 +98,97 @@ describe("[Node.js] Config implementation details", () => { vi.clearAllMocks(); }); + describe("compression codec guard", () => { + function withMissingZlibFn( + name: "createZstdCompress" | "createZstdDecompress", + fn: () => void, + ) { + const descriptor = Object.getOwnPropertyDescriptor(Zlib, name); + Object.defineProperty(Zlib, name, { + value: undefined, + configurable: true, + writable: true, + }); + try { + fn(); + } finally { + if (descriptor) { + Object.defineProperty(Zlib, name, descriptor); + } else { + delete (Zlib as unknown as Record)[name]; + } + } + } + + const nodeConfig: NodeClickHouseClientConfigOptions = { + url: new URL("http://localhost:8123"), + }; + + it("throws when zstd request compression is unsupported by the runtime", () => { + withMissingZlibFn("createZstdCompress", () => { + expect(() => + NodeConfigImpl.make_connection(nodeConfig as any, { + ...params, + compression: { + compress_request: { codec: "zstd" }, + decompress_response: undefined, + }, + }), + ).toThrow(/zstd compression is not supported/); + }); + }); + + it("throws when zstd response decompression is unsupported by the runtime", () => { + withMissingZlibFn("createZstdDecompress", () => { + expect(() => + NodeConfigImpl.make_connection(nodeConfig as any, { + ...params, + compression: { + compress_request: undefined, + decompress_response: { codec: "zstd" }, + }, + }), + ).toThrow(/zstd compression is not supported/); + }); + }); + + it("does not throw for gzip / boolean compression", () => { + expect(() => + NodeConfigImpl.make_connection(nodeConfig as any, { + ...params, + compression: { + compress_request: { codec: "gzip" }, + decompress_response: { codec: "gzip" }, + }, + }), + ).not.toThrow(); + }); + + it("throws for an unknown codec", () => { + expect(() => + NodeConfigImpl.make_connection(nodeConfig as any, { + ...params, + compression: { + compress_request: { codec: "lz4" } as any, + decompress_response: undefined, + }, + }), + ).toThrow(/Unknown request compression codec/); + }); + + it("does not throw for br compression", () => { + expect(() => + NodeConfigImpl.make_connection(nodeConfig as any, { + ...params, + compression: { + compress_request: { codec: "br" }, + decompress_response: { codec: "br" }, + }, + }), + ).not.toThrow(); + }); + }); + it("should create a connection with default KeepAlive settings", async () => { const nodeConfig: NodeClickHouseClientConfigOptions = { url: new URL("http://localhost:8123"), diff --git a/packages/client-node/__tests__/unit/node_connection.test.ts b/packages/client-node/__tests__/unit/node_connection.test.ts index 7ca89df93..dbdfe1d24 100644 --- a/packages/client-node/__tests__/unit/node_connection.test.ts +++ b/packages/client-node/__tests__/unit/node_connection.test.ts @@ -45,8 +45,8 @@ describe("[Node.js] Connection", () => { it("should generate random query_id for each query", async () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); @@ -86,8 +86,8 @@ describe("[Node.js] Connection", () => { it("should use provided query_id for query", async () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); @@ -115,8 +115,8 @@ describe("[Node.js] Connection", () => { it("should generate random query_id for every exec request", async () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); @@ -157,8 +157,8 @@ describe("[Node.js] Connection", () => { it("should use provided query_id for exec", async () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); @@ -185,8 +185,8 @@ describe("[Node.js] Connection", () => { it("should generate random query_id for every command request", async () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); @@ -220,8 +220,8 @@ describe("[Node.js] Connection", () => { it("should use provided query_id for command", async () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); @@ -247,8 +247,8 @@ describe("[Node.js] Connection", () => { it("should generate random query_id for every insert request", async () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); @@ -290,8 +290,8 @@ describe("[Node.js] Connection", () => { it("should use provided query_id for insert", async () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); diff --git a/packages/client-node/__tests__/unit/node_connection_compression.test.ts b/packages/client-node/__tests__/unit/node_connection_compression.test.ts index cd541ad29..00f7a5c17 100644 --- a/packages/client-node/__tests__/unit/node_connection_compression.test.ts +++ b/packages/client-node/__tests__/unit/node_connection_compression.test.ts @@ -3,7 +3,14 @@ import { sleep } from "../utils/sleep"; import Http, { type ClientRequest } from "http"; import Stream from "stream"; import Zlib from "zlib"; +import { ClickHouseLogLevel, LogWriter } from "@clickhouse/client-common"; +import { TestLogger } from "../../../client-common/__tests__/utils/test_logger"; import { assertConnQueryResult } from "../utils/assert"; +import { + createRequestCompressor, + decompressResponse, + isDecompressionError, +} from "../../src/connection/compression"; import { buildHttpConnection, buildIncomingMessage, @@ -13,6 +20,12 @@ import { stubClientRequest, } from "../utils/http_stubs"; +const zstdSupported = + typeof Zlib.createZstdCompress === "function" && + typeof Zlib.createZstdDecompress === "function" && + typeof Zlib.zstdCompressSync === "function" && + typeof Zlib.zstdDecompress === "function"; + beforeEach(() => { vi.clearAllMocks(); }); @@ -27,8 +40,8 @@ describe("Node.js Connection compression", () => { const adapter = buildHttpConnection({ compression: { - decompress_response: true, - compress_request: false, + decompress_response: { codec: "gzip" }, + compress_request: undefined, }, }); @@ -55,8 +68,8 @@ describe("Node.js Connection compression", () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); @@ -86,8 +99,8 @@ describe("Node.js Connection compression", () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, }); @@ -118,8 +131,8 @@ describe("Node.js Connection compression", () => { const adapter = buildHttpConnection({ compression: { - decompress_response: true, - compress_request: false, + decompress_response: { codec: "gzip" }, + compress_request: undefined, }, }); @@ -134,13 +147,58 @@ describe("Node.js Connection compression", () => { await assertConnQueryResult(queryResult, responseBody); }); + it("returns a clear error for a zstd response on a runtime without zstd support", () => { + // Simulate a Node.js runtime whose zlib lacks the zstd APIs (< 22.15.0). + const original = Object.getOwnPropertyDescriptor( + Zlib, + "createZstdDecompress", + ); + Object.defineProperty(Zlib, "createZstdDecompress", { + value: undefined, + configurable: true, + }); + try { + const response = buildIncomingMessage({ + body: "anything", + headers: { "content-encoding": "zstd" }, + }); + const logWriter = new LogWriter( + new TestLogger(), + "test", + ClickHouseLogLevel.OFF, + ); + const result = decompressResponse( + response, + logWriter, + ClickHouseLogLevel.OFF, + ); + expect(isDecompressionError(result)).toBe(true); + expect((result as { error: Error }).error.message).toContain( + "does not support zstd decompression", + ); + expect((result as { error: Error }).error.message).not.toContain( + "Unexpected encoding", + ); + } finally { + if (original) { + Object.defineProperty(Zlib, "createZstdDecompress", original); + } else { + // No original descriptor (runtime genuinely lacks zstd): remove the + // stub we added instead of leaving an `undefined` property behind. + delete (Zlib as unknown as Record)[ + "createZstdDecompress" + ]; + } + } + }); + it("throws on an unexpected encoding", async () => { const request = stubClientRequest(); httpRequestStub.mockReturnValue(request); const adapter = buildHttpConnection({ compression: { - decompress_response: true, - compress_request: false, + decompress_response: { codec: "gzip" }, + compress_request: undefined, }, }); @@ -148,11 +206,21 @@ describe("Node.js Connection compression", () => { query: "SELECT * FROM system.numbers LIMIT 5", }); - await emitCompressedBody(request, "abc", "br"); + // An unknown `Content-Encoding` is rejected before any decompression is + // attempted, so the body is sent as-is (uncompressed) - no codec the + // helper knows about is involved. + await sleep(0); + request.emit( + "response", + buildIncomingMessage({ + body: "abc", + headers: { "content-encoding": "lz4" }, + }), + ); await expect(selectPromise).rejects.toEqual( expect.objectContaining({ - message: "Unexpected encoding: br", + message: "Unexpected encoding: lz4", }), ); }); @@ -162,8 +230,8 @@ describe("Node.js Connection compression", () => { httpRequestStub.mockReturnValue(request); const adapter = buildHttpConnection({ compression: { - decompress_response: true, - compress_request: false, + decompress_response: { codec: "gzip" }, + compress_request: undefined, }, }); @@ -197,14 +265,89 @@ describe("Node.js Connection compression", () => { }), ); }); + + it.skipIf(!zstdSupported)( + 'decompresses a zstd response and sends Accept-Encoding: zstd if response: "zstd"', + async () => { + const request = stubClientRequest(); + httpRequestStub.mockReturnValue(request); + + const adapter = buildHttpConnection({ + compression: { + decompress_response: { codec: "zstd" }, + compress_request: undefined, + }, + }); + + const selectPromise = adapter.query({ + query: "SELECT * FROM system.numbers LIMIT 5", + }); + + const responseBody = "foobar"; + await sleep(0); + request.emit( + "response", + buildIncomingMessage({ + body: Zlib.zstdCompressSync(Buffer.from(responseBody)), + headers: { "content-encoding": "zstd" }, + }), + ); + + const queryResult = await selectPromise; + await assertConnQueryResult(queryResult, responseBody); + + expect(httpRequestStub).toHaveBeenCalledTimes(1); + const calledWith = + httpRequestStub.mock.calls[httpRequestStub.mock.calls.length - 1][1]; + expect( + (calledWith.headers as Record)["Accept-Encoding"], + ).toBe("zstd"); + }, + ); + + it('decompresses a br response and sends Accept-Encoding: br if response: { codec: "br" }', async () => { + const request = stubClientRequest(); + httpRequestStub.mockReturnValue(request); + + const adapter = buildHttpConnection({ + compression: { + decompress_response: { codec: "br" }, + compress_request: undefined, + }, + }); + + const selectPromise = adapter.query({ + query: "SELECT * FROM system.numbers LIMIT 5", + }); + + const responseBody = "foobar"; + await sleep(0); + request.emit( + "response", + buildIncomingMessage({ + body: Zlib.brotliCompressSync(Buffer.from(responseBody)), + headers: { "content-encoding": "br" }, + }), + ); + + const queryResult = await selectPromise; + await assertConnQueryResult(queryResult, responseBody); + + expect(httpRequestStub).toHaveBeenCalledTimes(1); + const calledWith = + httpRequestStub.mock.calls[httpRequestStub.mock.calls.length - 1][1]; + expect( + (calledWith.headers as Record)["Accept-Encoding"], + ).toBe("br"); + }); }); describe("request compression", () => { it("sends a compressed request if compress_request: true", async () => { const adapter = buildHttpConnection({ compression: { - decompress_response: false, - compress_request: true, + decompress_response: undefined, + compress_request: { codec: "gzip" }, }, }); @@ -243,5 +386,194 @@ describe("Node.js Connection compression", () => { (calledWith.headers as Record)["Content-Encoding"], ).toBe("gzip"); }); + + it.skipIf(!zstdSupported)( + 'sends a zstd-compressed request if compress_request: "zstd"', + async () => { + const adapter = buildHttpConnection({ + compression: { + decompress_response: undefined, + compress_request: { codec: "zstd" }, + }, + }); + + const values = "abc".repeat(1_000); + + let chunks = Buffer.alloc(0); + let resolveResult!: (value: Buffer) => void; + let rejectResult!: (reason: Error) => void; + const decompressed = new Promise((resolve, reject) => { + resolveResult = resolve; + rejectResult = reject; + }); + const request = new Stream.Writable({ + write(chunk, encoding, next) { + chunks = Buffer.concat([chunks, chunk]); + next(); + }, + final(callback) { + Zlib.zstdDecompress(chunks, (err, result) => { + callback(err); + if (err) { + rejectResult(err); + } else { + resolveResult(result); + } + }); + }, + }) as ClientRequest; + httpRequestStub.mockReturnValue(request); + + void adapter.insert({ + query: "INSERT INTO insert_compression_table", + values, + }); + + // trigger stream pipeline + await sleep(0); + request.emit("socket", socketStub); + + const finalResult = await decompressed; + expect(finalResult.toString("utf8")).toEqual(values); + expect(httpRequestStub).toHaveBeenCalledTimes(1); + const calledWith = + httpRequestStub.mock.calls[httpRequestStub.mock.calls.length - 1][1]; + expect( + (calledWith.headers as Record)["Content-Encoding"], + ).toBe("zstd"); + }, + ); + + it('sends a br-compressed request if compress_request is { codec: "br" }', async () => { + const adapter = buildHttpConnection({ + compression: { + decompress_response: undefined, + compress_request: { codec: "br" }, + }, + }); + + const values = "abc".repeat(1_000); + + let chunks = Buffer.alloc(0); + let resolveResult!: (value: Buffer) => void; + let rejectResult!: (reason: Error) => void; + const decompressed = new Promise((resolve, reject) => { + resolveResult = resolve; + rejectResult = reject; + }); + const request = new Stream.Writable({ + write(chunk, encoding, next) { + chunks = Buffer.concat([chunks, chunk]); + next(); + }, + final(callback) { + Zlib.brotliDecompress(chunks, (err, result) => { + callback(err); + if (err) { + rejectResult(err); + } else { + resolveResult(result); + } + }); + }, + }) as ClientRequest; + httpRequestStub.mockReturnValue(request); + + void adapter.insert({ + query: "INSERT INTO insert_compression_table", + values, + }); + + await sleep(0); + request.emit("socket", socketStub); + + const finalResult = await decompressed; + expect(finalResult.toString("utf8")).toEqual(values); + expect(httpRequestStub).toHaveBeenCalledTimes(1); + const calledWith = + httpRequestStub.mock.calls[httpRequestStub.mock.calls.length - 1][1]; + expect( + (calledWith.headers as Record)["Content-Encoding"], + ).toBe("br"); + }); + }); +}); + +describe("createRequestCompressor", () => { + async function roundTrip( + compressor: Stream.Transform, + decompress: (buf: Buffer) => Buffer, + input: string, + ): Promise { + const chunks: Buffer[] = []; + compressor.on("data", (chunk: Buffer) => chunks.push(chunk)); + const done = new Promise((resolve, reject) => { + compressor.on("end", resolve); + compressor.on("error", reject); + }); + compressor.end(Buffer.from(input)); + await done; + return decompress(Buffer.concat(chunks)).toString("utf8"); + } + + it("passes the level to the gzip compressor", () => { + const createGzip = vi.spyOn(Zlib, "createGzip"); + createRequestCompressor({ codec: "gzip", level: 1 }); + expect(createGzip).toHaveBeenCalledWith({ level: 1 }); + }); + + it("uses the codec default when no level is given", () => { + const createGzip = vi.spyOn(Zlib, "createGzip"); + createRequestCompressor({ codec: "gzip" }); + expect(createGzip).toHaveBeenCalledWith(undefined); + }); + + it("round-trips a gzip body compressed with an explicit level", async () => { + const values = "abc".repeat(1_000); + const out = await roundTrip( + createRequestCompressor({ codec: "gzip", level: 1 }), + (buf) => Zlib.gunzipSync(buf), + values, + ); + expect(out).toBe(values); + }); + + it.skipIf(!zstdSupported)( + "passes the level to the zstd compressor and round-trips", + async () => { + const createZstdCompress = vi.spyOn(Zlib, "createZstdCompress"); + const values = "abc".repeat(1_000); + const out = await roundTrip( + createRequestCompressor({ codec: "zstd", level: 19 }), + (buf) => Zlib.zstdDecompressSync(buf), + values, + ); + expect(createZstdCompress).toHaveBeenCalledWith({ + params: { [Zlib.constants.ZSTD_c_compressionLevel]: 19 }, + }); + expect(out).toBe(values); + }, + ); + + it("passes the quality to the brotli compressor (defaulting to 4)", () => { + const createBrotliCompress = vi.spyOn(Zlib, "createBrotliCompress"); + createRequestCompressor({ codec: "br" }); + expect(createBrotliCompress).toHaveBeenLastCalledWith({ + params: { [Zlib.constants.BROTLI_PARAM_QUALITY]: 4 }, + }); + createRequestCompressor({ codec: "br", quality: 11 }); + expect(createBrotliCompress).toHaveBeenLastCalledWith({ + params: { [Zlib.constants.BROTLI_PARAM_QUALITY]: 11 }, + }); + }); + + it("round-trips a br body compressed with an explicit quality", async () => { + const values = "abc".repeat(1_000); + const out = await roundTrip( + createRequestCompressor({ codec: "br", quality: 6 }), + (buf) => Zlib.brotliDecompressSync(buf), + values, + ); + expect(out).toBe(values); }); }); diff --git a/packages/client-node/__tests__/unit/node_custom_agent_connection.test.ts b/packages/client-node/__tests__/unit/node_custom_agent_connection.test.ts index d470b59e4..3b652a33a 100644 --- a/packages/client-node/__tests__/unit/node_custom_agent_connection.test.ts +++ b/packages/client-node/__tests__/unit/node_custom_agent_connection.test.ts @@ -22,8 +22,8 @@ function buildCustomAgentConnectionParams( url: new URL("http://localhost:8123"), request_timeout: 30_000, compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, max_open_connections: 10, auth: { username: "default", password: "", type: "Credentials" }, @@ -251,8 +251,8 @@ describe("[Node.js] NodeCustomAgentConnection", () => { url, headers: { "Content-Type": "text/plain" }, abort_signal: abortController.signal, - enable_request_compression: true, - enable_response_compression: true, + request_compression: { codec: "gzip" }, + response_compression_codec: "gzip", query: "SELECT 1", query_id: "test-query-id", log_writer: new LogWriter( diff --git a/packages/client-node/__tests__/unit/node_http_connection.test.ts b/packages/client-node/__tests__/unit/node_http_connection.test.ts index 2e8ca1341..dcff73712 100644 --- a/packages/client-node/__tests__/unit/node_http_connection.test.ts +++ b/packages/client-node/__tests__/unit/node_http_connection.test.ts @@ -21,8 +21,8 @@ function buildHttpConnectionParams( url: new URL("http://localhost:8123"), request_timeout: 30_000, compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, max_open_connections: 10, auth: { username: "default", password: "", type: "Credentials" }, diff --git a/packages/client-node/__tests__/unit/node_https_connection.test.ts b/packages/client-node/__tests__/unit/node_https_connection.test.ts index 04d306647..309aecbd3 100644 --- a/packages/client-node/__tests__/unit/node_https_connection.test.ts +++ b/packages/client-node/__tests__/unit/node_https_connection.test.ts @@ -27,8 +27,8 @@ function buildHttpsConnectionParams( url: new URL("https://localhost:8443"), request_timeout: 30_000, compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, max_open_connections: 10, auth: { username: "default", password: "", type: "Credentials" }, diff --git a/packages/client-node/__tests__/unit/node_multipart_query.test.ts b/packages/client-node/__tests__/unit/node_multipart_query.test.ts index ebd12b5f4..6f341cd73 100644 --- a/packages/client-node/__tests__/unit/node_multipart_query.test.ts +++ b/packages/client-node/__tests__/unit/node_multipart_query.test.ts @@ -73,8 +73,8 @@ describe("[Node.js] Multipart query params", () => { const adapter = buildHttpConnection({ database: "my_db", compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, use_multipart_params: true, }); diff --git a/packages/client-node/__tests__/utils/http_stubs.ts b/packages/client-node/__tests__/utils/http_stubs.ts index b194af297..845f84a89 100644 --- a/packages/client-node/__tests__/utils/http_stubs.ts +++ b/packages/client-node/__tests__/utils/http_stubs.ts @@ -101,8 +101,8 @@ export function buildHttpConnection(config: Partial) { request_timeout: 30_000, compression: { - decompress_response: true, - compress_request: false, + decompress_response: { codec: "gzip" }, + compress_request: undefined, }, max_open_connections: 10, diff --git a/packages/client-node/eslint.config.mjs b/packages/client-node/eslint.config.mjs index c7164f432..d142e6c9f 100644 --- a/packages/client-node/eslint.config.mjs +++ b/packages/client-node/eslint.config.mjs @@ -1,14 +1,12 @@ -import js from "@eslint/js"; import { defineConfig } from "eslint/config"; -import tseslint from "typescript-eslint"; -import { typescriptEslintConfig } from "../../eslint.config.base.mjs"; +import { + recommendedWarnConfigs, + typescriptEslintConfig, +} from "../../eslint.config.base.mjs"; export default defineConfig( - // Base ESLint recommended rules - js.configs.recommended, - // TypeScript-ESLint recommended rules with type checking - ...tseslint.configs.strict, - ...tseslint.configs.stylistic, + // Recommended rule sets, downgraded to warnings (only tsc reports errors) + ...recommendedWarnConfigs, { rules: { "@typescript-eslint/no-unused-vars": "warn", diff --git a/packages/client-node/package.json b/packages/client-node/package.json index 288e297fd..6fc0b578e 100644 --- a/packages/client-node/package.json +++ b/packages/client-node/package.json @@ -2,7 +2,7 @@ "name": "@clickhouse/client", "description": "Official JS client for ClickHouse DB - Node.js implementation", "homepage": "https://clickhouse.com", - "version": "1.21.0", + "version": "1.22.0", "license": "Apache-2.0", "keywords": [ "clickhouse", @@ -44,7 +44,7 @@ "build": "rm -rf dist; tsc" }, "dependencies": { - "@clickhouse/client-common": "1.21.0" + "@clickhouse/client-common": "1.22.0" }, "devDependencies": { "simdjson": "^0.9.2" diff --git a/packages/client-node/src/config.ts b/packages/client-node/src/config.ts index 6c1bcbee2..2e1a42f2d 100644 --- a/packages/client-node/src/config.ts +++ b/packages/client-node/src/config.ts @@ -7,12 +7,14 @@ import type { } from "@clickhouse/client-common"; import { type BaseClickHouseClientConfigOptions, + type CompressionMethod, type ConnectionParams, numberConfigURLValue, } from "@clickhouse/client-common"; import type http from "http"; import type https from "node:https"; import type Stream from "stream"; +import Zlib from "zlib"; import { NodeConnectionFactory, type TLSParams } from "./connection"; import { ResultSet } from "./result_set"; import { NodeValuesEncoder } from "./utils"; @@ -89,6 +91,58 @@ interface MutualTLSOptions { key: Buffer; } +function unknownCodecError( + value: string, + direction: "request" | "response", +): Error { + return new Error( + `Unknown ${direction} compression codec "${value}". ` + + `Supported codecs: gzip, zstd, br.`, + ); +} + +// zstd's zlib APIs were added in Node.js 22.15.0, and compression / +// decompression are separate functions - so each direction is gated on its own, +// naming the missing function to make the diagnosis concrete. + +/** Fails fast at client creation on an unknown request codec, or on `zstd` when + * this Node.js runtime's `zlib` does not provide the zstd compression API - + * rather than a TypeError deep in a later insert. The boolean forms (`false` + * off, `true` gzip) need no validation and are filtered out by the caller. */ +function ensureRequestCodecSupported(value: CompressionMethod): void { + if (value === "zstd") { + if (typeof Zlib.createZstdCompress !== "function") { + throw new Error( + "zstd compression is not supported by this Node.js runtime (v" + + process.versions.node + + "): the built-in zlib module does not provide `createZstdCompress` " + + "(the zstd APIs were added in Node.js 22.15.0). Use gzip compression instead.", + ); + } + } else if (value !== "gzip" && value !== "br") { + throw unknownCodecError(value, "request"); + } +} + +/** Fails fast at client creation on an unknown response codec, or on `zstd` + * when this Node.js runtime's `zlib` does not provide the zstd decompression + * API - rather than a TypeError deep in a later query. The boolean forms + * (`false` off, `true` gzip) need no validation and are filtered by the caller. */ +function ensureResponseCodecSupported(value: CompressionMethod): void { + if (value === "zstd") { + if (typeof Zlib.createZstdDecompress !== "function") { + throw new Error( + "zstd compression is not supported by this Node.js runtime (v" + + process.versions.node + + "): the built-in zlib module does not provide `createZstdDecompress` " + + "(the zstd APIs were added in Node.js 22.15.0). Use gzip compression instead.", + ); + } + } else if (value !== "gzip" && value !== "br") { + throw unknownCodecError(value, "response"); + } +} + export const NodeConfigImpl: Required< ImplementationDetails["impl"] > = { @@ -127,6 +181,13 @@ export const NodeConfigImpl: Required< nodeConfig: NodeClickHouseClientConfigOptions, params: ConnectionParams, ) => { + const { compress_request, decompress_response } = params.compression; + if (compress_request) { + ensureRequestCodecSupported(compress_request.codec); + } + if (decompress_response) { + ensureResponseCodecSupported(decompress_response.codec); + } let tls: TLSParams | undefined = undefined; if (nodeConfig.tls !== undefined) { if ("cert" in nodeConfig.tls && "key" in nodeConfig.tls) { diff --git a/packages/client-node/src/connection/compression.ts b/packages/client-node/src/connection/compression.ts index 317583762..0854bff92 100644 --- a/packages/client-node/src/connection/compression.ts +++ b/packages/client-node/src/connection/compression.ts @@ -1,4 +1,4 @@ -import type { LogWriter } from "@clickhouse/client-common"; +import type { LogWriter, RequestCompression } from "@clickhouse/client-common"; import { ClickHouseLogLevel } from "@clickhouse/client-common"; import type Http from "http"; import Stream from "stream"; @@ -15,32 +15,120 @@ export function decompressResponse( ): DecompressResponseResult { const encoding = response.headers["content-encoding"]; + // No `Content-Encoding`: nothing to decompress. + if (encoding === undefined) { + return { response }; + } + if (encoding === "gzip") { return { response: Stream.pipeline( response, Zlib.createGunzip(), function pipelineCb(err) { - if (err) { - if (log_level <= ClickHouseLogLevel.ERROR) { - log_writer.error({ - message: "An error occurred while decompressing the response", - err, - }); - } + if (err && log_level <= ClickHouseLogLevel.ERROR) { + log_writer.error({ + message: "An error occurred while decompressing the response", + err, + }); + } + }, + ), + }; + } + + if (encoding === "zstd") { + // zstd's zlib API was added in Node.js 22.15.0; on an older runtime the + // codec is recognized but unusable, so report that explicitly rather than + // falling through to a misleading "Unexpected encoding". + if (typeof Zlib.createZstdDecompress !== "function") { + return { + error: new Error( + "Received a zstd-compressed response, but this Node.js runtime (v" + + process.versions.node + + ") does not support zstd decompression: the built-in zlib module " + + "does not provide the zstd APIs (added in Node.js 22.15.0). Use gzip " + + "compression instead, or upgrade Node.js.", + ), + }; + } + return { + response: Stream.pipeline( + response, + Zlib.createZstdDecompress(), + function pipelineCb(err) { + if (err && log_level <= ClickHouseLogLevel.ERROR) { + log_writer.error({ + message: "An error occurred while decompressing the response", + err, + }); } }, ), }; - } else if (encoding !== undefined) { + } + + if (encoding === "br") { return { - error: new Error(`Unexpected encoding: ${encoding}`), + response: Stream.pipeline( + response, + Zlib.createBrotliDecompress(), + function pipelineCb(err) { + if (err && log_level <= ClickHouseLogLevel.ERROR) { + log_writer.error({ + message: "An error occurred while decompressing the response", + err, + }); + } + }, + ), }; } - return { response }; + return { error: new Error(`Unexpected encoding: ${encoding}`) }; } export function isDecompressionError(result: any): result is { error: Error } { return result.error !== undefined; } + +/** Returns the request-body compressor for the given config. Each codec carries + * its own optional tuning option - a `level` for gzip/zstd, a `quality` for + * Brotli; when omitted, the codec default is used (Brotli defaults to quality 4 + * rather than zlib's slow default of 11, which is impractical for a streaming + * insert body). The exhaustive switch fails the build if a codec is added to + * {@link RequestCompression} without a corresponding case here. */ +export function createRequestCompressor( + compression: RequestCompression, +): Stream.Transform { + switch (compression.codec) { + case "gzip": + return Zlib.createGzip( + compression.level !== undefined + ? { level: compression.level } + : undefined, + ); + case "zstd": + return Zlib.createZstdCompress( + compression.level !== undefined + ? { + params: { + [Zlib.constants.ZSTD_c_compressionLevel]: compression.level, + }, + } + : undefined, + ); + case "br": + return Zlib.createBrotliCompress({ + params: { + [Zlib.constants.BROTLI_PARAM_QUALITY]: compression.quality ?? 4, + }, + }); + default: { + const exhaustiveCheck: never = compression; + throw new Error( + `Unsupported request compression codec: ${String((exhaustiveCheck as { codec?: unknown }).codec)}`, + ); + } + } +} diff --git a/packages/client-node/src/connection/node_base_connection.ts b/packages/client-node/src/connection/node_base_connection.ts index e1e6577c8..337508ac0 100644 --- a/packages/client-node/src/connection/node_base_connection.ts +++ b/packages/client-node/src/connection/node_base_connection.ts @@ -223,9 +223,13 @@ export abstract class NodeBaseConnection implements Connection role: params.role, }); const { controller, controllerCleanup } = this.getAbortController(params); - // allows enforcing the compression via the settings even if the client instance has it disabled - const enableResponseCompression = - clickhouse_settings.enable_http_compression === 1; + // Accept-Encoding is sent whenever the server is asked to compress + // (enable_http_compression), independent of whether the client decompresses; + // the codec is the explicitly configured one, defaulting to gzip. + const responseCompressionCodec = + clickhouse_settings.enable_http_compression === 1 + ? (this.params.compression.decompress_response?.codec ?? "gzip") + : undefined; let body: string = params.query; const headers = this.buildRequestHeaders(params); @@ -246,7 +250,7 @@ export abstract class NodeBaseConnection implements Connection url: transformUrl({ url: this.params.url, searchParams }), body, abort_signal: controller.signal, - enable_response_compression: enableResponseCompression, + response_compression_codec: responseCompressionCodec, headers, query: params.query, query_id, @@ -270,7 +274,7 @@ export abstract class NodeBaseConnection implements Connection search_params: searchParams, err: err as Error, extra_args: { - decompress_response: enableResponseCompression, + decompress_response: responseCompressionCodec, clickhouse_settings, }, }); @@ -303,8 +307,7 @@ export abstract class NodeBaseConnection implements Connection url: transformUrl({ url: this.params.url, searchParams }), body: params.values, abort_signal: controller.signal, - enable_request_compression: - this.params.compression.compress_request, + request_compression: this.params.compression.compress_request, parse_summary: true, headers: this.buildRequestHeaders(params), query: params.query, @@ -550,7 +553,7 @@ export abstract class NodeBaseConnection implements Connection params.op === "Exec" ? // allows disabling stream decompression for the `Exec` operation only (params.decompress_response_stream ?? - this.params.compression.decompress_response) + Boolean(this.params.compression.decompress_response)) : // there is nothing useful in the response stream for the `Command` operation, // and it is immediately destroyed; never decompress it false; @@ -564,10 +567,9 @@ export abstract class NodeBaseConnection implements Connection body: sendQueryInParams ? params.values : params.query, abort_signal: controller.signal, parse_summary: true, - enable_request_compression: - this.params.compression.compress_request, - enable_response_compression: - this.params.compression.decompress_response, + request_compression: this.params.compression.compress_request, + response_compression_codec: + this.params.compression.decompress_response?.codec, try_decompress_response_stream: tryDecompressResponseStream, ignore_error_response: ignoreErrorResponse, headers: this.buildRequestHeaders(params), diff --git a/packages/client-node/src/connection/node_custom_agent_connection.ts b/packages/client-node/src/connection/node_custom_agent_connection.ts index 0f55b9c05..6000be525 100644 --- a/packages/client-node/src/connection/node_custom_agent_connection.ts +++ b/packages/client-node/src/connection/node_custom_agent_connection.ts @@ -26,8 +26,8 @@ export class NodeCustomAgentConnection extends NodeBaseConnection { protected createClientRequest(params: RequestParams): Http.ClientRequest { const headers = withCompressionHeaders({ headers: params.headers, - enable_request_compression: params.enable_request_compression, - enable_response_compression: params.enable_response_compression, + request_compression_codec: params.request_compression?.codec, + response_compression_codec: params.response_compression_codec, }); return this.httpRequestFn(params.url, { method: params.method, diff --git a/packages/client-node/src/connection/node_http_connection.ts b/packages/client-node/src/connection/node_http_connection.ts index 5a3f79408..12edaa884 100644 --- a/packages/client-node/src/connection/node_http_connection.ts +++ b/packages/client-node/src/connection/node_http_connection.ts @@ -16,8 +16,8 @@ export class NodeHttpConnection extends NodeBaseConnection { protected createClientRequest(params: RequestParams): Http.ClientRequest { const headers = withCompressionHeaders({ headers: params.headers, - enable_request_compression: params.enable_request_compression, - enable_response_compression: params.enable_response_compression, + request_compression_codec: params.request_compression?.codec, + response_compression_codec: params.response_compression_codec, }); return Http.request(params.url, { method: params.method, diff --git a/packages/client-node/src/connection/node_https_connection.ts b/packages/client-node/src/connection/node_https_connection.ts index a7d9b98d9..d9a35319d 100644 --- a/packages/client-node/src/connection/node_https_connection.ts +++ b/packages/client-node/src/connection/node_https_connection.ts @@ -63,8 +63,8 @@ export class NodeHttpsConnection extends NodeBaseConnection { protected createClientRequest(params: RequestParams): Http.ClientRequest { const headers = withCompressionHeaders({ headers: params.headers, - enable_request_compression: params.enable_request_compression, - enable_response_compression: params.enable_response_compression, + request_compression_codec: params.request_compression?.codec, + response_compression_codec: params.response_compression_codec, }); return Https.request(params.url, { method: params.method, diff --git a/packages/client-node/src/connection/socket_pool.ts b/packages/client-node/src/connection/socket_pool.ts index fba5c2531..6e2a42823 100644 --- a/packages/client-node/src/connection/socket_pool.ts +++ b/packages/client-node/src/connection/socket_pool.ts @@ -1,7 +1,6 @@ import Http from "http"; import Stream from "stream"; import type * as net from "net"; -import Zlib from "zlib"; import { enhanceStackTrace, getCurrentStackTrace, @@ -14,9 +13,15 @@ import { type ResponseHeaders, type ClickHouseSummary, type JSONHandling, + type CompressionMethod, + type RequestCompression, } from "@clickhouse/client-common"; import { getAsText, isStream } from "../utils"; -import { decompressResponse, isDecompressionError } from "./compression"; +import { + createRequestCompressor, + decompressResponse, + isDecompressionError, +} from "./compression"; import { type NodeConnectionParams } from "./node_base_connection"; export interface RequestParams { @@ -26,8 +31,8 @@ export interface RequestParams { body?: string | Stream.Readable; // provided by the user and wrapped around internally abort_signal: AbortSignal; - enable_response_compression?: boolean; - enable_request_compression?: boolean; + response_compression_codec?: CompressionMethod; + request_compression?: RequestCompression; // if there are compression headers, attempt to decompress it try_decompress_response_stream?: boolean; // if the response contains an error, ignore it and return the stream as-is @@ -388,8 +393,11 @@ export class SocketPool { } }; - if (params.enable_request_compression) { - Stream.pipeline(bodyStream, Zlib.createGzip(), request, callback); + if (params.request_compression) { + const compressor = createRequestCompressor( + params.request_compression, + ); + Stream.pipeline(bodyStream, compressor, request, callback); } else { Stream.pipeline(bodyStream, request, callback); } diff --git a/packages/client-node/src/version.ts b/packages/client-node/src/version.ts index a38a7bdc5..cbfb1f9da 100644 --- a/packages/client-node/src/version.ts +++ b/packages/client-node/src/version.ts @@ -1 +1 @@ -export default "1.21.0"; +export default "1.22.0"; diff --git a/packages/client-web/__tests__/unit/web_client.test.ts b/packages/client-web/__tests__/unit/web_client.test.ts index 5503d4606..b92f25907 100644 --- a/packages/client-web/__tests__/unit/web_client.test.ts +++ b/packages/client-web/__tests__/unit/web_client.test.ts @@ -22,6 +22,37 @@ describe("[Web] createClient", () => { ); }); + it("throws on a zstd request codec (Node-only)", () => { + expect(() => + createClient({ compression: { request: { codec: "zstd" } } }), + ).toThrow( + expect.objectContaining({ + message: expect.stringContaining( + "zstd request compression is not supported by @clickhouse/client-web", + ), + }), + ); + }); + + it("throws on a zstd response codec (Node-only)", () => { + expect(() => + createClient({ compression: { response: { codec: "zstd" } } }), + ).toThrow( + expect.objectContaining({ + message: expect.stringContaining( + "zstd response compression is not supported by @clickhouse/client-web", + ), + }), + ); + }); + + it("allows the gzip codec", () => { + const client = createClient({ + compression: { request: { codec: "gzip" }, response: { codec: "gzip" } }, + }); + expect(client).toBeDefined(); + }); + it("should not mutate provided configuration", async () => { const config: BaseClickHouseClientConfigOptions = { url: "https://localhost:8443", diff --git a/packages/client-web/__tests__/unit/web_multipart_query.test.ts b/packages/client-web/__tests__/unit/web_multipart_query.test.ts index 9aed29560..dc0746127 100644 --- a/packages/client-web/__tests__/unit/web_multipart_query.test.ts +++ b/packages/client-web/__tests__/unit/web_multipart_query.test.ts @@ -24,8 +24,8 @@ function buildWebConnection( url: new URL("https://localhost:8443"), request_timeout: 30_000, compression: { - decompress_response: false, - compress_request: false, + decompress_response: undefined, + compress_request: undefined, }, max_open_connections: 10, auth: { username: "default", password: "", type: "Credentials" }, diff --git a/packages/client-web/eslint.config.mjs b/packages/client-web/eslint.config.mjs index 578dc9cff..0a540ee80 100644 --- a/packages/client-web/eslint.config.mjs +++ b/packages/client-web/eslint.config.mjs @@ -1,14 +1,12 @@ -import js from "@eslint/js"; import { defineConfig } from "eslint/config"; -import tseslint from "typescript-eslint"; -import { typescriptEslintConfig } from "../../eslint.config.base.mjs"; +import { + recommendedWarnConfigs, + typescriptEslintConfig, +} from "../../eslint.config.base.mjs"; export default defineConfig( - // Base ESLint recommended rules - js.configs.recommended, - // TypeScript-ESLint recommended rules with type checking - ...tseslint.configs.strict, - ...tseslint.configs.stylistic, + // Recommended rule sets, downgraded to warnings (only tsc reports errors) + ...recommendedWarnConfigs, typescriptEslintConfig(import.meta.dirname), // Ignore build artifacts and externals { diff --git a/packages/client-web/package.json b/packages/client-web/package.json index cebd08518..15cc51367 100644 --- a/packages/client-web/package.json +++ b/packages/client-web/package.json @@ -2,7 +2,7 @@ "name": "@clickhouse/client-web", "description": "Official JS client for ClickHouse DB - Web API implementation", "homepage": "https://clickhouse.com", - "version": "1.21.0", + "version": "1.22.0", "license": "Apache-2.0", "keywords": [ "clickhouse", @@ -31,6 +31,6 @@ "build": "rm -rf dist; tsc" }, "dependencies": { - "@clickhouse/client-common": "1.21.0" + "@clickhouse/client-common": "1.22.0" } } diff --git a/packages/client-web/src/config.ts b/packages/client-web/src/config.ts index cdfb0f1f0..289e315bc 100644 --- a/packages/client-web/src/config.ts +++ b/packages/client-web/src/config.ts @@ -1,6 +1,7 @@ import type { BaseClickHouseClientConfigOptions, ClickHouseSpan, + CompressionSettings, ConnectionParams, DataFormat, ImplementationDetails, @@ -18,15 +19,36 @@ export type WebClickHouseClientConfigOptions = fetch?: typeof fetch; }; +/** The `zstd` codec is Node-only: the Web client does not compress request + * bodies, and relies on the browser to negotiate / decompress responses, so it + * cannot honor `{ codec: "zstd" }`. Fail fast at client creation rather than + * silently emitting an `Accept-Encoding: zstd` the client can't fulfill. */ +function ensureNoZstdCodec(compression: CompressionSettings): void { + const directions = [ + ["request", compression.compress_request], + ["response", compression.decompress_response], + ] as const; + for (const [direction, value] of directions) { + if (value?.codec === "zstd") { + throw new Error( + `zstd ${direction} compression is not supported by @clickhouse/client-web; ` + + `it is only available in @clickhouse/client (Node.js). Use gzip instead.`, + ); + } + } +} + export const WebImpl: ImplementationDetails["impl"] = { make_connection: ( config: WebClickHouseClientConfigOptions, params: ConnectionParams, - ) => - new WebConnection({ + ) => { + ensureNoZstdCodec(params.compression); + return new WebConnection({ ...params, fetch: config.fetch, - }), + }); + }, make_result_set: (( stream: ReadableStream, format: DataFormat, diff --git a/packages/client-web/src/connection/web_connection.ts b/packages/client-web/src/connection/web_connection.ts index 26f93d1df..6ea633c71 100644 --- a/packages/client-web/src/connection/web_connection.ts +++ b/packages/client-web/src/connection/web_connection.ts @@ -240,9 +240,9 @@ export class WebConnection implements Connection { const headers = withCompressionHeaders({ headers: prebuiltHeaders ?? this.defaultHeadersWithOverride(params), // It is not currently working as expected in all major browsers - enable_request_compression: false, - enable_response_compression: - this.params.compression.decompress_response, + request_compression_codec: undefined, + response_compression_codec: + this.params.compression.decompress_response?.codec, }); // avoiding "fetch called on an object that does not implement interface Window" error diff --git a/packages/client-web/src/version.ts b/packages/client-web/src/version.ts index a38a7bdc5..cbfb1f9da 100644 --- a/packages/client-web/src/version.ts +++ b/packages/client-web/src/version.ts @@ -1 +1 @@ -export default "1.21.0"; +export default "1.22.0"; diff --git a/skills/clickhouse-js-node-coding/SKILL.md b/skills/clickhouse-js-node-coding/SKILL.md index bb634af0c..6429830f7 100644 --- a/skills/clickhouse-js-node-coding/SKILL.md +++ b/skills/clickhouse-js-node-coding/SKILL.md @@ -78,6 +78,7 @@ Identify the user's task and read the matching reference file. | Task | Triggers / symptoms | Reference file | | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | | **Configure / connect the client** | Building a `createClient` call, URL parameters, `clickhouse_settings`, default format, custom HTTP headers | `reference/client-configuration.md` | +| **Compress requests / responses** | `compression`, gzip vs `zstd`, `{ codec }` option shape, Node version requirements, web limitations | `reference/compression.md` | | **Ping the server** | Health checks, readiness probes, "is ClickHouse up?" | `reference/ping.md` | | **Choose an insert format** | "Which format should I use to insert?", JSON vs raw, `JSONEachRow` vs `JSON` vs `JSONObjectEachRow` | `reference/insert-formats.md` | | **Insert into a subset of columns / different database** | `insert({ columns })`, excluding columns, ephemeral columns, cross-DB inserts | `reference/insert-columns.md` | diff --git a/skills/clickhouse-js-node-coding/reference/compression.md b/skills/clickhouse-js-node-coding/reference/compression.md new file mode 100644 index 000000000..bda6840ad --- /dev/null +++ b/skills/clickhouse-js-node-coding/reference/compression.md @@ -0,0 +1,129 @@ +# Compression + +> **Applies to:** all versions support boolean `compression`. The explicit +> codec object form, per-codec request options, and `zstd` support are a +> Node-only addition in `@clickhouse/client` `>= 1.22.0`; Brotli +> (`{ codec: "br" }`) is also added (any Node.js version, no minimum). Request +> compression is Node-only regardless of codec; response decompression on the +> web client is handled by the browser. + +The client can compress the outgoing request (insert) body and ask the server +to compress the response (read) body. Both are configured under `compression` +on `createClient`. + +## Answer checklist + +When answering compression questions, include the relevant points: + +- The option shape is `boolean | { codec }`, **not** a bare string. `true` + means gzip (backwards compatible); `{ codec: "zstd" }` selects zstd. There is + no `compression: { request: "zstd" }` shorthand — it must be + `{ request: { codec: "zstd" } }`. +- `zstd` is **Node-only** (`@clickhouse/client`) and requires **Node.js >= + 22.15.0** (the built-in `zlib` zstd APIs). On `@clickhouse/client-web` or an + older Node runtime, requesting `zstd` throws a clear error at `createClient`. +- Supported codecs are `gzip`, `zstd`, and `br` (Brotli). Unlike `zstd`, `br` + works on any supported Node.js version (it ships in `zlib`). Request-body + compression is Node-only for every codec (the web client sends requests + uncompressed); for responses, the web client rejects `zstd` but allows + `gzip`/`br`, which the browser decompresses. +- The request object takes a per-codec tuning option: a `level` for + `gzip`/`zstd`, a `quality` for `br` (`{ codec: "br", quality }`). Brotli + defaults to quality 4 — zlib's brotli default of 11 is far too slow for a + streaming insert. +- Response compression cannot be enabled for a `readonly=1` user — the server + rejects the required `enable_http_compression` setting change. +- Prefer `zstd` for write-heavy (insert) workloads: a similar-or-better ratio + than gzip at materially lower CPU, and ClickHouse decompresses gzip + single-threaded. + +## gzip (default, all versions) + +```ts +import { createClient } from "@clickhouse/client"; + +const client = createClient({ + compression: { + request: true, // compress insert bodies with gzip + response: true, // ask the server for a gzip-compressed response + }, +}); +``` + +`request: true` / `response: true` are equivalent to +`{ codec: "gzip" }`. + +## zstd (Node.js >= 22.15.0) + +```ts +const client = createClient({ + compression: { + request: { codec: "zstd" }, + response: { codec: "zstd" }, + }, +}); +``` + +You can mix codecs and directions, e.g. zstd inserts with uncompressed reads: + +```ts +const client = createClient({ + compression: { + request: { codec: "zstd" }, + // response omitted → uncompressed reads + }, +}); +``` + +## Brotli (any Node.js version) + +```ts +const client = createClient({ + compression: { + request: { codec: "br" }, // brotli insert bodies (quality 4 by default) + response: { codec: "br" }, // ask the server for a brotli-compressed response + }, +}); +``` + +Unlike `zstd`, Brotli needs no minimum Node.js version. Request-body compression +is Node-only (the web client sends requests uncompressed); `br` responses also +work on the web client, decompressed by the browser. Its tuning option is +`quality` (0-11), not `level`: + +```ts +const client = createClient({ + compression: { + request: { codec: "br", quality: 6 }, + }, +}); +``` + +## Request compression options (Node.js) + +The request object accepts a per-codec tuning option — a `level` for `gzip` +(zlib level) and `zstd` (zstd compression level), or a `quality` for `br` +(Brotli quality, 0-11). When omitted, the codec default is used (Brotli +defaults to 4). This applies to the **request** direction only; the response +compression options are chosen by the ClickHouse server. + +```ts +const client = createClient({ + compression: { + request: { codec: "zstd", level: 19 }, // higher ratio, more CPU + }, +}); +``` + +## Common pitfalls + +- **`compression: { request: "zstd" }` is a type error.** Use the object form: + `{ request: { codec: "zstd" } }`. +- **`zstd` on the web client throws.** `@clickhouse/client-web` does not + compress request bodies, and zstd response handling depends on the browser; + the web client rejects the `zstd` codec at `createClient`. Use Node, or gzip. +- **`zstd` on Node < 22.15 throws at client creation**, not deep inside a later + insert/query. The error names the running Node version and tells you to use + gzip instead. +- **Response compression + `readonly=1` user fails.** Response decompression + needs `enable_http_compression=1`, which a readonly user cannot set. diff --git a/tests/clickhouse-test-runner/eslint.config.mjs b/tests/clickhouse-test-runner/eslint.config.mjs index 6c435b4b6..e1c300d53 100644 --- a/tests/clickhouse-test-runner/eslint.config.mjs +++ b/tests/clickhouse-test-runner/eslint.config.mjs @@ -1,15 +1,13 @@ -import js from "@eslint/js"; import { defineConfig } from "eslint/config"; -import tseslint from "typescript-eslint"; import { + recommendedWarnConfigs, typescriptEslintConfig, testFilesOverrides, } from "../../eslint.config.base.mjs"; export default defineConfig( - js.configs.recommended, - ...tseslint.configs.strict, - ...tseslint.configs.stylistic, + // Recommended rule sets, downgraded to warnings (only tsc reports errors) + ...recommendedWarnConfigs, typescriptEslintConfig(import.meta.dirname), testFilesOverrides(), { diff --git a/tests/clickhouse-test-runner/package.json b/tests/clickhouse-test-runner/package.json index 57b4d11f2..996fe280a 100644 --- a/tests/clickhouse-test-runner/package.json +++ b/tests/clickhouse-test-runner/package.json @@ -1,7 +1,7 @@ { "name": "@clickhouse/clickhouse-test-runner", "private": true, - "version": "1.21.0", + "version": "1.22.0", "description": "Node.js port of ClickHouse/clickhouse-java tests/clickhouse-client harness", "engines": { "node": ">=20.19.0" @@ -23,12 +23,11 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@types/node": "25.9.2", - "eslint": "^10.4.1", - "eslint-plugin-prettier": "^5.5.6", + "@types/node": "25.9.3", + "eslint": "^10.5.0", "prettier": "3.8.4", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.0", + "typescript-eslint": "^8.61.1", "vitest": "^4.0.16" } } diff --git a/tests/clickhouse-test-runner/upstream-allowlist.txt b/tests/clickhouse-test-runner/upstream-allowlist.txt index 6a3a5feb4..c2210720f 100644 --- a/tests/clickhouse-test-runner/upstream-allowlist.txt +++ b/tests/clickhouse-test-runner/upstream-allowlist.txt @@ -321,7 +321,7 @@ 00507_sumwithoverflow 00511_get_size_of_enum 00513_fractional_time_zones -00516_is_inf_nan +# 00516_is_inf_nan: TODO: failing against latest ClickHouse stable; uses new server feature not yet in the latest Docker release 00516_modulo 00517_date_parsing 00518_extract_all_and_empty_matches @@ -532,7 +532,8 @@ 00822_array_insert_default 00823_sequence_match_dfa 00824_filesystem -00826_cross_to_inner_join +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 00826_cross_to_inner_join 00829_bitmap64_function 00834_date_datetime_cmp 00834_not_between @@ -668,7 +669,8 @@ 01020_having_without_group_by 01025_array_compact_generic 01026_char_utf8 -01029_early_constant_folding +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01029_early_constant_folding 01030_concatenate_equal_fixed_strings 01030_final_mark_empty_primary_key # 01031_pmj_new_any_semi_join: reference output drifts on released CH (`latest`) vs upstream master due to join optimizer changes; passes on `head`. @@ -825,10 +827,12 @@ 01314_position_in_system_columns 01315_count_distinct_return_not_nullable 01318_parallel_final_stuck -01321_aggregate_functions_of_group_by_keys +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01321_aggregate_functions_of_group_by_keys 01321_monotonous_functions_in_order_by_bug 01323_too_many_threads_bug -01324_if_transform_strings_to_enum +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01324_if_transform_strings_to_enum 01324_settings_documentation 01326_build_id 01326_fixed_string_comparison_denny_crane @@ -871,7 +875,8 @@ 01385_not_function 01389_filter_by_virtual_columns 01390_check_table_codec -01390_remove_injective_in_uniq +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01390_remove_injective_in_uniq 01391_join_on_dict_crash 01392_column_resolve 01396_negative_datetime_saturate_to_zero @@ -889,7 +894,8 @@ 01413_if_array_uuid 01413_truncate_without_table_keyword 01414_bloom_filter_index_with_const_column -01414_push_predicate_when_contains_with_clause +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01414_push_predicate_when_contains_with_clause 01415_table_function_view 01416_join_totals_header_bug 01417_update_permutation_crash @@ -931,8 +937,10 @@ 01459_decimal_casts 01460_allow_dollar_and_number_in_identifier 01460_mark_inclusion_search_crash -01470_columns_transformers2 -01471_limit_by_format +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01470_columns_transformers2 +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01471_limit_by_format 01471_with_format 01474_decimal_scale_bug 01475_fix_bigint_shift @@ -962,7 +970,8 @@ 01511_prewhere_with_virtuals 01513_ilike_like_cache 01514_tid_function -01515_with_global_and_with_propagation +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01515_with_global_and_with_propagation 01518_cast_nullable_virtual_system_column 01518_filtering_aliased_materialized_column 01518_nullable_aggregate_states1 @@ -997,12 +1006,14 @@ 01576_if_null_external_aggregation 01580_column_const_comparision 01582_any_join_supertype -01582_deterministic_function_with_predicate +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01582_deterministic_function_with_predicate 01583_const_column_in_set_index 01585_fuzz_bits_with_bugfix 01592_length_map 01592_toUnixTimestamp_Date -01593_functions_in_order_by +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01593_functions_in_order_by 01596_full_join_chertus 01600_encode_XML 01600_min_max_compress_block_size @@ -1017,7 +1028,8 @@ 01620_fix_simple_state_arg_type 01621_decode_XML 01623_byte_size_const -01626_cnf_test +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01626_cnf_test 01631_date_overflow_as_partition_key 01632_nullable_string_type_convert_to_decimal_type 01632_select_all_syntax @@ -1090,9 +1102,11 @@ 01700_deltasum 01700_mod_negative_type_promotion 01702_bitmap_native_integers -01702_rewrite_avg_for_algebraic_optimization +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01702_rewrite_avg_for_algebraic_optimization 01702_toDateTime_from_string_clamping -01703_rewrite_aggregate_function_case_insensitive +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01703_rewrite_aggregate_function_case_insensitive 01704_transform_with_float_key 01706_optimize_normalize_count_variants 01707_join_use_nulls @@ -1220,9 +1234,11 @@ 01846_null_as_default_for_insert_select 01851_fix_row_policy_empty_result 01851_s2_to_geo -01852_cast_operator_2 +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01852_cast_operator_2 01852_cast_operator_3 -01852_cast_operator_4 +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 01852_cast_operator_4 01852_jit_if 01852_s2_get_neighbours 01855_jit_comparison_constant_result @@ -1440,7 +1456,8 @@ 02313_negative_datetime64 02313_test_fpc_codec 02315_pmj_union_ubsan_35857 -02315_replace_multiif_to_if +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02315_replace_multiif_to_if 02316_const_string_intersact 02316_literal_no_octal 02316_values_table_func_bug @@ -1465,7 +1482,7 @@ 02346_text_index_bug84805 02346_text_index_bug87887 02346_text_index_bug93432 -02346_text_index_byte_size_reporting +# 02346_text_index_byte_size_reporting: TODO: failing against latest ClickHouse stable; uses setting 'text_index_dictionary_block_size' not yet in the latest Docker release (passes on head). 02346_text_index_collapsingmergetree 02346_text_index_default_granularity 02346_text_index_detach_attach @@ -1518,7 +1535,8 @@ 02393_every_metric_must_have_documentation 02394_every_profile_event_must_have_documentation 02395_every_merge_tree_setting_must_have_documentation -02398_subquery_where_pushdown_and_limit_offset +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02398_subquery_where_pushdown_and_limit_offset 02401_merge_tree_old_tmp_dirs_cleanup 02405_pmj_issue_40335 02406_try_read_datetime64_bug @@ -1573,8 +1591,10 @@ 02476_analyzer_join_with_unused_columns 02477_analyzer_ast_key_condition_crash 02477_exists_fuzz_43478 -02477_fuse_quantiles -02477_is_null_parser +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02477_fuse_quantiles +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02477_is_null_parser 02477_logical_expressions_optimizer_issue_89803 02478_analyzer_table_expression_aliases 02479_analyzer_aggregation_crash @@ -1586,7 +1606,8 @@ 02480_max_map_null_totals 02480_parse_date_time_best_effort_math_overflow 02481_aggregation_in_order_plan -02481_analyzer_optimize_grouping_sets_keys +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02481_analyzer_optimize_grouping_sets_keys 02481_low_cardinality_with_short_circuit_functins_mutations 02481_xxh3_hash_function 02482_if_with_nothing_argument @@ -1681,7 +1702,8 @@ 02560_null_as_default 02560_quantile_min_max 02561_sorting_constants_and_distinct_crash -02564_analyzer_ssb_cross_to_inner +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02564_analyzer_ssb_cross_to_inner 02564_date_format 02564_read_in_order_final_desc 02565_update_empty_nested @@ -1712,7 +1734,8 @@ 02679_explain_merge_tree_prewhere_row_policy 02680_instr_alias_for_position_case_insensitive 02681_aggregation_by_partitions_bug -02681_comparsion_tuple_elimination_ast +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02681_comparsion_tuple_elimination_ast 02690_subquery_identifiers 02691_multiple_joins_backtick_identifiers 02692_multiple_joins_unicode @@ -1721,7 +1744,8 @@ 02699_polygons_sym_difference_rollup 02699_polygons_sym_difference_total_analyzer 02700_regexp_operator -02702_logical_optimizer_with_nulls +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02702_logical_optimizer_with_nulls 02705_grouping_keys_equal_keys 02705_projection_and_ast_optimizations_bug 02707_analyzer_nested_lambdas_types @@ -1778,7 +1802,8 @@ 02784_move_all_conditions_to_prewhere_analyzer_asan 02784_projections_read_in_order_bug 02784_schema_inference_null_as_default -02785_date_predicate_optimizations_ast_query_tree_rewrite +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02785_date_predicate_optimizations_ast_query_tree_rewrite 02785_summing_merge_tree_datetime64 02786_transform_float 02787_transform_null @@ -1858,7 +1883,8 @@ 02866_size_of_marks_skip_idx_explain 02867_null_lc_in_bug 02867_nullable_primary_key_final -02868_distinct_to_count_optimization +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02868_distinct_to_count_optimization 02869_unicode_minus 02871_join_on_system_errors 02874_infer_objects_as_named_tuples @@ -1875,7 +1901,8 @@ 02884_virtual_column_order_by 02886_binary_like 02888_integer_type_inference_in_if_function -02888_obsolete_settings +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02888_obsolete_settings 02888_single_state_nullable_type 02889_system_drop_format_schema 02890_partition_prune_in_extra_columns @@ -1959,7 +1986,8 @@ 02968_full_sorting_join_fuzz 02968_sumMap_with_nan 02968_url_args -02969_analyzer_eliminate_injective_functions +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 02969_analyzer_eliminate_injective_functions 02969_functions_to_subcolumns_if_null 02970_generate_series 02971_functions_to_subcolumns_column_names @@ -2009,7 +2037,8 @@ 03003_sql_json_nonsense 03006_buffer_overflow_join 03006_mv_deduplication_throw_if_async_insert -03006_parallel_replicas_cte_explain_syntax_crash +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 03006_parallel_replicas_cte_explain_syntax_crash 03007_column_nullable_uninitialzed_value 03008_filter_projections_non_deterministoc_functions 03008_groupSortedArray_field @@ -2207,8 +2236,10 @@ 03164_early_constant_folding_analyzer 03164_optimize_read_in_order_nullable 03165_distinct_with_window_func_crash -03165_order_by_duplicate -03165_string_functions_with_token_text_indexes +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 03165_order_by_duplicate +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 03165_string_functions_with_token_text_indexes 03166_mv_prewhere_duplicating_name_bug 03167_base64_url_functions_sh 03167_empty_tuple_concat @@ -2411,8 +2442,10 @@ 03282_json_equal_comparison 03282_parallel_join_with_additional_filter 03283_json_binary_serialization_use_default_settings -03285_analyzer_extract_common_expr_bug -03285_analyzer_optimize_disjunctions +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 03285_analyzer_extract_common_expr_bug +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 03285_analyzer_optimize_disjunctions 03286_collation_locale_with_modifier 03286_format_datetime_timezones 03286_serialization_hint_system_columns @@ -2490,11 +2523,13 @@ 03365_time_to_time64_conv_bug 03366_bfloat16_sorting 03366_with_fill_dag -03367_bfloat16_tuple_final +# TODO: failing against latest ClickHouse stable; uses new server feature not yet in the latest Docker release +# 03367_bfloat16_tuple_final 03368_bfloat16_merge_join 03369_bfloat16_map 03370_join_identifiers -03371_bfloat16_special_values +# TODO: failing against latest ClickHouse stable; uses new server feature not yet in the latest Docker release +# 03371_bfloat16_special_values 03371_nullable_tuple_string_comparison 03374_date_trunc_with_negatives 03375_bloom_filter_array_equals @@ -2625,7 +2660,8 @@ 03594_coalescing_merge_tree_segfault 03594_funcs_on_empty_arguments 03594_json_extract_decimal_precision -03594_like_perfect_affix_rewrite_pass +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 03594_like_perfect_affix_rewrite_pass 03594_push_more_filters_down_joins 03595_alter_if_exists_mixed_commands 03595_alter_if_exists_runtime_check @@ -2636,7 +2672,8 @@ 03600_analyzer_setting_bool 03600_replace_fixed_string_bug 03601_histogram_quantile -03601_inconsistent_table_names +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 03601_inconsistent_table_names 03601_insert_squashing_remove_const 03601_json_from_string_accurate_cast_or_null 03601_replace_regex_fixedstring_empty_needle @@ -2697,7 +2734,8 @@ 03644_min_level_for_wide_part 03644_rows_before_aggregation_in_order 03651_positional_argument_agg_projection -03652_coalescing_merge_tree_fix_empty_tuple +# TODO: failing against latest ClickHouse stable; uses new server feature not yet in the latest Docker release +# 03652_coalescing_merge_tree_fix_empty_tuple 03652_join_using_legacy_step 03652_union_columns_2 03653_fractional_limit_offset @@ -2720,7 +2758,8 @@ # 03701_limit_by_in_order 03702_encode_decode_memory_usage 03702_json_datetime_format_settings -03702_optimize_inverse_dictionary_lookup_composite_and_layouts +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 03702_optimize_inverse_dictionary_lookup_composite_and_layouts 03703_function_dict_get_keys_large 03703_statistics_low_cardinality 03704_default_empty_order_by @@ -2738,7 +2777,8 @@ 03708_join_or_to_right_any_bug 03708_low_cardinality_aggregate_state_compatibility 03708_statistics_estimator_cast_type -03709_anti_join_runtime_filters +# TODO: failing against latest ClickHouse stable; uses new server feature not yet in the latest Docker release +# 03709_anti_join_runtime_filters 03709_coalescing_final 03709_final_prewhere_special_columns 03709_remove_unused_columns_from_prewhere @@ -2822,7 +2862,8 @@ 03760_join_reorder_outer_inner_nulls 03761_convert_outer_to_inner_join_keeps_header 03761_count_distinct_optimization_window -03761_inconsistent_ast_formatting +# TODO: failing against latest ClickHouse stable; upstream changed EXPLAIN SYNTAX formatting (operator syntax vs function call syntax) +# 03761_inconsistent_ast_formatting 03761_lazy_materialization_split_expr 03761_log_with_string_size 03762_count_distinct_optimization_multiple_columns diff --git a/vitest.node.config.ts b/vitest.node.config.ts index 65cecf043..7171ab820 100644 --- a/vitest.node.config.ts +++ b/vitest.node.config.ts @@ -7,10 +7,11 @@ if ( testMode !== "tls" && testMode !== "common" && testMode !== "common-integration" && + testMode !== "oss-dependents" && testMode !== "all" ) { throw new Error( - `Unsupported TEST_MODE: [${testMode}]. Supported modes are: unit, integration, tls, common, common-integration, all.`, + `Unsupported TEST_MODE: [${testMode}]. Supported modes are: unit, integration, tls, common, common-integration, oss-dependents, all.`, ); } @@ -37,6 +38,13 @@ const collections = { "common-integration": [ "packages/client-common/__tests__/integration/*.test.ts", ], + // Runnable reproductions of how the top OSS dependents use the client. + // Unlike the other (fast, build-free) modes, these are e2e-style guards: they + // import the public package names and resolve to the BUILT workspace packages + // (see the resolve.alias note below), so a breaking change in the published + // surface fails the matching consumer's test. `npm run build` must run first. + // See packages/client-node/__tests__/oss-dependents. + "oss-dependents": ["packages/client-node/__tests__/oss-dependents/*.test.ts"], all: [ "packages/client-common/__tests__/unit/*.test.ts", "packages/client-common/__tests__/utils/*.test.ts", @@ -45,6 +53,7 @@ const collections = { "packages/client-node/__tests__/unit/*.test.ts", "packages/client-node/__tests__/utils/*.test.ts", "packages/client-node/__tests__/integration/*.test.ts", + "packages/client-node/__tests__/oss-dependents/*.test.ts", ], }; @@ -95,10 +104,25 @@ export default defineConfig({ retry: process.env.CI ? 2 : 0, }, resolve: { - alias: { - "@clickhouse/client-common": "packages/client-common/src", - "@clickhouse/client-node": "packages/client-node/src", - "@test": "packages/client-common/__tests__", - }, + // The oss-dependents specs import the published package names (`@clickhouse/ + // client`, `-web`, `-common`) exactly as the upstream dependents do; those + // resolve through the node_modules workspace symlinks to the BUILT packages + // (run `npm run build` first) — an e2e-style guard against the published + // surface rather than `src`. `@clickhouse/client-node` is not a real package + // name (the node client publishes as `@clickhouse/client`); it is an + // internal alias the shared node setup/util files import, so we repoint it + // at the built node `dist` for this mode. Every other mode aliases the + // workspace `src` instead for a fast, build-free unit/integration loop. + alias: + testMode === "oss-dependents" + ? { + "@clickhouse/client-node": "packages/client-node/dist", + "@test": "packages/client-common/__tests__", + } + : { + "@clickhouse/client-common": "packages/client-common/src", + "@clickhouse/client-node": "packages/client-node/src", + "@test": "packages/client-common/__tests__", + }, }, });