“TRAVERSING”
A pale woman with red lips emerging from smoke, birds in flight around her

Day One Hundred Forty-Six

What moves so that nothing does

/Log

Day one hundred forty-six, or something like that

Nothing you can see has changed. That is the whole point of days like this one.

Every site stands on other people's work, stacked like sediment. This one sits on roughly a thousand packages I never chose one by one, resolved into a lockfile nobody reads. Today I read it. Or at least I had the machine read it to me, line by line, out loud.

The inventory

npm outdated returned thirty-nine lines. npm audit returned twenty-seven vulnerabilities: eleven moderate, fifteen high, one critical. The critical one lived inside Next.js itself, the framework holding up every page here. The fix was already sitting inside the semver range, waiting. Most fixes are.

So: npm update, then npm audit fix, without --force. The lockfile rewrote itself, 5,935 lines in and 4,879 lines out. Next went from 16.2.10 to 16.3.6, Sanity from 6.5 to 6.16, React to 19.3.

What broke

Three things, which is not many for a diff that size.

Next 16.3 no longer knows what experimental.viewTransition means. View Transitions are simply on now, the experiment having graduated into ordinary life. I deleted four lines of config. There is a particular pleasure in fixing something by removing it.

@sanity/ui renamed a prop on Stack from space to gap. Same distance between things, a new word for it.

And dotenv disappeared. I had never installed it. It had been arriving for months as a dependency of a dependency, and my scripts had quietly come to rely on a guest nobody invited. Node has been able to read an env file on its own for a while, so process.loadEnvFile('.env.local') took its place. One import fewer.

The icons

Then the build failed with twenty-three errors, all the same shape:

Export ArrowUpIcon doesn't exist in target module

@sanity/icons had jumped from 3.8 to 5.2 underneath me, lifted into the root of node_modules by hoisting because some other package wanted the new one. Version 5 no longer exports icons as named components, only a single Icon and a map of symbols. Every schema in the Studio that owned an arrow, a calendar, a star, was suddenly pointing at nothing.

This too was a dependency I had never declared. The fix was to finally admit it: @sanity/icons@^3, written into package.json as a direct dependency. npm now keeps 3.8 at the root for me and nests 5.2 under the packages that asked for it. Two versions of the same icons, living in the same tree, not speaking to each other.

The majors

Then the harder ones. Release notes first, one commit each.

@sanity/client 8 is ESM-only, wants Node 22.12, and drops the requester option and the per-request proxy. I used none of it. @portabletext/react 8 now nests lists by their level, which changes nothing here and is more correct everywhere else.

@sanity/visual-editing I did not upgrade. I removed it. It was listed in package.json and imported nowhere, since next-sanity ships its own copy. It had been sitting there like a coat left on a chair after the party.

motion 13 stopped borrowing @emotion/is-prop-valid whenever it happened to find it lying around in node_modules (it always did, courtesy of styled-components). Now it only uses what you hand it explicitly. Honest behaviour, at last.

nodemailer 10 is written in TypeScript now and brings its own types, so @types/nodemailer left with it. three moved to r186, which removes PCFSoftShadowMap. I checked every <Canvas> on the site. None of them casts shadows. That felt about right.

What I left behind

Four packages stay where they are, on purpose.

ESLint 10, because eslint-plugin-react crashes on it somewhere deep in usedPropTypes.js. Not mine to fix.

TypeScript 7, the compiler rewritten in Go. It type-checked the whole project without a complaint, and Next built with it, the TypeScript step finished in 1,579 milliseconds. Then typescript-eslint refused to even start: does not support TS 7.0. Fast, and alone. I went back to 5.9.3.

@types/node 26, because production runs on Node 24, and types should not promise what the runtime cannot give. And @sanity/icons 5, for the reasons above.

Numbers

Vulnerabilities: 27 → 13. Critical: 1 → 0. The three highs that remain live inside Sanity's CLI tooling, and npm's only suggestion is a downgrade to Sanity 5, which is not a fix, it is a retreat. Lint: 0 errors, 184 warnings, same as before. Build: green. Four commits.

None of it shows. The ICQ window opens the same way, the music still comes down from archive.org, and when the analyser can't hear anything the visuals still pulse on a synthetic 4/4 at 120 BPM. Maintenance is the work of keeping everything exactly where it was while the ground underneath it moves. Like repainting a room and hanging every picture back on the same nail.

Glad that nobody will read this

Day One Hundred Forty-Six · Log | Federico Bebber