Skip to content

build: replace tsup with tsdown and make the published types reachable - #167

Merged
dawsontoth merged 1 commit into
mainfrom
build/migrate-to-tsdown
Sep 11, 2026
Merged

build: replace tsup with tsdown and make the published types reachable#167
dawsontoth merged 1 commit into
mainfrom
build/migrate-to-tsdown

Conversation

@dawsontoth

Copy link
Copy Markdown
Contributor

One of two alternatives. This keeps declaration emit and moves off unmaintained tooling. The other is dropping --dts and staying on tsup. Pick one, not both.

Why move

tsup 8.5.1 inlines its own rollup-plugin-dts@6.1.1 compiled against typescript@5.7.3, and that vendored copy throws on TS 7 — the blocker on #145:

TypeError: Cannot read properties of undefined (reading 'useCaseSensitiveFileNames')

Nothing in our lockfile reaches that copy, so overrides can't help. And tsup is effectively dormant:

latest last published
tsup 8.5.1 2025-11-12 (~10 months, only dist-tag)
tsdown 0.23.0 2026-09-03

tsdown is the rolldown-based successor from the same ecosystem. The relevant difference isn't that it's newer — it's that it emits declarations through TypeScript itself:

ℹ Emit types with typescript@7.0.2

rather than through a pinned copy of rollup-plugin-dts. That's the structural reason it isn't exposed to this class of breakage.

Bonus fix: the types were unreachable

Worth knowing regardless of which branch you take — the declarations we already build can't be resolved by anyone:

// before
"exports": { ".": "./dist/index.js" }   // no "types" condition, no "types" field

This PR adds both, so the emit we're paying for is actually usable:

"types": "./dist/index.d.ts",
"exports": { ".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" } }

Config notes

  • outExtensions pins .js. tsdown defaults to .mjs, which would break bin (./dist/cli.js) and exports (./dist/index.js). Caught this the first time through.
  • dist/ gains .map files that tsup didn't emit. tsdown forces sourcemaps on whenever tsconfig sets declarationMap, which ours does — a sourcemap: false in the config does not override it. They aren't published: files already excludes dist/**/*.map, confirmed with npm pack --dry-run.

Verification

typescript 6.0.3 typescript 7.0.2
npm run build exit 0 exit 0
built CLI runs

Packed tarball contains exactly cli.js, index.js, AgentManager-*.js, both .d.ts, and schema.graphql — no maps, 59.8 kB. Lint, format, and 53 files / 345 tests pass. Bundle is slightly smaller than tsup's (94 kB vs 105 kB).

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request replaces the build tool tsup with tsdown, updating the build and dev scripts in package.json and adding a new tsdown.config.ts configuration file. It also updates the package exports to explicitly define type definitions. A critical issue was identified in the tsdown.config.ts file where the configuration option outExtensions is misspelled as plural instead of singular (outExtension). This typo would cause the option to be ignored, resulting in .mjs output files that break the package exports pointing to .js files.

Comment thread tsdown.config.ts
tsup 8.5.1 inlines its own `rollup-plugin-dts@6.1.1` compiled against
`typescript@5.7.3`, and that vendored copy throws on TypeScript 7:

  TypeError: Cannot read properties of undefined (reading 'useCaseSensitiveFileNames')

Nothing in our lockfile reaches it, so no `overrides` can fix it, and tsup
has not published since 2025-11-12 - ~10 months, with 8.5.1 the only
dist-tag. That is what blocks #145.

tsdown is the rolldown-based successor from the same ecosystem, last
published 2026-09-03. It emits declarations through TypeScript itself
(`Emit types with typescript@7.0.2`) rather than a pinned copy of
rollup-plugin-dts, which is structurally why it is not exposed to this class
of breakage.

While here: the declarations we were already building were unreachable.
package.json had no `types` field and no `types` condition in `exports`, so
no TypeScript consumer could resolve them. Added both, so the emit we are
paying for is now usable.

Config notes:
- `outExtensions` pins .js. tsdown defaults to .mjs, which would break
  `bin` (./dist/cli.js) and `exports` (./dist/index.js).
- dist gains .map files tsup did not emit, because tsdown forces sourcemaps
  on whenever tsconfig sets `declarationMap`, which ours does. They are not
  published - `files` already excludes `dist/**/*.map`. Verified with
  `npm pack --dry-run`.

Verified: build succeeds on typescript 6.0.3 and 7.0.2, the built CLI runs
(`node ./dist/cli.js --help`), and the packed tarball contains cli.js,
index.js, both .d.ts files and schema.graphql with no maps. Lint, format and
53 files / 345 tests pass. Bundle is slightly smaller (94 kB vs 105 kB).

Alternative to the --dts drop on build/drop-unused-dts - that branch
unblocks TS 7 by removing declaration emit entirely. Pick one, not both.
@dawsontoth
dawsontoth force-pushed the build/migrate-to-tsdown branch from 865e3b8 to 9df6926 Compare September 11, 2026 15:27
@dawsontoth
dawsontoth merged commit ed248de into main Sep 11, 2026
6 checks passed
@dawsontoth
dawsontoth deleted the build/migrate-to-tsdown branch September 11, 2026 15:30
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.16.54 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant