Skip to content

chore(deps): update dependencies and pnpm 12 - #91

Merged
kodiakhq[bot] merged 3 commits into
mainfrom
chore/update-dependencies
Sep 25, 2026
Merged

kodiakhq[bot] merged 3 commits into
mainfrom
chore/update-dependencies

Conversation

@mheob

@mheob mheob commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Summary

The workspace moves to pnpm 12 and to the newest release of every dependency that is at least three days old — with three deliberate exceptions, each for a reason stated below. Go is already current; apps/api has no outdated direct module.

Changes

build: move to pnpm 12 — packageManager goes to pnpm@12.6.0, and pnpm/action-setup to 6.1.0 in all four places ci-js.yml pins it. 6.1.0's only change is pnpm 12 support; CI would not install on 6.0.10. The lockfile gains a leading YAML document that pins the package manager itself, with an integrity hash for each platform's native binary. The dependency graph below it is untouched in that commit.

chore(deps): update dependencies — 23 packages, among them cn 0.2.6 → 0.4.0, recharts 3.8.0 → 3.10.1, oxlint 1.82 → 1.85, oxfmt 0.67 → 0.70, Vitest 5.0.1, React Query 5.103, and Sentry within v10 to 10.75.2.

fix(web): clear oxlint 1.85's new findings — two rules got stricter; details under Testing.

Motivation

Routine maintenance, 19 days after #45. Renovate is installed but has not opened a single pull request since the repository began; that is a configuration problem and gets its own change. This one brings the tree current by hand, following #45's procedure.

The release-age window is passed explicitly. pnpm-workspace.yaml carries a minimumReleaseAgeExclude list but no minimumReleaseAge, and pnpm config list confirms none is set — an exclusion from a gate that does not exist. So this run passed --config.minimum-release-age=4320, the three days the Renovate preset applies. It demonstrably held: Sentry landed on 10.75.2 rather than 10.75.3, published about 49 hours earlier, and likewise for TanStack, Lucide, Supabase and cve-lite-cli. pnpm 12.6.0 was chosen over 12.7.0 on the same rule.

Held back, on purpose:

  • TypeScript in packages/api-client stays on 6. Its generator crashes on 7, as CLAUDE.md records. Regenerating the client produces byte-identical output, which is the proof the pin still holds.
  • Sentry stays on 10. 11.0.0 is two days old. lib/observability.ts sets every dataCollection field explicitly because v10 resolves a partial object against permissive defaults — the semantics a major is most likely to change, and exactly what decides what leaves the browser. It deserves its migration guide read, in a change of its own.
  • The TanStack Router family is pinned exactly at the versions main runs — react-router 1.170.35, react-router-devtools 1.167.1, react-router-ssr-query 1.167.2, react-start 1.168.52.

That last one was found, not planned. router-core 1.171.30 changed interpolatePath from an options object to positional arguments — in a patch release — and @storybook/tanstack-react 10.6.0 still calls the old form. Every one of the 74 stories failed with path.endsWith is not a function. It is reported upstream as storybookjs/storybook#36330, and fixed by storybookjs/storybook#36333, merged to next on 2026-09-21 and in no published release yet: 10.6.0 predates it and 11.0.0-alpha.1 came out two days before the merge. Unpin once a release carries #36333.

Pinning the direct dependencies was not enough on its own. The in-range sweep had lifted router-core under Storybook's own caret ranges and under start-client-core, which pins its core exactly, so pnpm dedupe could not fold them — the tree held two router cores, which on main it never did. The lockfile was therefore rebuilt from main's graph with the new manifests, so only the direct dependencies that changed were re-resolved. The TanStack subgraph now matches main package for package.

cn was checked rather than trusted. Twenty-one generated shadcn files import it, and they cannot be edited. Its package is legitimate (maintainer shadcn, repository shadcn-ui/cn), but two releases in the range change class merging: 0.3.1 lets axis utilities override logical sides, and 0.3.2 stops merging custom animate-* classes. Neither reaches this code — there is exactly one logical-side utility in the frontend, on a different axis from its neighbour, no animate-none, and no pair of custom animations in one variant.

