fix: republish @amritk/mini-lynx-native with its dist, and remove the development export condition - #34
Merged
Conversation
…shing on it `@amritk/mini-lynx-native@0.2.0` reached npm as a src-only tarball. It was published by hand rather than through the release workflow, so none of the three things that workflow does before `changeset publish` ran: no `bun run build`, so no `dist/`; no `strip-development-exports`, so the `development` condition survived; no `copy-license`, so no LICENSE. The manifest still declared `./dist/index.js`, `./dist/background/index.js` and `./dist/testing/index.js`, and `files` still listed `dist` — all of it pointing at nothing. The surviving `development` condition is why that was survivable rather than fatal, and why it went unnoticed for a release: it resolves to `./src/*.ts`, and `src` does ship, so anything honouring the condition got raw TypeScript and looked healthy. Plain Node, a bundler on default conditions and `tsc` reading `types` all got a resolution failure instead. The patch changeset republishes the same code through the release workflow. The four `@amritk/lynx-*` packages pin the bridge at an exact version, so their 0.2.0 releases still resolve the broken tarball; changesets bumps them alongside it and they re-pin to 0.2.1. `scripts/check-publishable.mjs` closes the hole the hand-publish went through. It runs as `prepublishOnly` in every publishable package and fails the publish when an exports map points at a `dist/` file that is not on disk, when a `development` condition is still present, or when the package directory has no LICENSE — the three misses above, checked at the one moment that catches them regardless of who is publishing or from where. The repo already checks this ground in dist-smoke and consumer-e2e; neither runs on a laptop typing `npm publish`.
…checking The condition let the workspace resolve its own packages to source with no prior build. It did that by living in each package's `exports` map — the one file that ships — so it was reachable from a published tarball, and `@amritk/mini-lynx-native@0.2.0` shipped one. Pointing at `./src/*.ts` inside a tarball that also ships `src`, it resolved consumers to raw TypeScript and made a package with no `dist/` at all look healthy. Packages now resolve each other through `types`/`import` like any consumer, and CI builds before it type-checks. That is the whole trade: `types:check` and editor go-to-definition need `bun run build` first, and nothing that cannot ship is left inside a manifest. Everything the condition was load-bearing for keeps working through repo-local mechanisms: - Tests never used it. `vitest.config.ts` already aliases every workspace package to its `src/`, which is why `bun run test` is untouched here. - `scripts/ai-docs.ts` read it to find each subpath's source. It now derives the source from the built target — `./dist/x/index.js` is `./src/x/index.ts` by construction, since every package builds `rootDir: src` to `outDir: dist`. Verified to map the same 30 sources the condition named. - `scripts/bench-compare.ts` bundled with `conditions: ['development']` so a baseline checkout could be measured without a build. An esbuild resolver plugin does it by path instead, and produces byte-identical sizes on all 11 entries. - The playgrounds pinned it in `vite.config.ts` and `tsconfig.json`. They resolve `dist` now, so `deploy-playgrounds.yml` builds the packages first. `scripts/strip-development-exports.ts` and its test are deleted, and the step is gone from `release:publish` — there is nothing left to strip. `resolve-workspace-protocol` and `copy-license` stay: npm cannot install a `workspace:*` specifier, and it only bundles a LICENSE from inside the package directory. `check-publishable.mjs` keeps its check for the condition, now as a regression guard — reintroducing one would restore exactly the failure above, and the publish is the last place to catch it.
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@amritk/mini-lynx-native@0.2.0reached npm as a src-only tarball —filesdeclaresdist, the exports map declares./dist/index.js,./dist/background/index.jsand./dist/testing/index.js, and none of it is in the published package.It was not a packing bug. The package was published by hand rather than through the release workflow, so none of the three things
release:publishdoes beforechangeset publishran. The registry metadata is unambiguous:mini-lynx-native@0.2.0lynx-dialogs@0.2.0amritk, node 26.3.0Three misses at once: no
bun run build, so nodist/; nostrip-development-exports, so thedevelopmentcondition survived into the published manifest; nocopy-license, so the tarball carries no LICENSE.The surviving
developmentcondition is why a broken package stayed usable enough that this went unnoticed for a release. It resolves to./src/*.ts, andsrcdoes ship, so anything honouring that condition got raw TypeScript and looked healthy. Anything that did not — plain Node, a bundler on default conditions,tscreadingtypes— got a resolution failure against a manifest naming files that were not in the tarball. Consumers have been working around it by forcing the condition on: acustomConditionsentry intsconfig.json, a resolve condition in the bundler config, a--conditions developmentflag on the test command.The repo's existing guards were never wrong about this.
scripts/dist-smoke.test.tsandscripts/consumer-e2e.test.tsboth cover this package and both pass. Neither runs when someone typesnpm publishin a package directory.Changes
.changeset/mini-lynx-native-dist.md— patch bump for@amritk/mini-lynx-native, republishing the same code through the release workflow so 0.2.1 carriesdist/and its type declarations. The four@amritk/lynx-*packages pin the bridge at an exact version ("@amritk/mini-lynx-native": "0.2.0"), so their 0.2.0 releases still resolve the broken tarball; changesets bumps them alongside it and they re-pin to 0.2.1. Confirmed with achangeset versiondry run.scripts/check-publishable.mjs— the gate the hand-publish went through. Fails when an exports map points at adist/file that is not on disk, when adevelopmentcondition is still present, or when the package directory has no LICENSE. Plain node and node builtins only, so it cannot be skipped by an environment without bun.prepublishOnlyin all eight publishable packages —mini,mini-lynx,mini-lynx-native,mini-helpersand the fourlynx-*.prepublishOnlyrather thanprepackdeliberately:consumer-e2epacks synthetic copies withnpm packfrom a scratch directory, and aprepackhook would fire there against a tree that has no../../scripts.scripts/check-publishable.test.ts— seven cases, including the exact shape that shipped (a manifest promising dist against a tree with none) and the vacuous-pass case (an exports map with no dist target at all).Testing
Beyond the suites below, the publish path was simulated end to end:
resolve-workspace-protocol→strip-development-exports→copy-license, thennpm publish --dry-runinpackages/mini-lynx-native. It packs 52 files including all ofdist/and LICENSE, withprepublishOnlyrunning and passing. Withdist/moved aside, the same command fails and names all six missing export targets.bun run testpasses (932 tests)bun run checkpassesbun run check:reactivitypassesbun run types:checkpassesbun run buildpassesbunx changeset) if this affects a published packageAlso run:
bun run test:dist(57 tests, up from 50),bun run check:ai-docs, and thegenerate-llmsdiff.Related issues
Generated by Claude Code
📦 Bundle-size delta vs main (
9c6b6bc→6516dd0)Gzipped bytes of each bundled entry (esbuild, minified, browser/es2022, optional peer deps external). Bundling is deterministic, so unlike a timed benchmark these numbers carry no noise and every Δ is exact. ⚪ within ±0.5% · 🟢 smaller · 🔴 larger. Each package's
core (.)must stay flat as subpath features land — that is the whole charter, andsrc/core-size-budget.test.tsholds the absolute ceiling.