Skip to content

chore: update pnpm to v12 #864

chore: update pnpm to v12

chore: update pnpm to v12 #864

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
# Every job here reads the repository and writes nothing back, so the token is
# narrowed once at the top rather than per job. The repository default is
# already `read`, which makes this a guard against that setting being widened
# later rather than a change in what the jobs can do today.
permissions:
contents: read
# Clean adoption resolves a fresh dependency graph outside the checkout. Keep
# its installer independent of whichever npm release ships with the Node runner.
env:
CLEAN_ADOPTION_NPM_VERSION: 11.6.4
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Build the documentation site and check its Markdown integrations
run: pnpm docs:check
- name: Check the drawing-game source snippets
run: pnpm example:drawing-game:snippets:check
- run: pnpm typecheck
- run: pnpm lint
- run: pnpm format:check
test:
name: test (${{ matrix.os }}, node ${{ matrix.node }})
runs-on: ${{ matrix.os }}
strategy:
# One version failing should not hide the others.
fail-fast: false
matrix:
# The versions still in maintenance. Node 20 left it in April 2026, which
# is why it is not here; that pnpm 11 cannot install on it either is a
# consequence, not the reason, so raising pnpm does not raise this list.
# What the published package supports is a separate question, answered by
# `engines.node` and guarded by the `node-floor` job below.
os: [ubuntu-latest]
node: [22, 24]
# Every Node version on Linux, and one job each for the other two systems
# rather than a full cross product, which would be six jobs to answer a
# question two can. smocket ships as a devDependency and runs on
# contributors' machines rather than on a server, so an operating system
# the dual run has never been executed on is a gap in the central claim,
# not a convenience. `lts/*` tracks the current LTS so this does not need
# editing every October; it is a toolchain choice and deliberately not
# tied to `engines.node`, which a consumer's own runner honors instead.
include:
- os: windows-latest
node: lts/*
- os: macOS-latest
node: lts/*
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: ${{ matrix.node }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Run the suite against real socket.io
run: pnpm test:real
# The mock suite hard-gates like any other check: a mock regression fails
# it, and with it the badge.
- name: Run the suite against smocket
run: pnpm test:mock
# The example is documentation that executes, so it rots the moment nothing
# runs it. This builds `dist/` and runs the program, which fails the job if
# the example stops working against the package it demonstrates.
- name: Run the chat room example
run: pnpm example:chat-room
- name: Compare the drawing game against both Node targets
run: pnpm example:drawing-game:test
browser:
name: browser (chromium)
needs: package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Install the clean-adoption npm runner
run: npm install --global "npm@$CLEAN_ADOPTION_NPM_VERSION"
- name: Download the verified release candidate
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: release-candidate-${{ github.event.pull_request.head.sha || github.sha }}
path: .release-candidate
- name: Install Chromium for Playwright
run: pnpm exec playwright install --with-deps chromium
# Only the mock target has a counterpart in a page, so this asks a narrower
# question than the dual run. Does the mock behave in a browser the way it
# behaves in Node. #139 is what happens without it.
- name: Run the mock target in a browser
run: pnpm test:browser
- name: Prove one SharedWorker lobby across three Chromium tabs
run: pnpm test:shared-worker
- name: Verify production SharedWorker tab lifecycle
run: xvfb-run --auto-servernum pnpm test:shared-worker:lifecycle
- name: Reject unexpected SharedWorker page errors
run: xvfb-run --auto-servernum pnpm test:shared-worker:errors
- name: Compare SharedWorker with a real Socket.IO sidecar
run: pnpm test:shared-worker:parity
- name: Run the documented SharedWorker lobby
run: pnpm example:shared-worker
- name: Run the drawing game across three pages and both targets
run: pnpm example:drawing-game:verify
- name: Run candidate packages in Chromium
run: pnpm consumer:client:candidate -- --manifest .release-candidate/release-candidate.json --browser
node-floor:
name: declared node floor
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
# Install and build on a version the toolchain runs on. pnpm 11 needs
# 22.13, so this half cannot move down and does not need to: what it
# produces is `dist/`, and `dist/` is what the two steps below run.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Install the Node 20 compatibility runner
run: pnpm --dir compat/node20 install --frozen-lockfile
- run: pnpm build
- run: pnpm --filter smocket-client build
# Lower tier: the exact floor `engines.node` declares. Nothing installed
# is invoked here, not even pnpm, because pnpm 11 would not start on this
# version either. `scripts/smoke.mjs` imports `node:assert` and `dist/`
# and nothing else, so whatever Node can run the package can run it. It
# drives one room broadcast rather than only importing the module, so a
# `>=20` that delivers nothing fails here instead of shipping.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 20.0.0
- run: node scripts/smoke.mjs
- run: node --test packages/smocket-client/test/runtime.test.mjs packages/smocket-client/test/runtime.test.cjs
# Upper tier: the whole mock suite against `dist/` on Node 20.13.0. The
# exact 20.0.0 floor can collect this suite, but its fake timer cleanup
# does not complete. The smoke checks above cover that exact runtime,
# while this tier keeps the broader package behavior on Node 20.
#
# The root suite uses Vitest 5, which requires Node 22.12 or newer. This
# tier invokes Vitest 4 from `compat/node20` instead, which keeps the
# runner in a dedicated lockfile without executing unsupported Vitest 5
# code.
# The `node_modules` installed above is reused as is. Node 20 resolves
# pnpm's links without a reinstall or a separate artifact.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 20.13.0
- name: Reject a missing SharedWorker artifact with the Node 20 runner
run: node scripts/check-shared-worker-dist-gate.mjs
env:
SMOCKET_DIST_VITEST: compat/node20/node_modules/vitest/vitest.mjs
- run: node compat/node20/node_modules/vitest/vitest.mjs run --config vitest.dist.config.ts
compat:
name: real target (socket.io ${{ matrix.socketio }})
runs-on: ubuntu-latest
strategy:
matrix:
# Exercise the oracle across its supported range, not one pinned version.
socketio: ['4.7', '4.8']
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Pin socket.io ${{ matrix.socketio }}
run: pnpm add --workspace-root -D socket.io@${{ matrix.socketio }} socket.io-client@${{ matrix.socketio }}
- name: Typecheck against socket.io ${{ matrix.socketio }}
run: pnpm typecheck
- name: Run the suite against real socket.io ${{ matrix.socketio }}
run: pnpm test:real
conformance:
name: conformance report
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
# docs/conformance.md is generated from a dual run, so it is only true as
# long as it matches the suite. This runs the same generation and fails if
# the committed file has drifted, which is what keeps the report evidence
# rather than a claim someone forgot to update. It runs both targets again
# rather than reusing the `test` job, because the report needs the two
# results side by side and that job reports them separately per platform.
- name: Check the conformance report is current
run: pnpm check:conformance
public-surface:
name: public surface ledger
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
# This owns upstream declaration and classification drift only. The packed
# manifest, dependency policy, and import scanner remain in `package`.
- name: Check the reviewed upstream public surface
run: pnpm check:public-surface
- name: Reject classifications that reference closed issues
run: pnpm check:public-surface-issues
env:
GITHUB_TOKEN: ${{ github.token }}
published-type-version:
name: published type version
if: github.event_name == 'pull_request'
needs: package
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 22
- name: Detect synchronized package version changes
id: versions
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: node scripts/check-published-types.mjs detect --base "$BASE_SHA" >> "$GITHUB_OUTPUT"
- if: steps.versions.outputs.changed == 'true'
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- if: steps.versions.outputs.changed == 'true'
run: pnpm install --frozen-lockfile
- if: steps.versions.outputs.changed == 'true'
name: Download the synchronized release candidate
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: release-candidate-${{ github.event.pull_request.head.sha || github.sha }}
path: .release-candidate
- if: steps.versions.outputs.changed == 'true'
name: Enforce the published public-type version boundary
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
pnpm check:published-types check \
--base "$BASE_SHA" \
--manifest .release-candidate/release-candidate.json
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
# Coverage of smocket's own code, which only the mock target exercises; it
# gates on the thresholds in vitest.config.ts.
- name: Coverage against smocket
run: pnpm coverage
# The gate above is the check that matters. This upload only feeds the
# Codecov report, and it needs the CODECOV_TOKEN secret even on a public
# repository, since a tokenless upload is rejected. It never fails the job,
# so a Codecov outage or a missing token costs the report and not the run.
- name: Upload coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7
with:
files: ./coverage/lcov.info
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Install the clean-adoption npm runner
run: npm install --global "npm@$CLEAN_ADOPTION_NPM_VERSION"
- name: Build one immutable two-package release candidate
run: pnpm release:candidate
- name: Reject external imports in the built root package
run: pnpm assert:no-imports
# Package policy, Publint, Are The Types Wrong, and both independent
# consumers receive the exact tarballs named by this digest manifest.
- name: Verify every package and candidate consumer against one artifact set
run: pnpm check:release-candidate
- name: Preserve the verified candidate for later read-only jobs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: release-candidate-${{ github.event.pull_request.head.sha || github.sha }}
path: .release-candidate
if-no-files-found: error
include-hidden-files: true
retention-days: 7