Testing

  • pnpm format, pnpm lint, pnpm typecheck — silent.
  • Web unit tests — 541 passed across 68 files.
  • Storybook — 74 passed across 22 files, each story rendered in real Chromium under axe. This is the check that caught the router break.
  • pnpm --filter=web run build — exits 0; routeTree.gen.ts unchanged and its Register block intact.
  • pnpm run generate:api — byte-identical output.
  • pnpm cve — no known vulnerabilities.

The two lint findings, neither caused by the version changes:

  • no-base-to-string now sees that Recharts types a tooltip label as ReactNode, which admits objects and, in React 19, promises. The chart passed it through String(); it now formats a string and renders no label otherwise. The type is identical in recharts 3.8 and 3.10, so this was latent.
  • consistent-function-scoping flagged two stubs in the stats route test. The same pair was declared inline in three tests, each with its own copied suppression; it now lives once at module level, beside the rejecting helpers it mirrors.

Known and pre-existing, not introduced here: pnpm peers check reports @typescript-eslint 8.70 wanting TypeScript <6.1 while the repository is on 7, and @storybook/addon-vitest 10.6.0 wanting Vitest ^4 while the repository has been on 5 since #45. 10.6.0 is the newest stable addon. Both run green. The build also warns about two test files inside routes/; the router plugin and generator are the same versions as on main.

Worth watching in this PR's own checks: Vercel installs from packageManager with no installCommand of its own, so the preview deployments are the first real proof that Vercel's builders take pnpm 12 and the new lockfile header.

Breaking Changes

None for the application. For anyone working in the repository: pnpm 12 now fails outright on an unrecognised key in pnpm-workspace.yaml when the pinned version matches, where pnpm 11 ignored it; and pnpm install --frozen-lockfile false is no longer accepted — use --no-frozen-lockfile. Nothing in this repository used the latter.

12.6.0 rather than 12.7.0: the newer one is from today, and 12.6 is
exactly the three days the Renovate preset holds every other update
back by.

pnpm/action-setup moves to 6.1.0 with it. Its only change is pnpm 12
support, so CI would not install on 6.0.10.

The lockfile gains a leading YAML document that pins the package
manager itself, with integrity hashes for each platform's native
binary. The dependency graph below it is unchanged.
Everything moves to the newest release that is at least three days
old. The manual run passes that window explicitly, because pnpm
itself sets no minimumReleaseAge here; three days is what the
Renovate preset applies.

Three things are held back on purpose:

- typescript in packages/api-client stays on 6. Its generator crashes
  on 7, as CLAUDE.md records.
- @sentry/tanstackstart-react stays on 10. 11.0.0 is two days old, and
  lib/observability.ts sets every dataCollection field explicitly
  because of how v10 resolves a partial object. That wants its
  migration guide read first, in a change of its own.
- The TanStack Router family is pinned exactly at the versions main
  ran. router-core 1.171.30 changed interpolatePath from an options
  object to positional arguments in a patch release, and
  @storybook/tanstack-react 10.6.0 still calls the old form: every
  story failed with "path.endsWith is not a function". The fix is
  storybookjs/storybook#36333, merged to next on 2026-09-21 and in no
  release yet. Unpin once one carries it.

The lockfile is rebuilt from main's graph with the new manifests
rather than swept with an in-range update. The sweep had lifted the
router core under Storybook's own caret ranges and left two router
cores in the tree; now there is one, as on main.
Two rules got stricter. Neither finding came from the dependency
versions themselves.

no-base-to-string now sees that Recharts types a tooltip label as
ReactNode, which admits objects and, in React 19, promises. The chart
passed it through String(); it now formats a string and renders no
label for anything else. The type is identical in recharts 3.8 and
3.10, so this was latent rather than introduced.

