The registry answers POST /-/stage/package with a 404 for a name it has not
seen, so the first release of a new name cannot be staged at all — no token
scope changes that. The step now says so and lets the release stand rather
than failing after PyPI has already published.
The first version goes out by hand with 2FA; every one after it stages from
here.
wasm-pack downloads binaryen to get wasm-opt, and that download fails on this
runner while the same URL fetched with curl succeeds. wasm-pack uses a
wasm-opt already on PATH when it finds one, so the archive is fetched here
and put there.
Turning wasm-opt off instead would have been the smaller change and the
wrong one: the metadata in crates/bindings/Cargo.toml names the WebAssembly
features to keep the optimisation rather than skip it, and a release that
silently shipped an unoptimised module would be the first thing anyone
downloaded.
Publishing by hand needs a laptop with two credentials on it, and gets the
gate only if whoever ran it remembered. This runs the same `check.sh` every
push runs, then builds and uploads — and refuses at the first step if the tag
and the workspace version disagree, because a release tagged v0.3.0 that
publishes 0.2.0 cannot be undone: PyPI will not reuse a version even after it
is yanked.
Wheels are cross-compiled with zig for x86_64 and aarch64 against an older
glibc than the build image ships, so they are not silently pinned to
bookworm's, and an sdist covers everything else.
PyPI is uploaded directly. npm is only staged: npm is withdrawing direct
publish from tokens that bypass 2FA, and its trusted publishing is OIDC
against GitHub and GitLab, which this forge is neither. So the runner does
the part a token may do, and a maintainer approves the tarball with 2FA.
A missing NPM_TOKEN is a warning rather than a failure, so a release can go
to PyPI while the npm credential is still being sorted out.