From ed25b25893241eda007bf4412dee16f0d650de1a Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Jun 2026 21:49:18 +0000 Subject: [PATCH 1/5] Run web Vitest browser tests headless by default (#930) ## Summary The web Vitest suite (`vitest.web.config.ts`) left `browser.headless` unset, so Vitest launched a visible browser window when run locally and only fell back to headless in CI. This makes the web tests open a browser window on every local run. ## Changes - **Default to headless**: set `browser.headless` based on a new `BROWSER_HEADED` env var, so the runner stays headless unless explicitly opted out. ```ts browser: { enabled: true, // headless by default; set BROWSER_HEADED=true for a visible browser (debugging) headless: process.env.BROWSER_HEADED !== "true", provider: playwright(), instances: [{ browser }], }, ``` ## Checklist Delete items not relevant to your PR: - [ ] A human-readable description of the changes was provided to include in CHANGELOG Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- vitest.web.config.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vitest.web.config.ts b/vitest.web.config.ts index a4080bf67..496699998 100644 --- a/vitest.web.config.ts +++ b/vitest.web.config.ts @@ -133,6 +133,11 @@ export default defineConfig({ }, browser: { enabled: true, + // Run headless by default so the test runner never pops up a browser + // window (locally Vitest would otherwise launch a headed browser; it only + // defaults to headless in CI). Set BROWSER_HEADED=true to opt back into a + // visible browser, e.g. for debugging. + headless: process.env.BROWSER_HEADED !== "true", provider: playwright(), instances: [{ browser }], }, From 199f99460ab2fda2c87544bd4a7dad8e7509f60f Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 30 Jun 2026 11:19:31 +0200 Subject: [PATCH 2/5] Embed Vitest configs into client packages; run common tests from node/web (#931) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary The common package is now just a shared source folder, but it still carried its own test wiring (configs, scripts, CI jobs). This moves the Node.js and Web Vitest configs into their respective packages and runs the common specs as part of each client's `unit`/`integration` suites, dropping the standalone common test path entirely. - **Configs embedded in packages**: `vitest.{node,web}.config.ts`, setup, and otel files moved from repo root to `packages/client-node/` and `packages/client-web/`. Each config is repo-rooted so shared `client-common` sources/specs stay reachable; coverage confirms 16 `client-common/src` files are instrumented by each client run. - **Common folded into node/web collections**: `unit`/`integration` (+ `tls`/`jwt`/`all`) now include the common specs; the `common` and `common-integration` modes are removed. `client-common` has no test command. - **Scripts run from package folders**: `test:unit`, `test:integration`, etc. live in each client package; root `test:node:*`/`test:web:*` delegate via `npm --prefix`. All `test:common:*` scripts removed. - **Wiring removed**: deleted `common-unit-tests` jobs (`tests-node`, `tests-web`, `tests-bun`), updated CI path filters, `codecov.yml` flags (9→7), and `CONTRIBUTING.md`. ## Checklist - [ ] For significant changes, documentation in https://github.com/ClickHouse/clickhouse-docs was updated with further explanations or tutorials --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Peter Leonov Co-authored-by: Claude Opus 4.8 (1M context) --- .github/workflows/examples.yml | 16 ++--- .github/workflows/tests-bun.yml | 33 +++------- .github/workflows/tests-dist.yml | 16 ++--- .github/workflows/tests-node.yml | 58 +++--------------- .github/workflows/tests-oss-dependents.yml | 16 ++--- .github/workflows/tests-web.yml | 61 +++---------------- CONTRIBUTING.md | 17 +++--- codecov.yml | 12 ++-- package.json | 41 ++++++------- packages/client-node/eslint.config.mjs | 5 +- packages/client-node/package.json | 12 +++- .../client-node/vitest.config.ts | 34 ++++++----- .../client-node/vitest.otel.js | 0 .../client-node/vitest.setup.ts | 0 packages/client-web/eslint.config.mjs | 5 +- packages/client-web/package.json | 10 ++- .../client-web/vitest.config.ts | 29 ++++----- .../client-web/vitest.otel.js | 0 .../client-web/vitest.setup.ts | 0 19 files changed, 137 insertions(+), 228 deletions(-) rename vitest.node.config.ts => packages/client-node/vitest.config.ts (89%) rename vitest.node.otel.js => packages/client-node/vitest.otel.js (100%) rename vitest.node.setup.ts => packages/client-node/vitest.setup.ts (100%) rename vitest.web.config.ts => packages/client-web/vitest.config.ts (90%) rename vitest.web.otel.js => packages/client-web/vitest.otel.js (100%) rename vitest.web.setup.ts => packages/client-web/vitest.setup.ts (100%) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 22757f7b1..996ae342d 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -17,10 +17,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/examples.yml" pull_request: paths: @@ -33,10 +33,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/examples.yml" concurrency: diff --git a/.github/workflows/tests-bun.yml b/.github/workflows/tests-bun.yml index 897bdffbf..6ab380e8d 100644 --- a/.github/workflows/tests-bun.yml +++ b/.github/workflows/tests-bun.yml @@ -16,10 +16,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-bun.yml" pull_request: paths: @@ -31,10 +31,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-bun.yml" concurrency: @@ -42,23 +42,6 @@ concurrency: cancel-in-progress: true jobs: - common-unit-tests: - timeout-minutes: 5 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - - name: Setup Bun - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - - - name: Install dependencies - run: | - bun install - - - name: Run common unit tests - run: | - npm run test:common:unit:bun - node-unit-tests: timeout-minutes: 5 runs-on: ubuntu-latest diff --git a/.github/workflows/tests-dist.yml b/.github/workflows/tests-dist.yml index 49279e0cd..70f5ba967 100644 --- a/.github/workflows/tests-dist.yml +++ b/.github/workflows/tests-dist.yml @@ -16,10 +16,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-dist.yml" pull_request: paths: @@ -31,10 +31,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-dist.yml" schedule: diff --git a/.github/workflows/tests-node.yml b/.github/workflows/tests-node.yml index b509b334f..a06a8f976 100644 --- a/.github/workflows/tests-node.yml +++ b/.github/workflows/tests-node.yml @@ -16,10 +16,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-node.yml" pull_request: paths: @@ -31,10 +31,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-node.yml" schedule: @@ -100,48 +100,6 @@ jobs: fi cat prettier-output.txt - common-unit-tests: - timeout-minutes: 5 - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - node: [20, 22, 24, 26] - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - - name: Setup NodeJS ${{ matrix.node }} - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: ${{ matrix.node }} - - - name: Install dependencies - run: | - npm install - - - name: Run unit tests - run: | - npm run test:common:unit:node - - - name: Export coverage metrics - env: - COVERAGE_REPORT_NAME: ${{ github.job }} (${{ matrix.node }}) - 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 diff --git a/.github/workflows/tests-oss-dependents.yml b/.github/workflows/tests-oss-dependents.yml index c48d22987..cf7edd61b 100644 --- a/.github/workflows/tests-oss-dependents.yml +++ b/.github/workflows/tests-oss-dependents.yml @@ -16,10 +16,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-oss-dependents.yml" pull_request: paths: @@ -31,10 +31,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-oss-dependents.yml" schedule: diff --git a/.github/workflows/tests-web.yml b/.github/workflows/tests-web.yml index 4fb2bae42..a3424a48e 100644 --- a/.github/workflows/tests-web.yml +++ b/.github/workflows/tests-web.yml @@ -16,10 +16,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-web.yml" pull_request: paths: @@ -31,10 +31,10 @@ on: - "tsconfig.dev.json" - "eslint.config.base.mjs" - "docker-compose.yml" - - "vitest.node.config.ts" - - "vitest.node.setup.ts" - - "vitest.web.config.ts" - - "vitest.web.setup.ts" + - "packages/client-node/vitest.config.ts" + - "packages/client-node/vitest.setup.ts" + - "packages/client-web/vitest.config.ts" + - "packages/client-web/vitest.setup.ts" - ".github/workflows/tests-web.yml" schedule: @@ -59,51 +59,6 @@ env: NPM_CONFIG_FETCH_TIMEOUT: "600000" jobs: - common-unit-tests: - timeout-minutes: 5 - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - browser: [chromium, firefox] # We're not testing in WebKit atm - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - - name: Setup NodeJS - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: 24 - - - name: Install dependencies - run: | - npm install - npx playwright install ${{ matrix.browser }} - - - name: Run unit tests (${{ matrix.browser }}) - env: - BROWSER: ${{ matrix.browser }} - run: | - npm run test:common:unit:web - - - name: Export coverage metrics - env: - COVERAGE_REPORT_NAME: ${{ github.job }} (${{ matrix.browser }}) - 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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2c3ef219b..4df45ab5a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,13 +53,12 @@ everyone in the community can safely benefit from your contribution. We use [Vitest](https://vitest.dev/) as the test runner and the testing framework. It covers a variety of testing needs, including unit and integration tests, and supports both Node.js, Web environments and edge runtimes. -The repository uses three consolidated Vitest configuration files: +The repository keeps two Vitest configuration files, embedded in the client packages: -- `vitest.client-common.config.ts` - Tests for the common client package -- `vitest.node.config.ts` - Tests for the Node.js client package -- `vitest.web.config.ts` - Tests for the Web client package +- `packages/client-node/vitest.config.ts` - Tests for the Node.js client package +- `packages/client-web/vitest.config.ts` - Tests for the Web client package -Each config supports multiple test modes controlled by the `TEST_MODE` environment variable, allowing different test scenarios (unit, integration, TLS, etc.) to be run with a single configuration file. +The shared (common) sources live in `packages/client-common` and are bundled into both clients; the common specs are run as part of the Node.js and Web test suites, so the common code is covered without a separate config. Each config supports multiple test modes controlled by the `TEST_MODE` environment variable, allowing different test scenarios (unit, integration, TLS, etc.) to be run with a single configuration file. ### Type checking and linting @@ -89,11 +88,11 @@ treat all warnings as errors that must be fixed before merging. Does not require a running ClickHouse server. ```bash -# Run common unit tests -npm run test:common:unit - -# Run Node.js unit tests +# Run Node.js unit tests (also runs the common unit tests) npm run test:node:unit + +# Run Web unit tests (also runs the common unit tests) +npm run test:web:unit ``` ### Running integration tests diff --git a/codecov.yml b/codecov.yml index f5fbfcea2..88e312ce9 100644 --- a/codecov.yml +++ b/codecov.yml @@ -16,18 +16,16 @@ coverage: # 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) +# => 7 uploads total (one per flag) # -# `after_n_builds` therefore equals the number of flags (9). When a flag is +# `after_n_builds` therefore equals the number of flags (7). 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 @@ -36,11 +34,11 @@ codecov: 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 + after_n_builds: 7 comment: # Wait for all uploads before posting/updating the PR comment. - after_n_builds: 9 + after_n_builds: 7 flag_management: default_rules: @@ -49,12 +47,10 @@ flag_management: # 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/package.json b/package.json index 764d19367..8a465a4b2 100644 --- a/package.json +++ b/package.json @@ -24,29 +24,24 @@ "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", - "test:common:unit:web": "CLICKHOUSE_TEST_SKIP_INIT=1 TEST_MODE=common vitest -c vitest.web.config.ts", - "test:common:integration:node": "TEST_MODE=common-integration vitest -c vitest.node.config.ts", - "test:common:integration:web": "TEST_MODE=common-integration vitest -c vitest.web.config.ts", - "test:node:unit": "CLICKHOUSE_TEST_SKIP_INIT=1 TEST_MODE=unit vitest -c vitest.node.config.ts", - "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:integration:dist": "npm run build && TEST_TARGET=dist 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", - "test:node:coverage": "VITEST_COVERAGE=true TEST_MODE=all vitest -c vitest.node.config.ts", - "test:web:unit": "CLICKHOUSE_TEST_SKIP_INIT=1 TEST_MODE=unit vitest -c vitest.web.config.ts", - "test:web:integration": "TEST_MODE=integration vitest -c vitest.web.config.ts", - "test:web:integration:dist": "npm run build && TEST_TARGET=dist TEST_MODE=integration vitest -c vitest.web.config.ts", - "test:web:integration:local_cluster": "TEST_MODE=integration CLICKHOUSE_TEST_ENVIRONMENT=local_cluster vitest -c vitest.web.config.ts", - "test:web:integration:cloud": "TEST_MODE=integration CLICKHOUSE_TEST_ENVIRONMENT=cloud vitest -c vitest.web.config.ts", - "test:web:integration:cloud:jwt": "TEST_MODE=jwt CLICKHOUSE_TEST_ENVIRONMENT=cloud vitest -c vitest.web.config.ts", - "test:web:all": "TEST_MODE=all vitest -c vitest.web.config.ts", - "test:web:coverage": "VITEST_COVERAGE=true TEST_MODE=all vitest -c vitest.web.config.ts", + "test:node:unit": "npm --prefix packages/client-node run test:unit", + "test:node:unit:bun": "npm --prefix packages/client-node run test:unit:bun", + "test:node:integration:tls": "npm --prefix packages/client-node run test:integration:tls", + "test:node:integration": "npm --prefix packages/client-node run test:integration", + "test:node:integration:dist": "npm --prefix packages/client-node run test:integration:dist", + "test:node:oss-dependents": "npm --prefix packages/client-node run test:oss-dependents", + "test:node:integration:local_cluster": "npm --prefix packages/client-node run test:integration:local_cluster", + "test:node:integration:cloud": "npm --prefix packages/client-node run test:integration:cloud", + "test:node:all": "npm --prefix packages/client-node run test:all", + "test:node:coverage": "npm --prefix packages/client-node run test:coverage", + "test:web:unit": "npm --prefix packages/client-web run test:unit", + "test:web:integration": "npm --prefix packages/client-web run test:integration", + "test:web:integration:dist": "npm --prefix packages/client-web run test:integration:dist", + "test:web:integration:local_cluster": "npm --prefix packages/client-web run test:integration:local_cluster", + "test:web:integration:cloud": "npm --prefix packages/client-web run test:integration:cloud", + "test:web:integration:cloud:jwt": "npm --prefix packages/client-web run test:integration:cloud:jwt", + "test:web:all": "npm --prefix packages/client-web run test:all", + "test:web:coverage": "npm --prefix packages/client-web run test:coverage", "//": "See https://github.com/kylebarron/parquet-wasm/issues/798", "postinstall": "cd node_modules/parquet-wasm && npm pkg delete type", "prepare": "husky" diff --git a/packages/client-node/eslint.config.mjs b/packages/client-node/eslint.config.mjs index d142e6c9f..cc8c651d5 100644 --- a/packages/client-node/eslint.config.mjs +++ b/packages/client-node/eslint.config.mjs @@ -19,8 +19,9 @@ export default defineConfig( ignores: [ "./__tests__/**/*.ts", "eslint.config.mjs", - "vitest.*.config.ts", - "vitest.*.setup.ts", + "vitest.config.ts", + "vitest.setup.ts", + "vitest.otel.js", "coverage", "out", "dist", diff --git a/packages/client-node/package.json b/packages/client-node/package.json index d8e0941e9..2399b53a3 100644 --- a/packages/client-node/package.json +++ b/packages/client-node/package.json @@ -46,7 +46,17 @@ "typecheck": "tsc --noEmit", "lint": "eslint --max-warnings=0 .", "lint:fix": "eslint . --fix", - "build": "rm -rf dist; tsc" + "build": "rm -rf dist; tsc", + "test:unit": "CLICKHOUSE_TEST_SKIP_INIT=1 TEST_MODE=unit vitest", + "test:unit:bun": "CLICKHOUSE_TEST_SKIP_INIT=1 TEST_MODE=unit bun --bun vitest", + "test:integration": "TEST_MODE=integration vitest", + "test:integration:tls": "TEST_MODE=tls vitest", + "test:integration:dist": "npm --prefix ../.. run build && TEST_TARGET=dist TEST_MODE=integration vitest", + "test:integration:local_cluster": "CLICKHOUSE_TEST_ENVIRONMENT=local_cluster TEST_MODE=integration vitest", + "test:integration:cloud": "CLICKHOUSE_TEST_ENVIRONMENT=cloud TEST_MODE=integration vitest", + "test:oss-dependents": "TEST_MODE=oss-dependents vitest", + "test:all": "TEST_MODE=all vitest", + "test:coverage": "VITEST_COVERAGE=true TEST_MODE=all vitest" }, "dependencies": {}, "devDependencies": { diff --git a/vitest.node.config.ts b/packages/client-node/vitest.config.ts similarity index 89% rename from vitest.node.config.ts rename to packages/client-node/vitest.config.ts index 88268c89e..f29503b36 100644 --- a/vitest.node.config.ts +++ b/packages/client-node/vitest.config.ts @@ -1,17 +1,27 @@ import { defineConfig } from "vitest/config"; +import { fileURLToPath } from "node:url"; + +// Embedded in the node client package, but rooted at the repo so the shared +// (common) sources and specs are reachable. The node and web packages run the +// common tests so the common code is exercised and shows up in coverage. +const root = fileURLToPath(new URL("../..", import.meta.url)); + +// The package scripts run vitest via `npm --prefix packages/client-node`, which +// sets the process cwd to the package dir. Some specs read fixtures/certs via +// repo-root-relative paths (e.g. node_streaming_e2e, tls), so pin the cwd to the +// repo root to match `root` above. Workers inherit this cwd when they spawn. +process.chdir(root); const testMode = process.env.TEST_MODE; if ( testMode !== "unit" && testMode !== "integration" && 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, oss-dependents, all.`, + `Unsupported TEST_MODE: [${testMode}]. Supported modes are: unit, integration, tls, oss-dependents, all.`, ); } @@ -37,27 +47,22 @@ if (testTarget !== "src" && testTarget !== "dist") { const collections = { unit: [ + "packages/client-common/__tests__/unit/*.test.ts", + "packages/client-common/__tests__/utils/*.test.ts", "packages/client-node/__tests__/unit/*.test.ts", "packages/client-node/__tests__/utils/*.test.ts", ], integration: [ - "packages/client-node/__tests__/integration/*.test.ts", "packages/client-common/__tests__/integration/*.test.ts", + "packages/client-node/__tests__/integration/*.test.ts", ], // TLS tests require a specific environment setup // This list is integration + TLS tests tls: [ - "packages/client-node/__tests__/integration/*.test.ts", "packages/client-common/__tests__/integration/*.test.ts", + "packages/client-node/__tests__/integration/*.test.ts", "packages/client-node/__tests__/tls/*.test.ts", ], - common: [ - "packages/client-common/__tests__/unit/*.test.ts", - "packages/client-common/__tests__/utils/*.test.ts", - ], - "common-integration": [ - "packages/client-common/__tests__/integration/*.test.ts", - ], // Runnable reproductions of how the top OSS dependents use the client. // These specs import only the public package names, so they default to // TEST_TARGET=dist (see above) and resolve to the BUILT workspace packages: @@ -78,6 +83,7 @@ const collections = { }; export default defineConfig({ + root, test: { // Increase maxWorkers to speed up integration tests // as we're not bound by the CPU here. @@ -86,7 +92,7 @@ export default defineConfig({ hookTimeout: 300_000, testTimeout: 300_000, slowTestThreshold: testMode === "unit" ? 10_000 : undefined, - setupFiles: ["vitest.node.setup.ts"], + setupFiles: ["packages/client-node/vitest.setup.ts"], include: collections[testMode], coverage: { enabled: process.env.VITEST_COVERAGE === "true", @@ -118,7 +124,7 @@ export default defineConfig({ process.env.VITEST_OTEL_ENABLED === "true" && // not set in dependabot PRs !!process.env.OTEL_EXPORTER_OTLP_ENDPOINT, - sdkPath: "./vitest.node.otel.js", + sdkPath: "./packages/client-node/vitest.otel.js", }, }, retry: process.env.CI ? 2 : 0, diff --git a/vitest.node.otel.js b/packages/client-node/vitest.otel.js similarity index 100% rename from vitest.node.otel.js rename to packages/client-node/vitest.otel.js diff --git a/vitest.node.setup.ts b/packages/client-node/vitest.setup.ts similarity index 100% rename from vitest.node.setup.ts rename to packages/client-node/vitest.setup.ts diff --git a/packages/client-web/eslint.config.mjs b/packages/client-web/eslint.config.mjs index 0a540ee80..7217144d0 100644 --- a/packages/client-web/eslint.config.mjs +++ b/packages/client-web/eslint.config.mjs @@ -13,8 +13,9 @@ export default defineConfig( ignores: [ "./__tests__/**/*.ts", "eslint.config.mjs", - "vitest.*.config.ts", - "vitest.*.setup.ts", + "vitest.config.ts", + "vitest.setup.ts", + "vitest.otel.js", "coverage", "out", "dist", diff --git a/packages/client-web/package.json b/packages/client-web/package.json index dec875f8f..f5e376631 100644 --- a/packages/client-web/package.json +++ b/packages/client-web/package.json @@ -29,7 +29,15 @@ "typecheck": "tsc --noEmit", "lint": "eslint --max-warnings=0 .", "lint:fix": "eslint . --fix", - "build": "rm -rf dist; tsc" + "build": "rm -rf dist; tsc", + "test:unit": "CLICKHOUSE_TEST_SKIP_INIT=1 TEST_MODE=unit vitest", + "test:integration": "TEST_MODE=integration vitest", + "test:integration:dist": "npm --prefix ../.. run build && TEST_TARGET=dist TEST_MODE=integration vitest", + "test:integration:local_cluster": "CLICKHOUSE_TEST_ENVIRONMENT=local_cluster TEST_MODE=integration vitest", + "test:integration:cloud": "CLICKHOUSE_TEST_ENVIRONMENT=cloud TEST_MODE=integration vitest", + "test:integration:cloud:jwt": "CLICKHOUSE_TEST_ENVIRONMENT=cloud TEST_MODE=jwt vitest", + "test:all": "TEST_MODE=all vitest", + "test:coverage": "VITEST_COVERAGE=true TEST_MODE=all vitest" }, "dependencies": {} } diff --git a/vitest.web.config.ts b/packages/client-web/vitest.config.ts similarity index 90% rename from vitest.web.config.ts rename to packages/client-web/vitest.config.ts index 496699998..ca515c255 100644 --- a/vitest.web.config.ts +++ b/packages/client-web/vitest.config.ts @@ -2,6 +2,11 @@ import { defineConfig } from "vitest/config"; import { playwright } from "@vitest/browser-playwright"; import { fileURLToPath } from "node:url"; +// Embedded in the web client package, but rooted at the repo so the shared +// (common) sources and specs are reachable. The node and web packages run the +// common tests so the common code is exercised and shows up in coverage. +const root = fileURLToPath(new URL("../..", import.meta.url)); + const browser = process.env.BROWSER ?? "chromium"; if (browser !== "chromium" && browser !== "firefox" && browser !== "webkit") { throw new Error( @@ -14,8 +19,6 @@ if ( testMode !== "unit" && testMode !== "integration" && testMode !== "jwt" && - testMode !== "common" && - testMode !== "common-integration" && testMode !== "all" ) { throw new Error( @@ -57,13 +60,6 @@ const collections = { "packages/client-web/__tests__/integration/*.test.ts", "packages/client-web/__tests__/jwt/*.test.ts", ], - common: [ - "packages/client-common/__tests__/unit/*.test.ts", - "packages/client-common/__tests__/utils/*.test.ts", - ], - "common-integration": [ - "packages/client-common/__tests__/integration/*.test.ts", - ], all: [ "packages/client-common/__tests__/unit/*.test.ts", "packages/client-common/__tests__/utils/*.test.ts", @@ -75,6 +71,7 @@ const collections = { }; export default defineConfig({ + root, test: { // Increase maxWorkers to speed up integration tests // as we're not bound by the CPU here. @@ -83,7 +80,7 @@ export default defineConfig({ hookTimeout: 300_000, testTimeout: 300_000, slowTestThreshold: testMode === "unit" ? 10_000 : undefined, - setupFiles: ["vitest.web.setup.ts"], + setupFiles: ["packages/client-web/vitest.setup.ts"], include: collections[testMode], coverage: { enabled: process.env.VITEST_COVERAGE === "true", @@ -124,11 +121,11 @@ export default defineConfig({ process.env.VITEST_OTEL_ENABLED === "true" && // not set in dependabot PRs !!process.env.OTEL_EXPORTER_OTLP_ENDPOINT, - sdkPath: "./vitest.node.otel.js", + sdkPath: "./packages/client-node/vitest.otel.js", // According to testing, runners hang indefinitely when OTEL is enabled in browser tests, // and when they don't the exporter visibly slows the tests down (2x-5x). // Tests also crash (their iframe?) when the devtools are open in Chrome. - // browserSdkPath: './vitest.web.otel.js', + // browserSdkPath: './packages/client-web/vitest.otel.js', }, }, browser: { @@ -170,18 +167,18 @@ export default defineConfig({ // intact, and common-origin symbols share the client's one bundle. "@clickhouse/client-common": "@clickhouse/client-web", "@test": fileURLToPath( - new URL("./packages/client-common/__tests__", import.meta.url), + new URL("packages/client-common/__tests__", `file://${root}/`), ), } : { "@clickhouse/client-common": fileURLToPath( - new URL("./packages/client-common/src", import.meta.url), + new URL("packages/client-common/src", `file://${root}/`), ), "@clickhouse/client-web": fileURLToPath( - new URL("./packages/client-web", import.meta.url), + new URL("packages/client-web", `file://${root}/`), ), "@test": fileURLToPath( - new URL("./packages/client-common/__tests__", import.meta.url), + new URL("packages/client-common/__tests__", `file://${root}/`), ), }, }, diff --git a/vitest.web.otel.js b/packages/client-web/vitest.otel.js similarity index 100% rename from vitest.web.otel.js rename to packages/client-web/vitest.otel.js diff --git a/vitest.web.setup.ts b/packages/client-web/vitest.setup.ts similarity index 100% rename from vitest.web.setup.ts rename to packages/client-web/vitest.setup.ts From 8c51d9a12e67e82ef431e8158d5b77ce26e40e3a Mon Sep 17 00:00:00 2001 From: Peter Leonov Date: Tue, 30 Jun 2026 13:05:36 +0200 Subject: [PATCH 3/5] ci: run RowBinary skill benchmarks on a live ClickHouse (#933) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What Adds `.github/workflows/bench-skill-rowbinary.yml`, a dedicated workflow that runs the `@clickhouse/rowbinary` skill's benchmark suite (`npm run bench`) against a ClickHouse service container. It prints the tinybench summary to the job log (per-bench `hz` + the "Nx faster" lines, including the ledger **RowBinary vs JSONEachRow** comparison and the **monomorphized vs API-combinator** reader comparisons) and uploads the same numbers as a JSON artifact (`rowbinary-bench-results`). ## Why Numbers from this suite are cited externally (an upcoming `@clickhouse/rowbinary` blog post: RowBinary-vs-JSON throughput on numeric-heavy schemas, and the monomorphized-vs-naive parser speedup). Today those numbers can only be produced on a maintainer's laptop — `npm run bench` needs a live server and isn't run anywhere in CI. This gives them a **timestamped, third-party-reproducible CI artifact** instead. The "Record environment" step logs Node version, CPU, and `SELECT version()` so each run's log is self-describing. ## Design notes - **Decoupled from the correctness suite** (`tests-skill-rowbinary.yml`): benchmarks are slower and their throughput numbers are noisy, so they shouldn't gate every PR. Triggers on `workflow_dispatch` + PRs touching the skill / this workflow. - Reuses the existing `docker-compose.yml` `clickhouse` service and the local-`@clickhouse/datatype-parser` pack/install pattern from `tests-skill-rowbinary.yml`, so the skill is benchmarked against this checkout, not the published parser. - Single cell (Node 24, ClickHouse `latest`) — enough for a reference artifact without a full matrix. Draft: opened to produce the first CI bench log/artifact and let maintainers decide whether to keep it as-is. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) --- .github/workflows/bench-skill-rowbinary.yml | 101 ++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 .github/workflows/bench-skill-rowbinary.yml diff --git a/.github/workflows/bench-skill-rowbinary.yml b/.github/workflows/bench-skill-rowbinary.yml new file mode 100644 index 000000000..16b312939 --- /dev/null +++ b/.github/workflows/bench-skill-rowbinary.yml @@ -0,0 +1,101 @@ +name: "skill: rowbinary benchmarks" + +# Runs the RowBinary skill's benchmark suite (npm run bench) against a live +# ClickHouse server so the numbers cited externally (e.g. the @clickhouse/rowbinary +# blog post: RowBinary vs JSON, monomorphized vs API-combinator readers) have a +# timestamped, third-party-reproducible CI log + a machine-readable JSON artifact +# behind them — not just a maintainer's laptop. +# +# Decoupled from the correctness suite (tests-skill-rowbinary.yml): benchmarks are +# slower and their throughput numbers are noisy, so they shouldn't gate every PR. +# This runs on demand (workflow_dispatch) and on PRs that touch the skill or this +# workflow. + +permissions: {} +on: + workflow_dispatch: + pull_request: + paths: + - .github/workflows/bench-skill-rowbinary.yml + - skills/clickhouse-js-node-rowbinary/** + - packages/datatype-parser/** + +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +env: + # Network resilience: npm's default of 2 fetch retries is not enough for + # the transient registry errors (ECONNRESET) we regularly hit in CI. + NPM_CONFIG_FETCH_RETRIES: "5" + NPM_CONFIG_FETCH_RETRY_MINTIMEOUT: "10000" + NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT: "60000" + NPM_CONFIG_FETCH_TIMEOUT: "600000" + +jobs: + benchmarks: + timeout-minutes: 20 + runs-on: ubuntu-latest + defaults: + run: + working-directory: skills/clickhouse-js-node-rowbinary + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Start ClickHouse (latest) in Docker + uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0 + env: + CLICKHOUSE_VERSION: latest + with: + # The benchmarks only need the single-node HTTP server on :8123. + compose-file: "docker-compose.yml" + services: "clickhouse" + down-flags: "--volumes" + + - name: Setup NodeJS + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 24 + + - name: Record environment (CPU, Node, ClickHouse version) + run: | + echo "Node: $(node -v)" + echo "CPU cores: $(nproc)" + grep -m1 'model name' /proc/cpuinfo || true + # The server may still be starting; poll briefly so the version is captured. + for _ in $(seq 1 30); do + chv=$(curl -s 'http://localhost:8123/?query=SELECT%20version()') + [ -n "$chv" ] && break + sleep 1 + done + echo "ClickHouse: ${chv:-}" + + # Build + pack the in-repo @clickhouse/datatype-parser so the skill is + # benchmarked against THIS checkout, not the version published to npm. The + # committed package.json keeps a published range for end users; we only + # override node_modules below (`npm install --no-save`). + - name: Pack local @clickhouse/datatype-parser + working-directory: ${{ github.workspace }} + run: | + npm ci + npm pack --workspace @clickhouse/datatype-parser --pack-destination "${{ runner.temp }}" + + - name: Install dependencies + run: npm ci + + - name: Use the local datatype-parser build + run: npm install "${{ runner.temp }}"/clickhouse-datatype-parser-*.tgz --no-save + + # Prints the human-readable tinybench summary (per-bench hz + "Nx faster" + # lines, incl. the ledger RowBinary-vs-JSON comparison) to the job log, and + # writes the same numbers as JSON for the uploaded artifact. + - name: Run benchmarks + run: npm run bench -- --outputJson "${{ runner.temp }}/rowbinary-bench-results.json" + + - name: Upload benchmark results (JSON) + if: ${{ always() }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: rowbinary-bench-results + path: ${{ runner.temp }}/rowbinary-bench-results.json + if-no-files-found: error From 305030d9714aca93e9b5f7e128408d7e41867bd0 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 30 Jun 2026 18:45:03 +0200 Subject: [PATCH 4/5] Separate per-package READMEs and stop prepack from overwriting them (#934) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Packages are now published independently, but `prepack` copied the root README into every package, so the npm pages for `@clickhouse/client`, `@clickhouse/client-web`, and `@clickhouse/client-common` were all identical. This adds dedicated READMEs per package and keeps the root README as the combined overview. - **`prepack` no longer overwrites READMEs** — dropped `cp ../../README.md` from `client-node`, `client-web`, and `client-common`; they still copy `LICENSE` (and `client-node` still bundles skills). npm always ships a package's own `README.md`, so no `files` change is needed. - **`.gitignore`** — removed `packages/*/README.md` so committed per-package READMEs survive (LICENSE/skills copies stay ignored). - **`client-node` / `client-web` READMEs** — runtime-specific overviews (APIs, environment requirements, quick start, links). - **`client-common` README** — leads with a deprecation warning; explains it *was* the shared base for building custom/alternative clients, why it's deprecated (each runtime package is now self-contained), and points to the fork-an-in-tree-package workflow in `ALTERNATIVE_CLIENTS.md`. - **Root README** unchanged — remains the summary for both main packages. ## Checklist - [ ] For significant changes, documentation in https://github.com/ClickHouse/clickhouse-docs was updated with further explanations or tutorials --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Peter Leonov Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .gitignore | 1 - packages/client-common/README.md | 55 ++++++++++++++++++ packages/client-common/package.json | 2 +- packages/client-node/README.md | 89 +++++++++++++++++++++++++++++ packages/client-node/package.json | 2 +- packages/client-web/README.md | 86 ++++++++++++++++++++++++++++ packages/client-web/package.json | 2 +- 7 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 packages/client-common/README.md create mode 100644 packages/client-node/README.md create mode 100644 packages/client-web/README.md diff --git a/.gitignore b/.gitignore index aed1a6009..4af759539 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,5 @@ out coverage coverage-web .nyc_output -packages/*/README.md packages/*/LICENSE packages/*/skills/ diff --git a/packages/client-common/README.md b/packages/client-common/README.md new file mode 100644 index 000000000..b7cb27636 --- /dev/null +++ b/packages/client-common/README.md @@ -0,0 +1,55 @@ +# @clickhouse/client-common + +> [!WARNING] +> **This package is deprecated and is no longer maintained as a dependency.** +> It is no longer used by [`@clickhouse/client`](https://www.npmjs.com/package/@clickhouse/client) +> (Node.js) or [`@clickhouse/client-web`](https://www.npmjs.com/package/@clickhouse/client-web) +> (Web), and there is **no replacement package** to depend on. Do not add this +> package to new projects. +> +> - Building a ClickHouse app on **Node.js**? Install +> [`@clickhouse/client`](https://www.npmjs.com/package/@clickhouse/client). +> - Building for the **browser / edge runtimes**? Install +> [`@clickhouse/client-web`](https://www.npmjs.com/package/@clickhouse/client-web). + +## What this package was for + +Historically, the shared code between `@clickhouse/client` (Node.js) and +`@clickhouse/client-web` lived in this third published package, +`@clickhouse/client-common`, which both of them depended on. It exposed the +shared types and the base framework that were also intended to be the foundation +for building **custom client implementations** for alternative runtimes (such as +Bun or Cloudflare Workers) or alternative protocols (such as the native +ClickHouse protocol or gRPC over a proxy). + +## Why it is deprecated + +The shared-package approach is being retired to simplify versioning across the +packages and to avoid the bundling/duplication issues that several downstream +users have hit. + +What this means in practice: + +- The shared code is **not** being moved into a new shared package; there is no + replacement to depend on. +- Instead, the shared code is now inlined / co-located inside each runtime + package (`@clickhouse/client`, `@clickhouse/client-web`, …). Going forward, + each runtime package is **self-contained** and published independently. + +## Building a client for an alternative runtime or protocol + +The new, recommended approach is to **fork an existing in-tree client package and +iterate on it** — copy the pieces you need into your own package the same way +`client-node` and `client-web` do, rather than depending on a shared package. + +See +[Building specialized clients for alternative runtimes and protocols](https://github.com/ClickHouse/clickhouse-js/blob/main/ALTERNATIVE_CLIENTS.md) +for the full guide. + +## Changelog + +See [`CHANGELOG.md`](https://github.com/ClickHouse/clickhouse-js/blob/main/packages/client-common/CHANGELOG.md). + +## License + +[Apache 2.0](https://github.com/ClickHouse/clickhouse-js/blob/main/LICENSE) diff --git a/packages/client-common/package.json b/packages/client-common/package.json index e5893e09a..cd04443af 100644 --- a/packages/client-common/package.json +++ b/packages/client-common/package.json @@ -22,7 +22,7 @@ ], "scripts": { "pack": "npm pack", - "prepack": "cp ../../README.md ../../LICENSE .", + "prepack": "cp ../../LICENSE .", "typecheck": "tsc --noEmit", "lint": "eslint --max-warnings=0 .", "lint:fix": "eslint . --fix", diff --git a/packages/client-node/README.md b/packages/client-node/README.md new file mode 100644 index 000000000..1b2bb94cd --- /dev/null +++ b/packages/client-node/README.md @@ -0,0 +1,89 @@ +# @clickhouse/client + +Official Node.js client for [ClickHouse](https://clickhouse.com/), written +purely in TypeScript and thoroughly tested against actual ClickHouse versions. + +It is built on top of the Node.js [HTTP](https://nodejs.org/api/http.html) and +[Stream](https://nodejs.org/api/stream.html) APIs and supports streaming for +both selects and inserts. The client has zero external dependencies and is +optimized for maximum performance. + +> Looking for a browser / edge runtime (Cloudflare Workers, etc.) instead? Use +> [`@clickhouse/client-web`](https://www.npmjs.com/package/@clickhouse/client-web). + +## Installation + +```sh +npm i @clickhouse/client +``` + +## Environment requirements + +Node.js must be available in the environment to run the client. The client is +compatible with all the [maintained](https://github.com/nodejs/release#readme) +Node.js releases. + +| Node.js version | Supported? | +| --------------- | ---------- | +| 26.x | ✔ | +| 24.x | ✔ | +| 22.x | ✔ | +| 20.x | ✔ | + +If using TypeScript, version +[4.5](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html) +or above is required to enable +[inline import and export syntax](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html#type-modifiers-on-import-names). + +## Compatibility with ClickHouse + +| Client version | ClickHouse | +| -------------- | ---------- | +| 1.12.0+ | 24.8+ | + +The client may work with older versions too; however, this is best-effort +support and is not guaranteed. + +## Quick start + +```ts +import { createClient } from "@clickhouse/client"; + +const client = createClient({ + url: process.env.CLICKHOUSE_URL ?? "http://localhost:8123", + username: process.env.CLICKHOUSE_USER ?? "default", + password: process.env.CLICKHOUSE_PASSWORD ?? "", +}); + +const resultSet = await client.query({ + query: "SELECT * FROM system.tables", + format: "JSONEachRow", +}); + +const tables = await resultSet.json(); +console.log(tables); + +await client.close(); +``` + +See more examples in the +[examples directory](https://github.com/ClickHouse/clickhouse-js/tree/main/examples). + +## Documentation + +See the [ClickHouse website](https://clickhouse.com/docs/integrations/javascript) +for the full documentation. + +## Changelog + +See [`CHANGELOG.md`](https://github.com/ClickHouse/clickhouse-js/blob/main/packages/client-node/CHANGELOG.md). + +## Contact us + +If you have any questions or need help, feel free to reach out to us in the +[Community Slack](https://clickhouse.com/slack) (`#clickhouse-js` channel) or +via [GitHub issues](https://github.com/ClickHouse/clickhouse-js/issues). + +## License + +[Apache 2.0](https://github.com/ClickHouse/clickhouse-js/blob/main/LICENSE) diff --git a/packages/client-node/package.json b/packages/client-node/package.json index 2399b53a3..21495a03a 100644 --- a/packages/client-node/package.json +++ b/packages/client-node/package.json @@ -42,7 +42,7 @@ }, "scripts": { "pack": "npm pack", - "prepack": "rm -rf skills && cp ../../README.md ../../LICENSE . && cp -r ../../skills . && RBP=skills/clickhouse-js-node-rowbinary && rm -rf $RBP/tests $RBP/node_modules $RBP/dist $RBP/package.json $RBP/package-lock.json $RBP/tsconfig.json $RBP/tsconfig.build.json $RBP/vitest.config.ts $RBP/.gitignore $RBP/LICENSE $RBP/eval_result*.md", + "prepack": "rm -rf skills && cp ../../LICENSE . && cp -r ../../skills . && RBP=skills/clickhouse-js-node-rowbinary && rm -rf $RBP/tests $RBP/node_modules $RBP/dist $RBP/package.json $RBP/package-lock.json $RBP/tsconfig.json $RBP/tsconfig.build.json $RBP/vitest.config.ts $RBP/.gitignore $RBP/LICENSE $RBP/eval_result*.md", "typecheck": "tsc --noEmit", "lint": "eslint --max-warnings=0 .", "lint:fix": "eslint . --fix", diff --git a/packages/client-web/README.md b/packages/client-web/README.md new file mode 100644 index 000000000..14b13f535 --- /dev/null +++ b/packages/client-web/README.md @@ -0,0 +1,86 @@ +# @clickhouse/client-web + +Official Web client for [ClickHouse](https://clickhouse.com/), written purely in +TypeScript and thoroughly tested against actual ClickHouse versions. + +It is built on top of the +[Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and +[Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) APIs +and supports streaming for selects. It is compatible with Chrome/Firefox +browsers and Cloudflare Workers. The client has zero external dependencies and is +optimized for maximum performance. + +> Running on Node.js? Use +> [`@clickhouse/client`](https://www.npmjs.com/package/@clickhouse/client) +> instead, which additionally supports streaming for inserts. + +## Installation + +```sh +npm i @clickhouse/client-web +``` + +## Environment requirements + +The client targets runtimes that provide the standard +[Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and +[Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) APIs, +such as modern Chrome/Firefox browsers and Cloudflare Workers. + +If using TypeScript, version +[4.5](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html) +or above is required to enable +[inline import and export syntax](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html#type-modifiers-on-import-names). + +## Compatibility with ClickHouse + +| Client version | ClickHouse | +| -------------- | ---------- | +| 1.12.0+ | 24.8+ | + +The client may work with older versions too; however, this is best-effort +support and is not guaranteed. + +## Quick start + +```ts +import { createClient } from "@clickhouse/client-web"; + +const client = createClient({ + url: "http://localhost:8123", + username: "default", + password: "", +}); + +const resultSet = await client.query({ + query: "SELECT * FROM system.tables", + format: "JSONEachRow", +}); + +const tables = await resultSet.json(); +console.log(tables); + +await client.close(); +``` + +See more examples in the +[examples directory](https://github.com/ClickHouse/clickhouse-js/tree/main/examples). + +## Documentation + +See the [ClickHouse website](https://clickhouse.com/docs/integrations/javascript) +for the full documentation. + +## Changelog + +See [`CHANGELOG.md`](https://github.com/ClickHouse/clickhouse-js/blob/main/packages/client-web/CHANGELOG.md). + +## Contact us + +If you have any questions or need help, feel free to reach out to us in the +[Community Slack](https://clickhouse.com/slack) (`#clickhouse-js` channel) or +via [GitHub issues](https://github.com/ClickHouse/clickhouse-js/issues). + +## License + +[Apache 2.0](https://github.com/ClickHouse/clickhouse-js/blob/main/LICENSE) diff --git a/packages/client-web/package.json b/packages/client-web/package.json index f5e376631..23e67c4d3 100644 --- a/packages/client-web/package.json +++ b/packages/client-web/package.json @@ -25,7 +25,7 @@ }, "scripts": { "pack": "npm pack", - "prepack": "cp ../../README.md ../../LICENSE .", + "prepack": "cp ../../LICENSE .", "typecheck": "tsc --noEmit", "lint": "eslint --max-warnings=0 .", "lint:fix": "eslint . --fix", From a417d5c051ba5768bc2cc2cbdadff0e14a41e1b6 Mon Sep 17 00:00:00 2001 From: Peter Leonov Date: Thu, 2 Jul 2026 10:14:37 +0200 Subject: [PATCH 5/5] fix(client): re-export EXCEPTION_TAG_HEADER_NAME and extractErrorAtTheEndOfChunk (#935) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary The 1.23.0 migration ([#845]) deprecated `@clickhouse/client-common` and bundled its shared code into `@clickhouse/client` (Node.js) and `@clickhouse/client-web` (Web), re-exporting the public surface from each so users could switch their imports over. Two runtime values that are part of `@clickhouse/client-common`'s public index were missed: - `EXCEPTION_TAG_HEADER_NAME` - `extractErrorAtTheEndOfChunk` Downstream users import these directly. This was the first "missing re-export" report, from Langfuse: https://github.com/langfuse/langfuse/pull/14686 ## Changes Re-export both symbols from `@clickhouse/client` and `@clickhouse/client-web` using the same local-binding pattern as the other runtime values in `src/index.ts`. (Neither carries an `@deprecated` tag in the common index, so consumers importing them from the client packages get the clean, recommended path.) ## Verification - `npm run typecheck` (node + web) — clean - `npm run lint` (node + web) — clean - Built the node package and confirmed both symbols resolve at runtime: - `EXCEPTION_TAG_HEADER_NAME === "x-clickhouse-exception-tag"` - `typeof extractErrorAtTheEndOfChunk === "function"` [#845]: https://github.com/ClickHouse/clickhouse-js/pull/845 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) --- packages/client-node/CHANGELOG.md | 8 ++++++++ packages/client-node/src/index.ts | 4 ++++ packages/client-web/CHANGELOG.md | 8 ++++++++ packages/client-web/src/index.ts | 4 ++++ 4 files changed, 24 insertions(+) diff --git a/packages/client-node/CHANGELOG.md b/packages/client-node/CHANGELOG.md index 7ae3e0373..faa822daa 100644 --- a/packages/client-node/CHANGELOG.md +++ b/packages/client-node/CHANGELOG.md @@ -1,3 +1,11 @@ +# 1.23.1 + +## Bug Fixes + +- Re-export `EXCEPTION_TAG_HEADER_NAME` and `extractErrorAtTheEndOfChunk` from `@clickhouse/client`. Both are part of the (now deprecated) `@clickhouse/client-common` public API but were missed when its surface was bundled into and re-exported from the client packages in 1.23.0 ([#845]). Reported downstream by Langfuse. ([#935]) + +[#935]: https://github.com/ClickHouse/clickhouse-js/pull/935 + # 1.23.0 ## Migration Notes diff --git a/packages/client-node/src/index.ts b/packages/client-node/src/index.ts index 638f85035..9d3938272 100644 --- a/packages/client-node/src/index.ts +++ b/packages/client-node/src/index.ts @@ -93,6 +93,8 @@ import { ClickHouseSpanStatusCode as ClickHouseSpanStatusCode_, ClickHouseSpanKind as ClickHouseSpanKind_, defaultJSONHandling as defaultJSONHandling_, + EXCEPTION_TAG_HEADER_NAME as EXCEPTION_TAG_HEADER_NAME_, + extractErrorAtTheEndOfChunk as extractErrorAtTheEndOfChunk_, } from "./common/index"; export const ClickHouseError = ClickHouseError_; @@ -121,3 +123,5 @@ export const ClickHouseSpanNames = ClickHouseSpanNames_; export const ClickHouseSpanStatusCode = ClickHouseSpanStatusCode_; export const ClickHouseSpanKind = ClickHouseSpanKind_; export const defaultJSONHandling = defaultJSONHandling_; +export const EXCEPTION_TAG_HEADER_NAME = EXCEPTION_TAG_HEADER_NAME_; +export const extractErrorAtTheEndOfChunk = extractErrorAtTheEndOfChunk_; diff --git a/packages/client-web/CHANGELOG.md b/packages/client-web/CHANGELOG.md index 7ae3e0373..1883e1f6d 100644 --- a/packages/client-web/CHANGELOG.md +++ b/packages/client-web/CHANGELOG.md @@ -1,3 +1,11 @@ +# 1.23.1 + +## Bug Fixes + +- Re-export `EXCEPTION_TAG_HEADER_NAME` and `extractErrorAtTheEndOfChunk` from `@clickhouse/client-web`. Both are part of the (now deprecated) `@clickhouse/client-common` public API but were missed when its surface was bundled into and re-exported from the client packages in 1.23.0 ([#845]). Reported downstream by Langfuse. ([#935]) + +[#935]: https://github.com/ClickHouse/clickhouse-js/pull/935 + # 1.23.0 ## Migration Notes diff --git a/packages/client-web/src/index.ts b/packages/client-web/src/index.ts index 958bdd1da..d0030758f 100644 --- a/packages/client-web/src/index.ts +++ b/packages/client-web/src/index.ts @@ -92,6 +92,8 @@ import { ClickHouseSpanStatusCode as ClickHouseSpanStatusCode_, ClickHouseSpanKind as ClickHouseSpanKind_, defaultJSONHandling as defaultJSONHandling_, + EXCEPTION_TAG_HEADER_NAME as EXCEPTION_TAG_HEADER_NAME_, + extractErrorAtTheEndOfChunk as extractErrorAtTheEndOfChunk_, } from "./common/index"; export const ClickHouseError = ClickHouseError_; @@ -120,3 +122,5 @@ export const ClickHouseSpanNames = ClickHouseSpanNames_; export const ClickHouseSpanStatusCode = ClickHouseSpanStatusCode_; export const ClickHouseSpanKind = ClickHouseSpanKind_; export const defaultJSONHandling = defaultJSONHandling_; +export const EXCEPTION_TAG_HEADER_NAME = EXCEPTION_TAG_HEADER_NAME_; +export const extractErrorAtTheEndOfChunk = extractErrorAtTheEndOfChunk_;