diff --git a/.changeset/socket-mode-undici-v8.md b/.changeset/socket-mode-undici-v8.md new file mode 100644 index 000000000..d2ff20232 --- /dev/null +++ b/.changeset/socket-mode-undici-v8.md @@ -0,0 +1,5 @@ +--- +"@slack/socket-mode": minor +--- + +Support `undici@^8` as a peer dependency in addition to `undici@^7`. `undici@^8` requires Node.js >=22.19; `undici@^7` continues to support Node.js >=20. diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index d5afe57af..fffb8dd41 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -18,14 +18,20 @@ jobs: os: - "ubuntu-latest" - "windows-latest" - node-version: - - "20.x" - - "22.x" - - "24.x" - - "26.x" + versions: + - node: "20.x" + undici: "7" # undici v8 requires Node >=22.19, so 20.x tests against v7 + - node: "22.x" + undici: "8" + - node: "24.x" + undici: "8" + - node: "26.x" + undici: "8" runs-on: ${{ matrix.os }} permissions: contents: read + env: + SOCKET_MODE_UNDICI_VERSION: ${{ matrix.versions.undici }} steps: - name: Configure git settings (Windows) if: matrix.os == 'windows-latest' @@ -35,31 +41,34 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js ${{ matrix.versions.node }} uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: ${{ matrix.node-version }} + node-version: ${{ matrix.versions.node }} - name: Check versions run: | node --version npm --version - name: Install dependencies run: npm ci --verbose + # Force socket-mode onto the matrix's undici major. + - name: Install undici v${{ matrix.versions.undici }} for socket-mode + run: npm install undici@^${{ matrix.versions.undici }} --workspace=packages/socket-mode - name: Build packages run: npm run build - name: Lint run: npm run lint - name: Build docs - if: matrix.node-version == env.LATEST_SUPPORTED_NODE + if: matrix.versions.node == env.LATEST_SUPPORTED_NODE run: npm run docs - name: Run tests - if: matrix.node-version != env.LATEST_SUPPORTED_NODE + if: matrix.versions.node != env.LATEST_SUPPORTED_NODE run: npm test - name: Run test coverage - if: matrix.node-version == env.LATEST_SUPPORTED_NODE + if: matrix.versions.node == env.LATEST_SUPPORTED_NODE run: npm run test:coverage - name: Upload code coverage - if: matrix.node-version == env.LATEST_SUPPORTED_NODE && matrix.os == 'ubuntu-latest' + if: matrix.versions.node == env.LATEST_SUPPORTED_NODE && matrix.os == 'ubuntu-latest' uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: fail_ci_if_error: true @@ -74,7 +83,7 @@ jobs: with: fail_ci_if_error: true files: packages/cli-hooks/test-results.xml,packages/cli-test/test-results.xml,packages/logger/test-results.xml,packages/oauth/test-results.xml,packages/socket-mode/test-results.xml,packages/web-api/test-results.xml,packages/webhook/test-results.xml - flags: ${{ matrix.node-version }},${{ matrix.os }} + flags: ${{ matrix.versions.node }},${{ matrix.os }} report_type: test_results token: ${{ secrets.CODECOV_TOKEN }} verbose: true diff --git a/packages/socket-mode/package.json b/packages/socket-mode/package.json index 43222aad7..0d606f580 100644 --- a/packages/socket-mode/package.json +++ b/packages/socket-mode/package.json @@ -57,7 +57,7 @@ "eventemitter3": "^5" }, "peerDependencies": { - "undici": "^7.0.0" + "undici": "^7.0.0 || ^8.0.0" }, "devDependencies": { "@types/proxyquire": "^1.3.31", diff --git a/packages/socket-mode/src/undiciVersion.test.ts b/packages/socket-mode/src/undiciVersion.test.ts new file mode 100644 index 000000000..5ea57b350 --- /dev/null +++ b/packages/socket-mode/src/undiciVersion.test.ts @@ -0,0 +1,33 @@ +import assert from 'node:assert/strict'; +import { createRequire } from 'node:module'; +import { describe, it } from 'node:test'; + +// Guardrail for the `undici` peer dependency. undici v8 needs +// Node >=22 and v7 needs Node >=20, so CI passes the expected major in via SOCKET_MODE_UNDICI_VERSION. + +const require = createRequire(import.meta.url); +const undiciVersion: string = require('undici/package.json').version; +const undiciMajor = Number.parseInt(undiciVersion.split('.')[0], 10); +const nodeMajor = Number.parseInt(process.versions.node.split('.')[0], 10); + +describe('undici peer dependency', () => { + it('never runs undici v8+ on Node older than 22', () => { + assert.ok( + undiciMajor < 8 || nodeMajor >= 22, + `undici@${undiciVersion} requires Node >=22, but tests are running on Node ${process.versions.node}`, + ); + }); + + const expectedMajor = process.env.SOCKET_MODE_UNDICI_VERSION; + if (expectedMajor) { + it(`runs against the undici major pinned by CI (v${expectedMajor})`, () => { + assert.strictEqual( + undiciMajor, + Number.parseInt(expectedMajor, 10), + `Expected undici v${expectedMajor} (SOCKET_MODE_UNDICI_VERSION), but undici@${undiciVersion} is installed`, + ); + }); + } else { + it.skip('runs against the undici major pinned by CI (only when SOCKET_MODE_UNDICI_VERSION is set)'); + } +});