fix(build): restore VTODO API in committed dist - #30
Merged
Conversation
The upstream sync added husky to devDependencies without updating pnpm-lock.yaml, so `pnpm i --frozen-lockfile` failed. That killed the Quality Checks install step, which in turn skipped the "verify dist is up-to-date" gate -- the guard that would have caught the VTODO API disappearing from the committed build. The repo also carried two lockfiles that disagree: pnpm-lock.yaml resolves sax@1.4.4 while package-lock.json resolved sax@1.4.3, so an npm build and a pnpm build produce different browser bundles. The build script, ci.yml, release.yml and AGENTS.md all use pnpm, so pnpm is the single source of truth and the npm lockfile goes.
Consumers install this fork by git URL. npm runs `prepare` for a git dependency, but `prepare` only ran husky and the build hung off `prepublishOnly`, which a git install never triggers. So consumers got whatever `dist/` happened to be committed -- stale since the upstream sync -- with no way to notice. `prepare` now runs the build too. husky 9 exits 0 with a message when .git is absent, so it cannot block the build on a consumer install, and a dev-clone `pnpm install` still installs hooks and then builds. `build` no longer shells out to pnpm for the clean step; a consumer installing with npm has no pnpm on PATH and the build would have died there.
The version-bump check tested the staged file list with an unanchored grep, so `dist/package.json` matched as if it were the root manifest. Committing a rebuilt dist/ on its own then demanded a version bump that was already made in the preceding commit, and the hook could not be satisfied without bypassing it.
The upstream sync (f8d5561) resolved dist/ in favour of upstream's v2.1.8 build, which has no knowledge of this fork's additions. src/ was never touched, so the drift was invisible until a consumer imported it. Seven named exports were missing from the shipped bundles: todoQuery, todoMultiGet, fetchTodos, createTodo, updateTodo, deleteTodo and makeAddressBook. All 50 named exports in src/index.ts are now present in dist/tsdav.cjs.js and dist/tsdav.d.ts. Generated output only -- produced by `pnpm build`, not hand-edited.
The dist gate only ran when HEAD~1..HEAD touched src/, so it was blind to a merge commit that changes dist/ without changing src/ -- exactly how the VTODO API was lost. It now rebuilds and diffs unconditionally. It also ran on npm, whose lockfile resolved different transitive versions than pnpm's and so produced different browser bundles; the gate could not have agreed with a pnpm-built dist. Node was pinned to 18, below rimraf 6's `20 || >=22`, so the build step would have failed had the gate ever fired. Both now follow the rest of CI: pnpm 10 and the Node version in .nvmrc.
This was referenced Aug 14, 2026
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.
What was broken
The fork's VTODO API (
fetchTodos,todoQuery,todoMultiGet,createTodo,updateTodo,deleteTodo) lives insrc/but was missing from the committeddist/onmaster.makeAddressBookwas gone too — seven named exports in total.f8d5561 merge: sync upstream natelindev/tsdav (v2.1.6 → v2.1.8)resolveddist/in favour of upstream's v2.1.8 build, which knows nothing about this fork's additions.src/was untouched, so nothing looked wrong in review.Consumers install this fork by git URL. npm runs
prepareon a git install, butpreparewas just"husky"and the build hung offprepublishOnly, which a git install never triggers. So every npm consumer got the stale committeddist/. Downstream this breaks 6 of 8 todo tools inPhilflowIO/dav-mcp(dav-mcp#41). It did not reproduce for maintainers, whose lockfiles pin an older commit whosedist/still had the exports.Why the guards missed it
Three of them failed at once, and they compound:
huskytodevDependencieswithout updatingpnpm-lock.yaml.pnpm i --frozen-lockfilehas been broken onmasterever since.Install dependencies, soVerify dist is up-to-datewas skipped — the one gate that would have caught this.git diff HEAD~1 HEAD | grep "^src/". A merge commit changesdist/without changingsrc/, so it would have skipped anyway. It also ran on Node 18, below rimraf 6's20 || >=22, so its build step would have died.Changes
fix(deps): sync pnpm lock, drop npm lock--frozen-lockfile. Also removespackage-lock.json— see below.fix(build): rebuild dist on install for git depspreparenow runs the build;buildno longer shells out to pnpm. Version 2.3.0 → 2.3.1.fix(hooks): match root package.json exactlydist/package.json.fix(build): restore lost exports in committed distpnpm build, nothing hand-edited.ci: verify dist against a fresh build always.nvmrcNode.The only hand-written changes are
package.json(3 lines),.husky/pre-commit(1 line) and.github/workflows/quality-checks.yml. Everything underdist/is build output — review the four small files and takedist/on trust from the CI gate.On dropping
package-lock.jsonThe repo carried two lockfiles that disagree:
pnpm-lock.yamlresolvessax@1.4.4,package-lock.jsonresolvedsax@1.4.3. An npm build and a pnpm build therefore produce different browser bundles (verified:dist/tsdav.jsanddist/tsdav.min.jsdiffer in the bundled sax stream decoder). An unconditional dist gate can only work against one of them.build,ci.yml,release.ymlandAGENTS.mdall use pnpm, so pnpm wins and the npm lockfile goes. Nothing referenced it except the workflow this PR converts. Say the word if you'd rather keep it and I'll invert the choice.Proof
Baseline,
master:This branch:
And the drift-proof test — clone this branch,
git rm -r dist, commit, then git-install it:With
dist/absent from the repo entirely, the consumer still gets a working package. Committed-dist drift can no longer reach anyone.A dev-clone
pnpm installstill works (exit 0, husky hooks installed, then build). husky 9 exits 0 with a message when.gitis absent, so it cannot block the build on a consumer install.Not fixed here — follow-ups
pnpm typecheckis red onmaster.src/client.ts:267passesfetch: fetchOverridetomakeAddressBook, whose params type has nofetch. The merge added that line; the signature never had the field. So the KaiOS fetch override is dead formakeAddressBook, andci.yml/release.ymlare red. Left alone because it changes runtime behaviour and belongs in its own PR..husky/pre-commitstill uses the husky v8 preamble and prints a DEPRECATED warning on every commit; it will fail on husky v10.ci.ymlonly triggers on PRs tomain, but the default branch ismaster, so it never runs.