Skip to content

fix(build): restore VTODO API in committed dist - #30

Merged
PhilflowIO merged 5 commits into
masterfrom
fix/rebuild-dist-with-todo-api
Aug 14, 2026
Merged

fix(build): restore VTODO API in committed dist#30
PhilflowIO merged 5 commits into
masterfrom
fix/rebuild-dist-with-todo-api

Conversation

@PhilflowIO

Copy link
Copy Markdown
Owner

What was broken

The fork's VTODO API (fetchTodos, todoQuery, todoMultiGet, createTodo, updateTodo, deleteTodo) lives in src/ but was missing from the committed dist/ on master. makeAddressBook was gone too — seven named exports in total.

f8d5561 merge: sync upstream natelindev/tsdav (v2.1.6 → v2.1.8) resolved dist/ 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 prepare on a git install, but prepare was just "husky" and the build hung off prepublishOnly, which a git install never triggers. So every npm consumer got the stale committed dist/. Downstream this breaks 6 of 8 todo tools in PhilflowIO/dav-mcp (dav-mcp#41). It did not reproduce for maintainers, whose lockfiles pin an older commit whose dist/ still had the exports.

Why the guards missed it

Three of them failed at once, and they compound:

  1. The same merge added husky to devDependencies without updating pnpm-lock.yaml. pnpm i --frozen-lockfile has been broken on master ever since.
  2. Quality Checks run 24032766404 on that merge failed at Install dependencies, so Verify dist is up-to-date was skipped — the one gate that would have caught this.
  3. Even had it run, it was keyed on git diff HEAD~1 HEAD | grep "^src/". A merge commit changes dist/ without changing src/, so it would have skipped anyway. It also ran on Node 18, below rimraf 6's 20 || >=22, so its build step would have died.

Changes

Commit
fix(deps): sync pnpm lock, drop npm lock Restores --frozen-lockfile. Also removes package-lock.json — see below.
fix(build): rebuild dist on install for git deps prepare now runs the build; build no longer shells out to pnpm. Version 2.3.0 → 2.3.1.
fix(hooks): match root package.json exactly The version-bump check's unanchored grep matched dist/package.json.
fix(build): restore lost exports in committed dist Generated output only. ~2.5k lines, all from pnpm build, nothing hand-edited.
ci: verify dist against a fresh build always Unconditional rebuild + diff, on pnpm and the .nvmrc Node.

The only hand-written changes are package.json (3 lines), .husky/pre-commit (1 line) and .github/workflows/quality-checks.yml. Everything under dist/ is build output — review the four small files and take dist/ on trust from the CI gate.

On dropping package-lock.json

The repo carried two lockfiles that disagree: pnpm-lock.yaml resolves sax@1.4.4, package-lock.json resolved sax@1.4.3. An npm build and a pnpm build therefore produce different browser bundles (verified: dist/tsdav.js and dist/tsdav.min.js differ in the bundled sax stream decoder). An unconditional dist gate can only work against one of them. build, ci.yml, release.yml and AGENTS.md all 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:

$ npm install github:PhilflowIO/tsdav#master
version: 2.3.0
FAIL fetchTodos / todoQuery / todoMultiGet / createTodo / updateTodo / deleteTodo
missing on master: 6/6

This branch:

$ npm install github:PhilflowIO/tsdav#fix/rebuild-dist-with-todo-api
installed tsdav version: 2.3.1

OK   DAVClient.prototype.fetchTodos    -> function
OK   DAVClient.prototype.todoQuery     -> function
OK   DAVClient.prototype.todoMultiGet  -> function
OK   DAVClient.prototype.createTodo    -> function
OK   DAVClient.prototype.updateTodo    -> function
OK   DAVClient.prototype.deleteTodo    -> function
OK   require('tsdav').makeAddressBook  -> function

ALL SIX TODO METHODS PRESENT

And the drift-proof test — clone this branch, git rm -r dist, commit, then git-install it:

dist files in HEAD: 0
$ npm install git+file:///.../drift-repo#fix/rebuild-dist-with-todo-api
OK   fetchTodos / todoQuery / todoMultiGet / createTodo / updateTodo / deleteTodo
PREPARE REBUILT DIST FROM SRC: all six present

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 install still works (exit 0, husky hooks installed, then build). husky 9 exits 0 with a message when .git is absent, so it cannot block the build on a consumer install.

Not fixed here — follow-ups

  • pnpm typecheck is red on master. src/client.ts:267 passes fetch: fetchOverride to makeAddressBook, whose params type has no fetch. The merge added that line; the signature never had the field. So the KaiOS fetch override is dead for makeAddressBook, and ci.yml / release.yml are red. Left alone because it changes runtime behaviour and belongs in its own PR.
  • .husky/pre-commit still uses the husky v8 preamble and prints a DEPRECATED warning on every commit; it will fail on husky v10.
  • ci.yml only triggers on PRs to main, but the default branch is master, so it never runs.

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.
@PhilflowIO
PhilflowIO merged commit d411d78 into master Aug 14, 2026
1 check passed
@PhilflowIO
PhilflowIO deleted the fix/rebuild-dist-with-todo-api branch August 14, 2026 20:43
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