Skip to content

Commit 2cd9b64

Browse files
committed
The loader merged: say "in Node", and name the release it ships in
nodejs/node#65748, the --vfs-mount / --vfs-load flags and registerProvider, merged on 17 September — one day after v26.9.0 was cut. v26.9.0 itself shipped three of the others: the ZipProvider (#64915), native addons from a mount (#65680) and SEA assets behind a VFS mount (#65675). So every piece is in Node, all but one released, and that one ships in the next 26.x. "The next 26.x" rather than a version number on purpose. A new CLI flag is normally semver-minor, and minor changes do not go into patch releases, so this may well be 26.10.0 rather than 26.9.1; there is no release proposal yet to settle it, and wording that is right either way is worth more than a number that may need correcting. README: the header note, the requirements table (with rows for "useVfs" and for "vfsArchive", #65810, which is still open and needed by `bundle sea` only), the prose around it, and the development note. HISTORY: the three additions, the section headings, the addon and SEA passages, and why the release workflow still ships disabled — now a wait of one release rather than an open PR. The workflow header and the example's requirements say the same. The deck's status slide gets back the headline its own checklist said to restore once the flags landed, "This is in Node.", with version tags on the released rows and "next 26.x" on the one that is not. The speaker notes stop warning against saying "landed" and start being precise about merged versus released instead; the title slide's tense note says what to open with before that release exists.
1 parent 3d5c9ed commit 2cd9b64

6 files changed

Lines changed: 101 additions & 88 deletions

File tree

‎.github/workflows/release.yml.disabled‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
## THIS WORKFLOW CANNOT RUN YET. It is here to be read, not to fire.
33
## =============================================================================
44
##
5-
## Everything below depends on a node no released line carries yet: `node:vfs` and
6-
## the ZIP support in `node:zlib` are released and `ZipProvider` is merged, but the
7-
## `--vfs-mount` / `--vfs-load` loader is still an open pull request (see HISTORY.md,
8-
## "What changed in node").
5+
## Everything below depends on a node no released line carries yet: all of it is
6+
## in node, most of it released by v26.9.0, but the `--vfs-mount` / `--vfs-load`
7+
## loader merged the day after v26.9.0 was cut and ships in the next 26.x release
8+
## (see HISTORY.md, "What changed in node"). One release from now, this can run.
99
## There is no `node-version` GitHub Actions can install that would make this pass,
1010
## so shipping it live would produce a permanently red workflow and a repository
1111
## that looks broken.
@@ -91,8 +91,9 @@
9191
# persist-credentials: false
9292
#
9393
# # The archive format needs node:vfs and the --vfs-mount / --vfs-load loader,
94-
# # so a released node will not do until that work lands upstream. This is the one
95-
# # thing standing between this workflow and being able to run at all.
94+
# # which is merged but first released in the next 26.x. Set
95+
# # BUNDLE_NODE_VERSION to that release once it exists: it is the one thing
96+
# # standing between this workflow and being able to run at all.
9697
# - name: Set up node
9798
# uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
9899
# with:

‎HISTORY.md‎

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,21 @@ that runs on any installed Node, or as a fully self-contained native executable
6868
no Node at all.
6969

7070
It is driven by Node.js itself, in three additions on top of Node's existing experimental
71-
**virtual file system** (`node:vfs`, by Matteo Collina). The first has landed since this was
72-
written; the other two are one open pull request, so running any of this still means a Node
73-
built from `main` with that applied:
71+
**virtual file system** (`node:vfs`, by Matteo Collina). All three have landed since this was
72+
written — two released, the third merged and due in the next 26.x release:
7473