consistent-function-scoping flagged two stubs in the stats route test
that capture nothing. The same pair was declared inline in three
tests, each with its own copy of the suppression. It now lives once at
module level, beside the rejecting helpers it mirrors.
@vercel

vercel Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
kurze-url-api Ready Ready Preview Sep 25, 2026 2:27pm UTC
kurze-url-web Ready Ready Preview Sep 25, 2026 2:27pm UTC

Request Review

@kodiakhq
kodiakhq Bot merged commit a653a53 into main Sep 25, 2026
27 checks passed
@kodiakhq
kodiakhq Bot deleted the chore/update-dependencies branch September 25, 2026 14:30
kodiakhq Bot pushed a commit that referenced this pull request Sep 25, 2026
## Summary

Renovate has been installed since the repository began and has never opened a pull request. This fixes why, and — because every green pull request here merges itself — makes sure that once it does start, a major cannot land without someone deciding it should. A release-age gate for manual installs rides along, since it is the same policy from the other side.

## Changes

**`.github/renovate.json`**, four rules on top of the shared preset:

- **One weekly window for every update**, Monday before 6am Berlin time.
- **Majors open as drafts** (`draftPR`).
- **TypeScript in `packages/api-client` capped below 7** (`allowedVersions`).
- **The TanStack Router family disabled** — `react-router`, `react-router-devtools`, `react-router-ssr-query`, `react-start` — matching the exact pins from #91.

Each rule carries a `description` saying why, so the reason travels with it into the dashboard.

**`pnpm-workspace.yaml`** — `minimumReleaseAge: 4320`.

**`CLAUDE.md`** — one entry under "Non-obvious constraints". Neither Renovate nor Kodiak was documented anywhere in the repository or its planning docs.

## Motivation

