mirror of
https://github.com/pnpm/pnpm.git
synced 2026-06-28 09:55:39 -04:00
* chore(pnpr): license under PolyForm Shield 1.0.0 Relicense the pnpr/ subtree (the pnpm-compatible registry server) from MIT to the source-available PolyForm Shield License 1.0.0. The rest of the monorepo stays MIT. pnpr may be run, modified, and self-hosted for any purpose except providing a product that competes with it. - Add pnpr/LICENSE.md (PolyForm Shield 1.0.0). - Override the inherited workspace MIT in the pnpr crates via license-file. - Point the @pnpm/pnpr npm wrapper at the bundled LICENSE.md. - Note the carve-out in the root README (the root LICENSE stays pristine MIT so license detection keeps recognizing it). * chore(agent): license pnpm-agent under PolyForm Shield 1.0.0 Relicense the pnpm-agent server (agent/server) from MIT to the source-available PolyForm Shield License 1.0.0, matching pnpr. The @pnpm/agent.client package stays MIT so the agent protocol remains openly implementable. - Add agent/server/LICENSE.md (PolyForm Shield 1.0.0). - Set the package license to "SEE LICENSE IN LICENSE.md". - Exempt pnpm-agent from meta-updater's MIT normalization via a SOURCE_AVAILABLE_PKGS set, so lint:meta stays green. - Note the carve-out in the agent/server README + add a changeset. pnpm-agent is only a devDependency of the pnpm CLI, so no source- available code ships in the MIT-licensed CLI artifact. * docs(license): add contribution terms with relicensing grant for pnpr and pnpm-agent Contributions to the source-available trees (pnpr/, agent/server) are accepted under the same PolyForm Shield License plus a grant letting the licensor relicense them under other terms. This preserves the option to later relax to a more permissive source-available license or offer a separate commercial license without per-contributor consent. - Add pnpr/CONTRIBUTING.md and agent/server/CONTRIBUTING.md. - Point to them from each tree's README license section. * docs(license): add npm trademark/non-affiliation notice to pnpr and pnpm-agent State that pnpr and pnpm-agent are not affiliated with or endorsed by npm, Inc., GitHub, or Microsoft, and that "npm" is used only to describe registry-protocol compatibility. Also add a License section to the published @pnpm/pnpr npm wrapper README.
193 lines
5.6 KiB
Markdown
193 lines
5.6 KiB
Markdown
# pnpm-agent
|
|
|
|
A pnpm agent server that resolves dependencies server-side and streams only the files missing from the client's content-addressable store.
|
|
|
|
> **Status:** experimental. Versions are pre-1.0; the wire protocol may change between releases.
|
|
|
|
## How it works
|
|
|
|
1. Client sends `POST /v1/install` with dependencies, an optional existing lockfile, and the integrity hashes of packages already in its store.
|
|
2. Server resolves the full dependency tree using pnpm's own resolution engine.
|
|
3. Server computes which file digests the client is missing — at the individual file level, not just the package level.
|
|
4. Server streams an NDJSON response on `/v1/install` (`D`-lines for missing file digests, `I`-lines for pre-packed package index entries, a final `L`-line with the lockfile + stats, or an `E`-line on error).
|
|
5. The client then requests the missing file contents from `POST /v1/files`, which streams a gzip-compressed binary of packed file entries.
|
|
|
|
This eliminates sequential metadata round-trips (the server resolves in one shot) and avoids downloading files that already exist in the client's store from other packages.
|
|
|
|
## Starting the server
|
|
|
|
### Install from npm
|
|
|
|
```bash
|
|
pnpm add -g pnpm-agent
|
|
pnpm-agent
|
|
```
|
|
|
|
### Docker
|
|
|
|
A Dockerfile is provided at `agent/server/Dockerfile`. It is layered on top of [`ghcr.io/pnpm/pnpm`](https://github.com/pnpm/pnpm/pkgs/container/pnpm) and installs Node.js and `pnpm-agent` inside the image.
|
|
|
|
```bash
|
|
# Build the image locally
|
|
docker build -t pnpm-agent agent/server
|
|
|
|
# Run it, persisting the store + cache in ./agent-data
|
|
docker run --rm \
|
|
-p 4873:4873 \
|
|
-v "$(pwd)/agent-data:/agent-data" \
|
|
pnpm-agent
|
|
```
|
|
|
|
Override the defaults with `-e`, same variables as described below:
|
|
|
|
```bash
|
|
docker run --rm \
|
|
-p 4000:4000 \
|
|
-e PORT=4000 \
|
|
-e PNPM_AGENT_UPSTREAM=https://my-proxy.example.com/ \
|
|
-v "$(pwd)/agent-data:/agent-data" \
|
|
pnpm-agent
|
|
```
|
|
|
|
The image exposes port `4873` and declares a `/agent-data` volume; mount a host directory there if you want the resolved metadata, store index, and file store to survive container restarts.
|
|
|
|
### From source
|
|
|
|
```bash
|
|
# Build first
|
|
pnpm --filter pnpm-agent run compile
|
|
|
|
# Run with defaults (port 4873, upstream https://registry.npmjs.org/)
|
|
node lib/bin.js
|
|
|
|
# Or configure via environment variables
|
|
PORT=4000 \
|
|
PNPM_AGENT_STORE_DIR=./my-store \
|
|
PNPM_AGENT_CACHE_DIR=./my-cache \
|
|
PNPM_AGENT_UPSTREAM=https://registry.npmjs.org/ \
|
|
node lib/bin.js
|
|
```
|
|
|
|
### Environment variables
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `PORT` | `4873` | Port to listen on |
|
|
| `PNPM_AGENT_STORE_DIR` | `./store` | Directory for the server's content-addressable store |
|
|
| `PNPM_AGENT_CACHE_DIR` | `./cache` | Directory for package metadata cache |
|
|
| `PNPM_AGENT_UPSTREAM` | `https://registry.npmjs.org/` | Upstream npm registry to resolve from |
|
|
|
|
### Programmatic usage
|
|
|
|
```typescript
|
|
import { createRegistryServer } from 'pnpm-agent'
|
|
|
|
const server = await createRegistryServer({
|
|
storeDir: '/var/lib/pnpm-agent/store',
|
|
cacheDir: '/var/lib/pnpm-agent/cache',
|
|
registries: { default: 'https://registry.npmjs.org/' },
|
|
})
|
|
|
|
server.listen(4000, () => {
|
|
console.log('pnpm agent listening on port 4000')
|
|
})
|
|
```
|
|
|
|
## Quick start
|
|
|
|
Terminal 1 — start the server:
|
|
|
|
```bash
|
|
cd agent/server
|
|
pnpm run compile
|
|
node lib/bin.js
|
|
# pnpm agent server listening on http://localhost:4873
|
|
```
|
|
|
|
Terminal 2 — use it from any project:
|
|
|
|
```bash
|
|
cd my-project
|
|
```
|
|
|
|
Add to `pnpm-workspace.yaml`:
|
|
|
|
```yaml
|
|
agent: http://localhost:4873
|
|
```
|
|
|
|
Or pass `--config.agent=http://localhost:4873` on the command line.
|
|
|
|
Then run:
|
|
|
|
```bash
|
|
pnpm install
|
|
```
|
|
|
|
That's it. pnpm will resolve dependencies on the server, download only the files missing from your local store, and link `node_modules` as usual. Remove the `agent` setting to go back to normal behavior.
|
|
|
|
## API
|
|
|
|
### `POST /v1/install`
|
|
|
|
**Request body** (JSON):
|
|
|
|
```json
|
|
{
|
|
"projects": [
|
|
{
|
|
"dir": ".",
|
|
"dependencies": { "react": "^19.0.0" },
|
|
"devDependencies": { "typescript": "^5.0.0" }
|
|
}
|
|
],
|
|
"overrides": {},
|
|
"lockfile": null,
|
|
"storeIntegrities": ["sha512-abc...", "sha512-def..."]
|
|
}
|
|
```
|
|
|
|
**Response** (NDJSON, `Content-Type: application/x-ndjson`). Each line is one message:
|
|
|
|
- `D\t{digest}\t{size}\t{executable}` — file digest missing from the client's store.
|
|
- `I\t{integrity}\t{pkgId}\t{base64-msgpack}` — pre-packed package index entry.
|
|
- `L\t{json}` — final lockfile and stats. Emitted last on success.
|
|
- `E\t{json}` — error. Emitted if resolution fails.
|
|
|
|
### `POST /v1/files`
|
|
|
|
**Request body** (JSON):
|
|
|
|
```json
|
|
{ "digests": [{ "digest": "<hex>", "size": 123, "executable": false }] }
|
|
```
|
|
|
|
**Response** (gzip-compressed binary, `Content-Type: application/x-pnpm-install`):
|
|
|
|
```
|
|
[4 bytes: JSON metadata length]
|
|
[N bytes: JSON metadata]
|
|
[file entries: 64B digest + 4B size + 1B mode + content, repeated]
|
|
[64 zero bytes: end marker]
|
|
```
|
|
|
|
## License
|
|
|
|
Source-available under the [PolyForm Shield License 1.0.0](./LICENSE.md) —
|
|
**not** open source. You may run, modify, and self-host `pnpm-agent` for any
|
|
purpose except providing a product that competes with it (or with a product the
|
|
licensor provides using it). Commercial / non-compete licenses are available
|
|
from Zoltan Kochan (<https://kochan.io>).
|
|
|
|
The rest of the pnpm monorepo is MIT licensed; `pnpm-agent` and the `pnpr/`
|
|
registry server are the source-available exceptions.
|
|
|
|
Contributions to `agent/server/` are accepted under separate terms — see
|
|
[`CONTRIBUTING.md`](./CONTRIBUTING.md).
|
|
|
|
## Trademark notice
|
|
|
|
pnpm-agent is not affiliated with, endorsed by, or sponsored by npm, Inc.,
|
|
GitHub, or Microsoft. "npm" is a trademark of npm, Inc., used here only to
|
|
describe compatibility with the npm registry protocol.
|