Repository navigation
v0.0.645
One command to start, branch caches the server enforces
Starting with vx is now one command: vx init installs vx for you.
A cache server, not the client, now keeps a branch's builds out of
main's entries. A remote hit whose download would outlast the task
gives way and the task runs here, and a local hit copies its files out
without checking them first.
This release is breaking: cache.store.verify is gone, task keys reach
the remote plain, and vx init maps only Turbo and Nx repos.
Read the breaking changes first.
Enjoy the release!
In this release
- One command to start
- Branch caches the cache server enforces
- A slow download no longer holds a fast task
- Other noteworthy changes
- Breaking changes
One command to start
Starting meant installing @vzn/vx first, then running vx init.
Now vx init installs vx itself: globally, with the package manager
that started it, so a bare vx is on your PATH (skipped when that vx
is already this version), and as a root devDependency with the repo's
own manager. Beside a turbo.json or nx.json it hands the repo to
@vzn/vx-migrate; anywhere else it writes .vx/workspace.ts and an
empty root vx.config.ts, then locks.
bunx @vzn/vx init─ vx init 0.0.645 ────────────────────────────────────────────
from no turbo.json or nx.json: one project, the root
files .vx/workspace.ts
vx.config.ts
.vx/.gitignore
.vx/.gitattributes
installed bun add -g @vzn/vx@0.0.645
bun add @vzn/vx@0.0.645 --dev
lock 1 project config → .vx/projects.lock.json
next declare a task in vx.config.ts, then vx lock && vx run <task>See the quickstart.
Branch caches the cache server enforces
A pull request should read what main built and never write where main
reads. vx used to decide that on the client, with a second, scoped key
per task, so only the client kept a branch out of main's entries.
Task keys now reach every remote plain. The CI OIDC token, checked
against the cache server's trust policy, decides where a write lands:
main's entries, the token's own branch, or nowhere. turboCache() only
steers reads: every HEAD, GET and batch POST names the run's refs,
its own branch first, in x-artifact-read-scopes. On CI the refs come
from its env; on a laptop from git (the current branch, then
origin/HEAD).
HEAD /v8/artifacts/0a1b2c3d4e5f6789
x-artifact-read-scopes: refs/heads/feat-x, refs/heads/mainflowchart LR
PR[CI on feat-x] -- "reads feat-x, then main" --> S[cache server]
PR -- "writes, OIDC token: feat-x" --> S
S -- "files the write under" --> B[feat-x entries]
M[CI on main] -- "writes, OIDC token: main" --> S
S --> T[main entries]For a server that ignores the header, such as Vercel's,
turboCache({ scope: 'key' }) folds the ref into each key and asks for
every ref's key in one batch; the first hit wins. How a server
implements its half:
Branch caches a server enforces.
A slow download no longer holds a fast task
A remote hit always waited for its whole body, even when running the
task would have finished first: a large artifact on a slow link held its
task longer than the task takes.
A remote that says an entry's size and the task's stored time (Turbo's
API does, in its batch query and HEAD) now lets vx weigh each download
while a task waits on it. When the rest of the body would take longer
than twice the task's stored time, room for the run and its save, vx
gives the download up and runs the task here. It uploads nothing: the
remote already holds the key. A remote that says neither is awaited, as
before. With 500 tasks 30 ms away at 4 MB/s per
connection, 20 of them 8 MB, a run went
from 3,070 ms to 1,807 ms (min of 5 runs, before and after the
change).
The run's footer now says how many bytes each remote direction moved,
and --dry says what restoring the remote hits would download:
4 task(s) planned, 2 cache hits (1 local, 1 remote, 12 MB), 1 would run, 1 no-cache.Other noteworthy changes
- A local hit copies its stored files out without checking their size,
mtime or bytes first, and a save no longer reads its outputs back to
write a checksum. The local store is vx's own, so the check caught
nothing. A remote hit is still checked against its archive's checksum
when it is unpacked.
Breaking changes
cache.store.verifyandVX_CACHE_STORE_VERIFYare removed: delete
them from.vx/workspace.tsand the environment.- Scoped task keys are removed: task keys are plain on every remote.
- The
x-vx-cache-scopeheader (turboCache(),nxCache()) is
removed;turboCache()sendsx-artifact-read-scopeson reads. VX_CACHE_SCOPE,github({ cacheScope })andgitlab({ cacheScope })
now scope only plugin entries (ctx.cache, run records).vx initin a repo with only apackage.jsonwrites one empty root
project and no longer maps scripts: runbunx @vzn/vx-migratefor
that.- Plugin API: a remote cache layer's methods take no
RemoteKey, and
RemoteKeyis removed.hasresolvesArtifactInfoornull, not a
boolean;hasManyresolves aMapof the held keys toArtifactInfo,
not aSet.
See also Upgrading.
How to update
vx upgrade