Run the browser sandbox¶
The wasm sandbox is the proof that the core runs in a browser: nexus-raw-core compiled to wasm32-unknown-unknown, listing a raw Nexus directory and uploading files from a page.
The same protocol code answers as on the command line: the transport issues the search requests, the pagination walks the continuation tokens, and the .sha256 markers arrive and are hidden by the client.
What stays native is the filesystem-bound slice: up, down, clone and the rest that touch a local directory. The in-memory PUT is not a file operation, so nxr_put carries it to the browser.
The code lives in examples/wasm-sandbox/, a standalone crate like the other examples.
Its README carries the full detail.
This page is the tour.
Run it locally¶
The first build needs two tools:
Then open http://localhost:8134/: the page lists /repository/demo/ on load, the fake Nexus that ships with the sandbox server.
just wasm-smoke builds the same two steps and runs the smoke, which is what CI runs.
Point it at a real Nexus¶
The fake's repository is named demo.
A real one knows nothing about it.
Open the page with your repository: http://localhost:8134/?repo=<name>.
The sandbox server becomes a guarded same-origin proxy.
A real Nexus sends no CORS headers, so the browser cannot call it directly, and the proxy owns that hop: it forwards GET, HEAD and PUT for /repository/* and /service/rest/*, and dials the --upstream host and nothing else.
The guards default to the strict end:
| Flag | Default | Meaning |
|---|---|---|
--allow-host HOST |
empty | lets a request name HOST in its Host header, repeatable |
--rate-limit N |
60 | proxied requests per 10 seconds per client, then 429 with Retry-After |
--max-response-bytes N |
8388608 | cuts an upstream answer off at the cap with 502 |
--max-request-bytes N |
104857600 | caps a proxied PUT body, then 413 |
A forward-proxy request (curl --proxy ...) answers 403: the proxy is a facade for the page, not a relay.
A 400 or 404 on the listing means the upstream has no searchable repository under that name, or it is not raw.
The page says so in its error block.
Upload¶
The page's upload form (or a drop on the listing) calls nxr_put: the bytes are PUT first, then the .sha256 marker, the same order and shape as nxr put.
The fake stores both and the search lists them, so the client hides the marker and the new name appears after the refresh.
With --upstream, the proxy forwards the PUT body and the Authorization header to the real Nexus.
Static hosting, no backend¶
The fake Nexus ships with two faces over one module: serve.mjs imports it for the Node fake, and a ServiceWorker serves the same answers from the browser.
On a static host there is no Node process, so the page registers the worker instead, and the worker intercepts /repository/* and /service/rest/* with the same data: same pagination loop, same 404 arm, markers served so the client can hide them.
A directory of static files is the whole demo, which is what makes it landable on a docs site.
Three constraints apply:
- The page must be served over
https://or fromlocalhost: a ServiceWorker needs a secure context. - The sandbox must sit at the origin root. The URL grammar of the wire protocol is origin-absolute, so the search endpoint always resolves against the bare origin, outside any deployment prefix and outside a worker scoped to one.
- The worker registers only where no sandbox server marks the page, so it never shadows the Node fake or the proxy.
What CI watches¶
The wasm job builds the crate for wasm32, regenerates the wasm-bindgen glue at the locked version and runs the smoke.
The smoke drives the fake module, then the built wasm under plain node (a full listing, one injected failure retried on the way, an upload re-listed with its digest), then the page in a headless browser against a backend-free static server, where the only path to a listing is the ServiceWorker.
The browser run opens ?smoke=interact: the page clicks a folder, goes up and uploads a synthetic file through the form, and the final beacon must say interact = "ok".
A break in the read surface or in the page's navigation and upload fails the build, not a browser console.