75-
1. **ZIP archive support in `node:zlib`** — merged as
74+
1. **ZIP archive support in `node:zlib`** —
7675
[nodejs/node#64339](https://github.com/nodejs/node/pull/64339), released in **v26.8.0** —
77-
plus a **`ZipProvider`** that mounts such an archive through VFS as a file tree, merged as
78-
[nodejs/node#64915](https://github.com/nodejs/node/pull/64915) and due in the next release.
76+
plus a **`ZipProvider`** that mounts such an archive through VFS as a file tree,
77+
[nodejs/node#64915](https://github.com/nodejs/node/pull/64915), released in **v26.9.0**.
7978
2. A **`--vfs-mount` / `--vfs-load` module loader** that mounts directories and archives
8079
and resolves a program's entry point and all its `require()`/`import` against them —
81-
open as [nodejs/node#65748](https://github.com/nodejs/node/pull/65748).
80+
[nodejs/node#65748](https://github.com/nodejs/node/pull/65748), merged on 17 September,
81+
the day after v26.9.0 was cut, so it ships in the next 26.x release.
8282
3. **`vfs.registerProvider()`**, the extension point that lets a preloaded module
8383
decide which provider backs a mount — which is what makes a *verifying* mount, or a
84-
*recording* one, possible from userland at all. It ships in the same pull request as the
85-
flags, and is the reason that one is the piece nothing here runs without.
84+
*recording* one, possible from userland at all. It came in the same pull request as the
85+
flags, which is why that one was the piece nothing here could run without.
8686

8787
Together they let the root a program runs from be a plain `.zip` embedded inside the
8888
program's own file. Combined with Node's newer **Single Executable Application (SEA)**
@@ -127,14 +127,14 @@ one lives:
127127
below only because it's the foundation everything else stands on.
128128
- **The novel work is two additions to Node:**
129129
- **ZIP archive support in `node:zlib`** ([nodejs/node#64339](https://github.com/nodejs/node/pull/64339),
130-
merged, in v26.8.0) and the **`ZipProvider`** that mounts an archive through VFS
131-
([nodejs/node#64915](https://github.com/nodejs/node/pull/64915), merged).
130+
released in v26.8.0) and the **`ZipProvider`** that mounts an archive through VFS
131+
([nodejs/node#64915](https://github.com/nodejs/node/pull/64915), released in v26.9.0).
132132
- The **`--vfs-mount` / `--vfs-load` module loader** that makes a mounted tree the thing a
133133
program actually resolves and runs from, and the provider registry that decides what
134-
backs a mount — open as
135-
[nodejs/node#65748](https://github.com/nodejs/node/pull/65748). Loading a **native addon**
136-
out of a mount was a separate pull request,
137-
[nodejs/node#65680](https://github.com/nodejs/node/pull/65680), merged on 4 September.
134+
backs a mount — [nodejs/node#65748](https://github.com/nodejs/node/pull/65748), merged on
135+
17 September and due in the next 26.x release. Loading a **native addon** out of a mount
136+
was a separate pull request, [nodejs/node#65680](https://github.com/nodejs/node/pull/65680),
137+
released in v26.9.0.
138138
- **The SEA group** is recent upstream Node functionality the experiment leans on, carried
139139
along so the whole pipeline works from one binary.
140140

@@ -175,15 +175,15 @@ Two details make the whole single-file trick possible:
175175
- Read paths enforce content-size limits and reject malformed records (zip-bomb / corrupt
176176
input guards), with dedicated `ERR_ZIP_*` codes.
177177

178-
### 2. `ZipProvider` — a VFS provider backed by a ZIP archive *([nodejs/node#64915](https://github.com/nodejs/node/pull/64915) — merged)*
178+
### 2. `ZipProvider` — a VFS provider backed by a ZIP archive *([nodejs/node#64915](https://github.com/nodejs/node/pull/64915) — released in v26.9.0)*
179179

180180
The bridge between the two: a provider for Matteo's `node:vfs` that exposes the entries of
181181
a `ZipFile` (on disk) or `ZipBuffer` (in memory) as a browsable, read/write file tree.
182182
Directories are recognized both explicitly and implicitly; a file opened for write commits
183183
as a new archive entry when its handle is closed. This is what lets a `.zip` be *mounted*
184184
and treated like a directory.
185185

186-
### 3. `--vfs-mount` / `--vfs-load` startup flags — the keystone *([nodejs/node#65748](https://github.com/nodejs/node/pull/65748) — open)*
186+
### 3. `--vfs-mount` / `--vfs-load` startup flags — the keystone *([nodejs/node#65748](https://github.com/nodejs/node/pull/65748) — merged, in the next 26.x release)*
187187

188188
This is what wires VFS into Node's *startup and module resolution* so a mounted tree
189189
becomes the thing the program actually runs from. Mounting and running stay separate
@@ -230,7 +230,7 @@ several mounts and still have exactly one entry point:
230230
not load: the same sources are mounted in the same order, so the reserved paths line up,
231231
and the worker runs its own entry point.
232232
- **Native addons** were a separate pull request,
233-
[nodejs/node#65680](https://github.com/nodejs/node/pull/65680), merged on 4 September. The
233+
[nodejs/node#65680](https://github.com/nodejs/node/pull/65680), released in v26.9.0. The
234234
reason they needed one is that
235235
`dlopen()`/`LoadLibrary()` open a shared object *by path* and a VFS path has no inode to
236236
open. It reads the addon's bytes out of the mount and loads them from a private,
@@ -898,9 +898,10 @@ environment — one build, decided about later.
898898

899899
**The package rides inside as an archive node mounts for itself.** The stub runs before
900900
anything is mounted, so it cannot import this package the ordinary way. It no longer has to:
901-
`"useVfs": true` with `"vfsArchive"` ([nodejs/node#65675](https://github.com/nodejs/node/pull/65675),
902-
and the `vfsArchive` that followed it) embeds a ZIP in the executable and mounts it as the
903-
file system the main script runs from. The stub is injected at the root of that mount, so
901+
`"useVfs": true` ([nodejs/node#65675](https://github.com/nodejs/node/pull/65675), released in
902+
v26.9.0) with `"vfsArchive"` ([nodejs/node#65810](https://github.com/nodejs/node/pull/65810),
903+
still open) embeds a ZIP in the executable and mounts it as the file system the main script
904+
runs from. The stub is injected at the root of that mount, so
904905
requiring the launcher is a relative path and nothing else.
905906

906907
That replaced the userland version of the same idea: the verifier bundle as a raw SEA asset,
@@ -1154,7 +1155,8 @@ its attestation from it. Two attestations over one artifact, from one identity:
11541155
the registry copy, and this project's over the bytes inside it.
11551156

11561157
> **It cannot run yet.** Every step depends on the `--vfs-mount` / `--vfs-load` work, which
1157-
> is still an open pull request, so there is no `node-version` that would make it pass. The
1158+
> is merged but not yet in a release, so there is no `node-version` that would make it pass
1159+
> until the next 26.x ships. The
11581160
> file is disabled two ways over — it does not end in `.yml`, so GitHub never parses it, and
11591161
> its body is commented out — and it carries the one-line command that turns it back into a
11601162
> live workflow. It is there to be read.
@@ -1876,11 +1878,12 @@ the right one for a release pipeline specifically — less obviously so for ordi
18761878

18771879
#### Why it ships disabled
18781880

1879-
None of this can run yet. `node:vfs` and the ZIP support in `node:zlib` are released and
1880-
`ZipProvider` is merged, but the `--vfs-mount` / `--vfs-load` loader is still open, so there
1881-
is no `node-version` GitHub Actions can install that would make the workflow pass, and
1882-
shipping it live would produce a permanently red workflow and a repository that looks
1883-
broken.
1881+
None of this can run yet. Everything it needs is in Node, and most of it is released —
1882+
but the `--vfs-mount` / `--vfs-load` loader merged the day after v26.9.0 was cut, so until
1883+
the next 26.x release there is no `node-version` GitHub Actions can install that would make
1884+
the workflow pass, and shipping it live would produce a permanently red workflow and a
1885+
repository that looks broken. That is a wait of one release, and the header carries the
1886+
command that ends it.
18841887

18851888
It is kept anyway, at `.github/workflows/release.yml.disabled`: the file does not end in
18861889
`.yml`, so GitHub never parses it, and the body is commented out on top of that. The header

‎README.md‎

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ filesystem, so an archive that does not check out never becomes one and its entr
1515
never runs. Every member is re-hashed against its signed digest as it is read, for the life
1616
of the process.
1717

18-
> **Requires a Node built from `main`, with one open pull request applied.** `node:vfs` and
19-
> the ZIP support in `node:zlib` are released, and `ZipProvider` is merged and should be in
20-
> the next release; the `--vfs-mount` / `--vfs-load` loader — and with it
21-
> `vfs.registerProvider()` — is still open, and is the piece nothing here runs without. See
22-
> [Requirements](#requirements). Everything here is experimental.
18+
> **Requires the next Node 26 release.** Everything this needs is in Node: most of it is
19+
> released, through v26.9.0, and the `--vfs-mount` / `--vfs-load` loader — the piece nothing
20+
> here runs without — merged on 17 September, the day after v26.9.0 shipped. Until the next
21+
> 26.x release, that means a Node built from `main`. See [Requirements](#requirements).
22+
> Everything here is experimental.
2323
2424
---
2525

@@ -403,10 +403,10 @@ From code, `createSeaBase()` and `buildSea()` split the expensive half (a ~155 M
403403
Node) from the cheap one, `@pipobscure/bundle/launch` is the entry point all of this runs
404404
through — `run()`, `runSelf()`, `verify()`, `main()` — and `verifySelf()` lets an application
405405
report on its own provenance. The package rides inside the executable as an archive that node
406-
mounts for itself: `"useVfs": true` with `"vfsArchive"`
407-
([nodejs/node#65675](https://github.com/nodejs/node/pull/65675) and the `vfsArchive` that
408-
followed it), which is why the generated stub is three lines and why there is no second copy
409-
of the verifier anywhere.
406+
mounts for itself: `"useVfs": true` ([nodejs/node#65675](https://github.com/nodejs/node/pull/65675),
407+
released in v26.9.0) with `"vfsArchive"` ([nodejs/node#65810](https://github.com/nodejs/node/pull/65810),
408+
still open), which is why the generated stub is a handful of lines and why there is no second
409+
copy of the verifier anywhere.
410410

411411
---
412412

@@ -490,21 +490,28 @@ Everything here sits on Node's experimental `node:vfs` (by Matteo Collina) and r
490490
|---|---|
491491
| **`node:vfs`**, and modules resolving and loading out of a mount | released, v26.4.0 |
492492
| **ZIP support in `node:zlib`** — `ZipFile`, `ZipBuffer`, `ZipEntry` | released, v26.8.0 |
493-
| **`ZipProvider`**, a VFS provider backed by such an archive | merged — [nodejs/node#64915](https://github.com/nodejs/node/pull/64915) |
494-
| **`--vfs-mount` / `--vfs-load`**, and `vfs.registerProvider()` | open — [nodejs/node#65748](https://github.com/nodejs/node/pull/65748) |
495-
| **Native addons loaded from a mount** | merged — [nodejs/node#65680](https://github.com/nodejs/node/pull/65680) |
496-
497-
A released Node already reads ZIP archives and already resolves modules out of a mount; the
498-
provider that turns one into the other is merged, so `main` today has everything a program
499-
needs to *be* an archive. What is still missing is the way to ask for that mount from outside
500-
the program, which is the whole hinge: **`--vfs-mount` / `--vfs-load`** make a mounted tree
501-
the thing a program resolves and runs from, and the same pull request brings
502-
`vfs.registerProvider()` — the extension point that lets a preload decide what backs a mount,
503-
and therefore the one that makes a *verifying* mount possible from userland at all. Until it
504-
lands, build Node from `main` with it applied; nothing in this package runs without it.
505-
506-
Native addons out of a mount landed on 4 September as
507-
[nodejs/node#65680](https://github.com/nodejs/node/pull/65680), which closes the last gap in
493+
| **`ZipProvider`**, a VFS provider backed by such an archive | released, v26.9.0 — [nodejs/node#64915](https://github.com/nodejs/node/pull/64915) |
494+
| **Native addons loaded from a mount** | released, v26.9.0 — [nodejs/node#65680](https://github.com/nodejs/node/pull/65680) |
495+
| **`"useVfs"`**, a SEA's assets behind a VFS mount | released, v26.9.0 — [nodejs/node#65675](https://github.com/nodejs/node/pull/65675) |
496+
| **`--vfs-mount` / `--vfs-load`**, and `vfs.registerProvider()` | merged 17 Sep, in the next 26.x release — [nodejs/node#65748](https://github.com/nodejs/node/pull/65748) |
497+
| **`"vfsArchive"`**, a ZIP as a SEA's file system — `bundle sea` only | open — [nodejs/node#65810](https://github.com/nodejs/node/pull/65810) |
498+
499+
v26.9.0 already has everything a program needs to *be* an archive: it reads ZIP archives,
500+
turns one into a file system, resolves modules out of it, and loads native addons from it. The
501+
one thing it lacks is the way to ask for that mount from *outside* the program, which is the
502+
whole hinge: **`--vfs-mount` / `--vfs-load`** make a mounted tree the thing a program resolves
503+
and runs from, and the same pull request brings `vfs.registerProvider()` — the extension point
504+
that lets a preload decide what backs a mount, and therefore the one that makes a *verifying*
505+
mount possible from userland at all. It merged on 17 September, one day after v26.9.0 was
506+
cut, so it ships in the next 26.x release. Until then, build Node from `main`.
507+
508+
[nodejs/node#65810](https://github.com/nodejs/node/pull/65810) is needed only to build an
509+
executable. It lets a SEA's file system *be* a ZIP archive rather than a list of assets, which
510+
is how this package gets inside one: `bundle sea` embeds the verifier bundle whole and node
511+
mounts it. It is still open; everything else here works without it.
512+
513+
Native addons out of a mount shipped in v26.9.0, as
514+
[nodejs/node#65680](https://github.com/nodejs/node/pull/65680), which closed the last gap in
508515
what a bundle can contain. A `dlopen()` needs a path with an inode behind it and a VFS path
509516
has none, so it reads the addon's bytes out of the mount and loads them from a private,
510517
self-cleaning image instead — an anonymous memfd on Linux, an unlinked temp file elsewhere.
@@ -526,9 +533,10 @@ npm test # 144 tests; generates a throwaway PKI into build/certs/
526533
npm run typecheck
527534
```
528535

529-
The suite needs a Node carrying the [requirements](#requirements); against a build of
530-
[nodejs/node#65748](https://github.com/nodejs/node/pull/65748) all 144 pass, launcher, mount
531-
and executable tests included.
536+
The suite needs a Node carrying the [requirements](#requirements) — today, one built from
537+
`main` with [nodejs/node#65810](https://github.com/nodejs/node/pull/65810) applied for the
538+
executable tests; from the next 26.x release, only that. Against such a build all 144 pass,
539+
launcher, mount and executable tests included.
532540

533541
Tests import the sources rather than the build, so they run under Node's type stripping. The
534542
test PKI is generated on demand by `tools/testpki.ts` and is **never committed** — a private
@@ -566,8 +574,8 @@ does to release itself is something you can do to your own project.
566574
[`.github/workflows/release.yml.disabled`](.github/workflows/release.yml.disabled) is the
567575
whole pipeline as a workflow — CI, pack, fetch the published release, audit the diff, gate,
568576
sign through sigstore with the workflow's OIDC identity, publish with npm provenance, every
569-
action pinned to a commit SHA. It is inert, because the Node it needs is not released yet; the
570-
header carries the command that makes it live.
577+
action pinned to a commit SHA. It is inert until the next 26.x release gives GitHub Actions a
578+
Node it can install; the header carries the command that makes it live.
571579

572580
---
573581

‎examples/static-server/README.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ enumeration page instead — every mounted source, in precedence order.
281281

282282
## Requirements
283283

284-
The same unreleased node the rest of this repository needs — `node:vfs`,
285-
`ZipProvider`, and the `--vfs-mount` / `--vfs-load` flags. See the root
286-
[README](../../README.md#requirements).
284+
The same Node the rest of this repository needs: one with the `--vfs-mount` /
285+
`--vfs-load` flags, which means the next 26.x release, or `main` until it ships.
286+
Everything else the server uses — `node:vfs`, `ZipProvider`, the ZIP support in
287+
`node:zlib` — is in v26.9.0 already. See the root [README](../../README.md#requirements).

0 commit comments

Comments
 (0)