Skip to content

fix(release): stop the publish hooks from racing each other - #140

Merged
Bccorb merged 1 commit into
mainfrom
fix/publish-race-between-prepublish-hooks
Jul 30, 2026
Merged

fix(release): stop the publish hooks from racing each other#140
Bccorb merged 1 commit into
mainfrom
fix/publish-race-between-prepublish-hooks

Conversation

@Bccorb

@Bccorb Bccorb commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

What broke

The release run for Version Packages published @seamless-auth/core@0.11.0 and @seamless-auth/express@0.11.0 but failed to publish @seamless-auth/fastify@0.1.0. The visible error pointed at tsup, but build:js actually succeeded and the next script is what failed:

src/index.ts(21,8): error TS2307: Cannot find module '@seamless-auth/core' or its corresponding type declarations.
@seamless-auth/fastify@0.1.0 build:types: `tsc -p tsconfig.build.json` Exit status 2

Why

changeset publish builds its publish queue with a concurrency limit of 10, so all three packages publish at the same time (the run log shows all three Publishing lines on an identical timestamp). Each package's prepublishOnly was pnpm run clean && pnpm run build, and clean is rm -rf dist.

So core deleted its own dist while the fastify adapter was type checking against it. build:js survived because tsup marks @seamless-auth/core as external and never resolves it; build:types needs the real declaration files. Express only escaped on timing, so this was a race that could hit either adapter.

Confirmed by hiding packages/core/dist and running the fastify build:types locally, which reproduces the identical error list.

The fix

release:stable already runs pnpm build (pnpm -r --sort build, topologically ordered) before changeset publish, and that ordered build succeeded in the failed run. The per-package rebuild in prepublishOnly was redundant, and re-running it concurrently is what destroyed the correct build.

Replaced it in all three packages with a non-destructive check that build output exists. Dropping the hook outright would also fix the race, but then publishing without a prior build would silently ship a tarball with no dist, since files just omits a missing directory. The guard turns that into a failed publish instead.

Verification

Run from the workspace root:

  • pnpm build clean, pnpm test green (core 214 tests, express 150, fastify 23)
  • the guard exits 0 with dist present and exits 1 with the message when it is absent
  • all three prepublishOnly hooks run concurrently and all exit 0, which is the exact scenario that failed
  • pnpm pack for fastify produces a tarball containing dist/index.js and the declarations

Release impact

No changeset here on purpose. This is release plumbing rather than an adopter-facing change, and a pending changeset would make the changesets action open a Version Packages PR instead of publishing. main already carries the 0.1.0 bump and changelog for fastify, so merging this triggers a publish run that skips the two packages already on npm and ships @seamless-auth/fastify@0.1.0.

changeset publish runs every package concurrently, so each package's prepublishOnly ran rm -rf dist followed by a rebuild at the same time. core deleted its own dist while the fastify adapter was type checking against it, failing build:types with TS2307 and blocking @seamless-auth/fastify from publishing.

release:stable already runs pnpm build in topological order before changeset publish, so the per-package rebuild was redundant. Replace it with a check that the dist output exists, which also keeps a publish from silently shipping a tarball with no dist.
@Bccorb
Bccorb merged commit c9a8f3f into main Jul 30, 2026
2 checks passed
@Bccorb
Bccorb deleted the fix/publish-race-between-prepublish-hooks branch July 30, 2026 04:50
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