Skip to content

fix(knip): scope packages/* entry exports so dead code gets flagged - #208

Merged
fennifith merged 1 commit into
playfulprogramming:mainfrom
bbornino:feature/204-knip-internal-package-exports
Aug 22, 2026
Merged

fix(knip): scope packages/* entry exports so dead code gets flagged#208
fennifith merged 1 commit into
playfulprogramming:mainfrom
bbornino:feature/204-knip-internal-package-exports

Conversation

@bbornino

Copy link
Copy Markdown
Contributor

Closes #204

Problem

knip's default entry-file exemption treats every package's declared main (src/index.ts) as a public API boundary — reasonable for a package with real external consumers, but wrong for packages/* here, since these are all private: true internal workspace packages with no consumer outside this monorepo. As a result, knip wasn't catching genuinely dead exports in these packages, which is how a dead list() function and S3Object interface in packages/s3/src/utils.ts went unflagged through multiple clean test:unit runs.

Fix

One-line addition to knip.json, matching the existing apps/worker override pattern:

"packages/*": {
      "includeEntryExports": true
}

Cleanup

Running knip with the fix surfaced 12 previously-invisible findings. Investigated each individually (checked for real consumers anywhere, including tests, and whether any might be reserved for planned-but-not-yet-wired-up work like #94's schema endpoints) rather than blanket-ignoring the list:

Un-exported only (used internally, so kept — just no longer part of the package's public surface):
- DELETE_S3_OBJECT_GRACE_PERIOD_MS, PostImageInputSchema, TasksKeys (packages/bullmq)
- EnvSchema (packages/common)
- FIRST_CONTRIBUTOR_YEAR (packages/github-api)

Removed entirely (zero consumers anywhere):
- TaskInputsValues / TaskOutputsValues (packages/bullmq) — never referenced anywhere, including internally; only TaskInputs/TaskOutputs themselves are actually used
- EnvType (packages/common) — never referenced
- getCommits / GetCommitsParams (packages/github-api) — whole file deleted. This REST-based commit listing was never wired up to any caller; getAuthorGitHubStats.ts already covers commit-history stats via a separate GraphQL query
- exists / matchesEtag (packages/s3) — exists had no callers; matchesEtag's ETag-based staleness check was superseded by the LastModified/unmodifiedSince approach from #197's delete-s3-object work (ETag can't detect a same-content rewrite, which is exactly the race that check needs to catch)

One edge case worth flagging for review: un-exporting PostImageInputSchema revealed it's a const whose only usage anywhere is Static<typeof PostImageInputSchema> — a type-only query, never read as a runtime value. ESLint's no-unused-vars correctly flags this once it's no longer exported (exports are exempt from that check). Resolved with a scoped eslint-disable-next-line and a comment explaining why, rather than restructuring or leaving it exported (which would just re-trigger the knip finding this PR fixes).

Testing

- pnpm exec knip — 0 findings (was 12 with the config change alone, 0 before the config change)
- pnpm build:all — clean, all 10 projects
- pnpm test:unit — clean (sherif, eslint, publint, vitest all green across every project)

knip's default entry-file exemption treated every package's src/index.ts
as a public API boundary, even though these are all private internal
workspace packages with no external consumer. Add includeEntryExports
for packages/* in knip.json, matching the existing apps/worker override.

Also remove the exports this newly surfaces as genuinely dead (no
consumers anywhere, including tests), and drop export on ones only
used within their own file:

- packages/bullmq: DELETE_S3_OBJECT_GRACE_PERIOD_MS, PostImageInputSchema,
  TasksKeys un-exported; TaskInputsValues/TaskOutputsValues removed (never
  referenced anywhere)
- packages/common: EnvSchema un-exported; EnvType removed (never referenced)
- packages/github-api: FIRST_CONTRIBUTOR_YEAR un-exported; getCommits/
  GetCommitsParams removed entirely - superseded by the GraphQL-based
  getAuthorGitHubStats, never wired up to any caller
- packages/s3: exists/matchesEtag removed - matchesEtag's ETag-based
  check was superseded by the LastModified-based approach from playfulprogramming#197's
  delete-s3-object work, exists had no callers
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: eca206b5-30d3-4868-bd8c-ee525d64bd44


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.

@fennifith
fennifith added this pull request to the merge queue Aug 22, 2026
Merged via the queue into playfulprogramming:main with commit 6323963 Aug 22, 2026
5 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.

knip isn't checking internal packages/* exports for dead code

2 participants