Skip to content

chore: migrate package manager from bun to pnpm#191

Merged
maxktz merged 3 commits into
mainfrom
chore/migrate-to-pnpm
May 24, 2026
Merged

chore: migrate package manager from bun to pnpm#191
maxktz merged 3 commits into
mainfrom
chore/migrate-to-pnpm

Conversation

@maxktz
Copy link
Copy Markdown
Contributor

@maxktz maxktz commented May 24, 2026

Migrates the monorepo from bun to pnpm, and from bumpp + the tag-triggered bun publish to changesets.

What changed

  • PM: pnpm-workspace.yaml (+ catalogs moved here from package.json, native build scripts allowlisted), packageManager: pnpm@11.1.1, pnpm-lock.yaml; removed bun.lock.
  • Releases → changesets: .changeset/, ci:version/ci:release scripts, publishConfig.directory: dist on the 3 public packages (keeps the existing dist build). Removed bumpp + bump.config.ts; release.yml now runs changesets/action on push to main.
  • CI/Vercel: workflows + both vercel.json switched to pnpm.
  • Bun kept (intentional): apps/demo dev scripts (bun as a TS runtime) and the CLI's package-manager detection / docs — these support paykit users on bun.

Verified

  • pnpm install, pnpm turbo build typecheck --filter ./packages/* (8/8 pass — paykit-source resolves through pnpm symlinks), pnpm pack ships dist (not src).

Release behavior

Merging this to main triggers the Release workflow. With no pending changesets and 0.0.6 not yet on npm, it runs pnpm ci:release → builds + changeset publish → publishes paykitjs/@paykitjs/polar/@paykitjs/stripe@0.0.6 as latest. Requires a valid NPM_TOKEN secret.

Summary by CodeRabbit

  • Chores
    • Switched project tooling and scripts from Bun to pnpm across dev, CI, and release flows.
    • Adopted Changesets-driven versioning and publishing with an automated release workflow.
    • Updated CI/E2E workflows, workspace config, and deployment settings for consistency.
    • Revised developer docs, setup scripts, and linting rules to match the new toolchain.

Review Change Stack

- pnpm workspace + lockfile; packageManager pnpm@11.1.1 (catalogs moved to
  pnpm-workspace.yaml, native build scripts allowlisted)
- replace bumpp + tag-triggered bun publish with changesets
  (publishConfig.directory: dist keeps the existing dist build)
- convert CI workflows and Vercel configs to pnpm
- keep bun as a runtime for apps/demo scripts and the CLI package-manager detection
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
paykit Ignored Ignored Preview May 24, 2026 10:50am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c48c3509-aa1b-47ba-958a-281178306856

📥 Commits

Reviewing files that changed from the base of the PR and between a7d14fa and 759a95e.

📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • .github/workflows/e2e.yml
  • .github/workflows/npm-dist-tag.yml
  • .github/workflows/release.yml
✅ Files skipped from review due to trivial changes (1)
  • .github/workflows/npm-dist-tag.yml

📝 Walkthrough

Walkthrough

This PR migrates the repository from Bun to pnpm, introduces Changesets for versioning and releases, adds a pnpm workspace, updates CI/CD workflows and app manifests to pnpm, and adds a publish helper script to publish built package dists.

Changes

Package Manager & Release Pipeline Migration

Layer / File(s) Summary
Changesets Framework & Release Workflow
.changeset/README.md, .changeset/config.json, .github/workflows/release.yml
Changesets configuration is added with GitHub changelog generation and package targeting, and the release workflow is rewritten to use changesets/action@v1 for automated versioning and publishing, replacing manual Bun-based steps.
Workspace Configuration & pnpm Package Manager Declaration
pnpm-workspace.yaml, package.json
Root package.json declares pnpm@11.1.1, root scripts and devDeps transition to pnpm commands, and pnpm-workspace.yaml defines monorepo packages, allowBuilds, and dependency catalogs.
CI/CD Workflows to pnpm
.github/workflows/ci.yml, .github/workflows/e2e.yml, .github/workflows/npm-dist-tag.yml, scripts/worktree-setup.sh
CI and E2E workflows replace Bun with pnpm/action-setup, enable pnpm caching, install with pnpm install --frozen-lockfile, update test/playwright invocations, and pin action SHAs for determinism.
Package Publishing Helper Script
scripts/publish-dist.mjs
Adds a script that reads each package dist/package.json, checks npm for the version, and publishes new versions from dist/ with npm publish --access public.
Application Package Configuration Updates
apps/demo/package.json, apps/demo/vercel.json, apps/web/package.json, apps/web/vercel.json, apps/web/lighthouserc.json, apps/wh/package.json, apps/wh/drizzle.config.ts, packages/dash/src/plugin/html.ts
Removes Bun packageManager fields, updates scripts and deployment commands to use pnpm, and updates helper/error messages to reference pnpm.
Developer Documentation & Build Configuration
CONTRIBUTING.md, .superset/config.json, .oxlintrc.json
Developer setup docs updated to include pnpm (corepack enable) and pnpm-based dev commands; build setup and lint rules adjusted accordingly.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • getpaykit/paykit#155: Previous CI/E2E workflow migration work with overlapping CI changes.
  • getpaykit/paykit#173: Earlier webhook-listen/workflow that touched the D1 SQLite error message now updated to reference pnpm.

Poem

🐰 From Bun we hop to pnpm's bright green,
Changesets hum, keeping versions serene,
Workflows pivot, scripts now lightly tread,
CI and deploys march where green pins led,
A little rabbit cheers — releases ahead!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: migrate package manager from bun to pnpm' accurately and concisely describes the primary change in the PR, which is a comprehensive migration of the monorepo's package manager from Bun to pnpm across all configuration, CI/CD workflows, and documentation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/migrate-to-pnpm

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

31-31: ⚖️ Poor tradeoff

Consider pinning GitHub Actions to commit SHAs.

The new pnpm/action-setup@v4 references use version tags. For enhanced security and reproducibility, consider pinning to specific commit SHAs (e.g., pnpm/action-setup@fe1e16c3126dd1225ad154e1a3f6a2c1ab0da622). This prevents potential supply-chain attacks if a version tag is moved.

Also applies to: 60-60, 87-87

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml at line 31, Replace the loose tag usage of the
GitHub Action pnpm/action-setup@v4 with a pinned commit SHA to improve security
and reproducibility; update the occurrence shown (pnpm/action-setup@v4) and the
other two occurrences of pnpm/action-setup in the workflow to use a specific
commit ref (e.g., pnpm/action-setup@<commit-sha>) so each action reference is
pinned to an immutable SHA instead of a mutable tag.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Line 22: Replace tag-pinned GitHub Actions with their corresponding full
commit SHAs: locate every uses: entry such as actions/checkout@v4,
pnpm/action-setup@v4, actions/setup-node@v4 in .github/workflows/release.yml
(and similarly in .github/workflows/ci.yml, e2e.yml, npm-dist-tag.yml) and
update each to the exact commit SHA for that action (e.g.,
actions/checkout@<full-sha>) so the workflow references a fixed commit instead
of a floating tag.

In `@packages/polar/package.json`:
- Around line 13-15: The package.json for `@paykitjs/polar` is configured to
publish from "dist" but main/types/exports point to ./src/* causing pnpm pack to
fail; fix by either (A) removing the "publishConfig.directory" entry so
publishing uses the package root package.json (and keep main/types/exports as
./src/*), or (B) emit/copy a complete package.json into dist/ with updated
"main", "types", and "exports" that reference the built files inside dist (e.g.,
dist/index.js, dist/index.d.ts), or (C) update the package root's
"main"/"types"/"exports" to point to the built outputs under dist and ensure the
build produces those files; modify the package.json fields ("publishConfig",
"main", "types", "exports") accordingly and ensure the chosen option results in
a package.json present at the publish root that correctly references the
published file layout.

In `@packages/stripe/package.json`:
- Around line 13-15: The package.json currently sets publishConfig.directory to
"dist", which causes pnpm pack to fail because dist/package.json is missing;
either remove the publishConfig.directory entry from
packages/stripe/package.json and ensure the built output aligns with existing
main/types/exports pointing at the repo root (so packing uses the top-level
manifest), or keep publishConfig.directory but change the build to emit a
dist/package.json and update main/types/exports in packages/stripe/package.json
to reference compiled files inside dist (not ./src/index.ts); pick one approach
and apply consistently so pnpm pack can find a package.json in the publish
directory.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Line 31: Replace the loose tag usage of the GitHub Action pnpm/action-setup@v4
with a pinned commit SHA to improve security and reproducibility; update the
occurrence shown (pnpm/action-setup@v4) and the other two occurrences of
pnpm/action-setup in the workflow to use a specific commit ref (e.g.,
pnpm/action-setup@<commit-sha>) so each action reference is pinned to an
immutable SHA instead of a mutable tag.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 19c725c1-b90c-40ff-bd14-cfe4d955551a

📥 Commits

Reviewing files that changed from the base of the PR and between 97cc957 and 6d608f7.

⛔ Files ignored due to path filters (2)
  • bun.lock is excluded by !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • .changeset/README.md
  • .changeset/config.json
  • .github/workflows/ci.yml
  • .github/workflows/e2e.yml
  • .github/workflows/release.yml
  • .superset/config.json
  • CONTRIBUTING.md
  • apps/demo/package.json
  • apps/demo/vercel.json
  • apps/web/lighthouserc.json
  • apps/web/package.json
  • apps/web/vercel.json
  • apps/wh/drizzle.config.ts
  • apps/wh/package.json
  • bump.config.ts
  • package.json
  • packages/dash/src/plugin/html.ts
  • packages/paykit/package.json
  • packages/polar/package.json
  • packages/stripe/package.json
  • pnpm-workspace.yaml
  • scripts/worktree-setup.sh
💤 Files with no reviewable changes (2)
  • bump.config.ts
  • apps/demo/package.json

Comment thread .github/workflows/release.yml Outdated
Comment thread packages/polar/package.json Outdated
Comment thread packages/stripe/package.json Outdated
- drop publishConfig.directory (it made pnpm link workspace deps to dist,
  breaking paykit-source -> src resolution when dist isn't built)
- publish built dist via scripts/publish-dist.mjs in ci:release instead
- disable no-underscore-dangle / consistent-function-scoping (intentional
  Node-internal + sentinel names) so oxlint --deny-warnings passes
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/publish-dist.mjs`:
- Around line 15-20: The try/catch around execSync(`npm view ${spec} version`)
treats all errors as "not published"; change the catch to capture the thrown
error (catch (err)) and inspect err.stderr / err.message / err.status to detect
the genuine "version not found" case (e.g., 404/E404 or npm's "No matching
version" text) and only set alreadyPublished = false in that case; for any other
error (network/auth/registry) rethrow or exit non-zero so transient failures
fail fast. Ensure you reference the same execSync call, the spec variable, and
the alreadyPublished flag when making this change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 67d3b033-6dba-45b8-9bfb-e31fe0aa5ec2

📥 Commits

Reviewing files that changed from the base of the PR and between 6d608f7 and a7d14fa.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • .oxlintrc.json
  • package.json
  • scripts/publish-dist.mjs
✅ Files skipped from review due to trivial changes (1)
  • .oxlintrc.json

Comment thread scripts/publish-dist.mjs
Comment on lines +15 to +20
try {
execSync(`npm view ${spec} version`, { stdio: "ignore" });
alreadyPublished = true;
} catch {
// `npm view` exits non-zero when the version does not exist yet.
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle only “version not found” as a skip condition.

The catch-all here treats any npm view failure as “not published yet”. Transient registry/auth/network errors should fail fast instead of attempting publish.

Suggested fix
   let alreadyPublished = false;
   try {
     execSync(`npm view ${spec} version`, { stdio: "ignore" });
     alreadyPublished = true;
-  } catch {
-    // `npm view` exits non-zero when the version does not exist yet.
+  } catch (error) {
+    const message = String(error?.stderr || error?.message || "");
+    // npm returns E404 when a specific version does not exist yet.
+    if (message.includes("E404")) {
+      alreadyPublished = false;
+    } else {
+      throw error;
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
execSync(`npm view ${spec} version`, { stdio: "ignore" });
alreadyPublished = true;
} catch {
// `npm view` exits non-zero when the version does not exist yet.
}
try {
execSync(`npm view ${spec} version`, { stdio: "ignore" });
alreadyPublished = true;
} catch (error) {
const message = String(error?.stderr || error?.message || "");
// npm returns E404 when a specific version does not exist yet.
if (message.includes("E404")) {
alreadyPublished = false;
} else {
throw error;
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/publish-dist.mjs` around lines 15 - 20, The try/catch around
execSync(`npm view ${spec} version`) treats all errors as "not published";
change the catch to capture the thrown error (catch (err)) and inspect
err.stderr / err.message / err.status to detect the genuine "version not found"
case (e.g., 404/E404 or npm's "No matching version" text) and only set
alreadyPublished = false in that case; for any other error
(network/auth/registry) rethrow or exit non-zero so transient failures fail
fast. Ensure you reference the same execSync call, the spec variable, and the
alreadyPublished flag when making this change.

@maxktz maxktz merged commit 0eacbe5 into main May 24, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant