Releases: saintparish4/opal
Release list
v0.3.1
Full Changelog: v0.3.0...v0.3.1
v0.3.0
v0.2.1
A performance fix for one finding: a 367-package Next.js install spent most of its time parsing package metadata it never used, and almost none of it on the network.
Every package on the registry publishes a record of every version it has ever released. Opal was building the full dependency detail for all of them before selecting one. On that project it parsed 130,246 published versions to choose 367, then held the rest in memory and freed it again.
Version bodies are now kept as raw slices and parsed on demand.
Measured
On a 367-package Next.js tree with a warm store and warm metadata:
| before | after | |
|---|---|---|
| whole install, offline | 128.6s | 37.7s |
| the resolve phase alone | 74.3s | 8.4s |
| whole install, with network | 188.9s | 60.0s |
--prefer-offline |
— | 26.0s |
| lockfile and tree already present | — | 5.9s |
Also in this release
- Per-phase timings.
365 packages resolved in 587.1sdescribed the whole install, not resolution. It now reads(resolve 43.2s, fetch 0.5s, link 13.5s), because those three phases are slow for unrelated reasons and one total hides which to fix. - Fewer syscalls when linking. A 21,000 file tree made 21,000
create_dir_allcalls where a few hundred would do. Invisible on ext4, and not on a DrvFS mount under WSL2. - The hardlink warning now names the remedy. If your project and cache sit on different filesystems, every file is copied instead of linked, which can be most of an install's time. Set
OPAL_CACHE_DIRto the same filesystem, or move the project off/mnt/cif you are on WSL2.
Note
A version a registry lists but cannot be installed from — no tarball, or no usable integrity — is now skipped in favour of the next best match, rather than being filtered out when the packument was first read.
No lockfile format change. v0.2.0 lockfiles are read as-is.
Full Changelog: v0.2.0...v0.2.1
v0.2.0
Correctness, speed, and visibility across the package manager. Four bugs in this release produced a wrong node_modules without ever failing an install.
Breaking
opal.lock is now v3. A v0.1.0 binary refuses a v3 lockfile rather than misreading it, so upgrade before sharing a lockfile with one. Going the other way, v0.2.0 replaces a v1 or v2 lockfile by re-resolving — except under --frozen-lockfile, where it is an error, because a build that promised not to rewrite the lockfile must not rewrite it to upgrade it either.
A required dependency this platform cannot run is now EBADPLATFORM, matching npm. Previously it installed and produced a tree that could not run. A package declared in optionalDependencies is still skipped, which is how jest, vite and anything else depending on fsevents keeps working.
The graph cache misses once after upgrading: the resolver learned to walk files it used to skip, so records written by v0.1.0 no longer describe what it would produce.
Fixed — installs that were silently wrong
- A root dependency could be linked at the wrong version. With
shared@^1declared alongside a dependency onshared@^2, the tree got 2.x at the top level and the version you asked for was downloaded and never placed. --productionoverwroteopal.lock, and--production --frozen-lockfile— the ordinary CI invocation — failed against a perfectly valid lockfile every time.- Platform variants of native optionals all installed.
esbuilddeclares 25, totalling 256 MB; one 9.8 MB binary is what belongs on a host. They stay recorded inopal.lock, so one committed file still installs the right binary on every platform. - A dependency could write lines into your lockfile.
Range::parse(">=1\npkg …")kept the newline and the lockfile is one fact per line, so a dependency's ownpackage.jsoncould append entries — including package entries with attacker-controlled tarball URLs — to the lockfile of every project installing it. Found by fuzzing.
Faster
- Registry metadata is cached across runs. Re-resolving a 74-package tree against a warm store went from 7.6s to 0.36s, making no round trips at all.
--offlineand--prefer-offlineare new. - Packuments are fetched in npm's abbreviated form, roughly half the bytes.
- The CAS hashes before writing, so content it already holds costs a hash and a
statinstead of a write, an fsync, a read-back and a rename.
New
npm:alias specifiers."string-width-cjs": "npm:string-width@^4.2.0"installs one package under another's name — how a package depends on two majors of one dependency at once. Unblocksglob@10,rimraf@5,node-gyp@10andsucrase, which could not be installed at all.- Progress output. A spinner while resolving and linking, a bar advancing per package while fetching, and one warning per deprecated package. Plain lines when stderr is not a terminal, so CI logs stay readable.
opal cache gcprunes what it can no longer use — graph records for deleted projects, and registry metadata past 30 days.- Bounded retries and explicit timeouts on registry requests; ceilings on what a tarball may unpack to.
Install
curl -fsSL https://raw.githubusercontent.com/saintparish4/opal/master/install.sh | bashmacOS and Linux, x64 and arm64. WSL2 is covered by the Linux builds. Native Windows remains a v2 target.
Full Changelog: v0.1.0...v0.2.0
v0.1.0
Full Changelog: https://github.com/saintparish4/opal/commits/v0.1.0