**Why no pull request ever arrived.** The preset `github>mheob/renovate-config` gives dependencies, devDependencies and the package manager separate schedules, and its non-major group puts dependencies and devDependencies into one branch. Together with the two-hour Wednesday window this file used to set, the Dependency Dashboard (#1) listed everything as "Awaiting Schedule" from 2026-09-01 to 2026-09-25. The outcome is observed; Renovate's exact reckoning for a group spanning several schedules was not verified, which is why the fix is a single window that matches everything rather than a tuned intersection. The hosted app visits a repository only every few hours, so a narrow weekly window can be missed week after week.

**Why fixing the schedule alone would have been dangerous.** Kodiak's configuration lives in `mheob/.github`'s `.github/.kodiak.toml`, shared across repositories, with `require_automerge_label = false` and no `blocking_labels`. #85, #86 and #90 carried no label and were merged by Kodiak all the same. A working schedule would therefore have auto-merged whatever Renovate proposed the moment its checks passed — including two branches the dashboard already showed pending:

- **`typescript-7.x`** would lift `packages/api-client` onto TypeScript 7. CI never runs the client generator, so it passes every check, merges, and breaks the next `pnpm run generate:api` with nothing pointing back at the cause.
- **Sentry 11**, once three days old. `lib/observability.ts` sets every `dataCollection` field explicitly because of how v10 resolves a partial object; a change there is exactly what decides what leaves the browser, and no test would notice.

**Why drafts rather than a dashboard tick or a label.** Kodiak never merges a draft, and CI still runs on one — `pull_request` triggers here carry no draft filter, and Vercel builds previews for drafts too — so the pull request exists with its checks already run, and marking it ready for review is the decision. A dashboard-approval gate would stop the pull request from being created at all, so the decision would have to be made before seeing whether it is green. A blocking label would work just as well — the preset already tags majors `major ⚠️`, so `blocking_labels = ["major ⚠️"]` in the Kodiak config would need no Renovate change — but that file governs every repository sharing it, which is a decision beyond this one.

**The release-age gate.** `pnpm-workspace.yaml` already listed packages to exclude from a release-age gate that nothing set; `pnpm config list` confirmed none was in effect. pnpm 12's own release notes name this pattern — a policy that silently is not there — as the reason its settings check got stricter. 4320 minutes is the three days the preset's `:security` preset gives Renovate, so a manual `pnpm add` or `pnpm update` now holds back what Renovate would.

## Testing

- `renovate-config-validator --strict` passes, run both against the file as global config and — without a path argument, so it discovers the file itself — as a repository config, which is the stricter of the two. It was run through `npx` with install scripts disabled: pnpm 12's `dlx` refuses to finish while Renovate's dependencies carry unapproved build scripts, and approving them for a validator was not worth it. Its only warning is that RE2 is unbuilt and regex validation may be approximate; this file uses no patterns, only exact names and `*`.
- `pnpm install` accepts `minimumReleaseAge` under pnpm 12 — which now fails on an unrecognised key when the pinned version matches — and `pnpm config get minimumReleaseAge` reports 4320. The lockfile passes as it stands, because #91 was resolved under the same window.
- `pnpm format` and `pnpm lint` are silent.

What cannot be tested here is Renovate's next run. The first real evidence is the Dependency Dashboard after the coming Monday morning: updates should move out of "Awaiting Schedule", and any major should arrive as a draft.

## Breaking Changes

None for the application. Two changes in how dependencies arrive: Renovate majors now appear as drafts that wait for a human, and a manual install refuses any package published less than three days ago. A security fix that is still too fresh goes through `--config.minimum-release-age=0` on that one command, as the comment in `pnpm-workspace.yaml` says.
kodiakhq Bot pushed a commit that referenced this pull request Oct 3, 2026
## Summary

Ends the TanStack hold-back from #91 and the CVE exemptions from #99. `@storybook/tanstack-react` 10.6.1 carries the `interpolatePath` fix the pins were waiting for, and the twelve CVE-2026-102989 versions are now older than the three-day release-age gate.

## Changes

- `apps/web/package.json`: `@tanstack/react-router`, `react-router-devtools`, `react-router-ssr-query` and `react-start` move from exact pins to caret ranges at their current versions.
- `.github/renovate.json`: the rule disabling those four packages is removed.
- `pnpm-workspace.yaml`: the twelve exact-version `minimumReleaseAgeExclude` entries for CVE-2026-102989 are removed, as their comment asked after 2026-10-03T18:00Z.
- `pnpm-lock.yaml`: `pnpm update -r --depth 99 @tanstack/start-client-core` moves Storybook's copy onto the version the app already uses, so the second `router-core` (1.171.29), `start-client-core`, `start-storage-context` and `history` drop out of the tree. Nothing else in the lockfile changes.
- `CLAUDE.md`: the Renovate passage now says why the hold existed and why it ended. It also records the trap that remains: Storybook reaches `start-client-core` through its own caret range, so updating only the direct dependencies leaves a second router core, and pnpm 12 rejects `--depth Infinity`.

## Motivation

`router-core` 1.171.30 changed `interpolatePath`'s signature in a patch release, and Storybook 10.6.0 failed every story on it. storybookjs/storybook#36333 fixed that and shipped in 10.6.1, released 2026-09-29, according to its release notes. That version is already installed here. Keeping the pins would block the router family's future fixes, security releases included.

## Testing

- `pnpm install --frozen-lockfile` passes the supply-chain policy without the exclusions.
- `pnpm lint` and `pnpm typecheck` are clean.
- Web unit tests: 783 passed.
- Storybook tests: 116 passed. These were what broke on the router-core change.
- `pnpm --filter @kurze-url/web run build` succeeds, and `routeTree.gen.ts` is unchanged.

## Breaking Changes

None.

This branch was successfully deployed

2 active deployments
Preview – kurze-url-web — 9edd21cf Deployed Sep 25, 2026 by vercel[bot]
Preview – kurze-url-api — 9edd21cf Deployed Sep 25, 2026 by vercel[bot]
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