The libsql auth backend classified a duplicate row only through SQLite
result codes. Turso's remote protocol reports it as a Hrana stream error
whose message carries the code name, so the counter seed on a second
start against the same database failed instead of being tolerated, and
pnpr exited at startup. A taken username reported the same way answered
500 instead of the login or name-taken path.
Parse the Hrana message the way the lock-conflict check already does.
Related to https://github.com/pnpm/tasks/issues/183.
* docs(pnpr): document reverse-proxy and TLS setup, webhooks, lifecycle, and pnprServer
Document production deployment and operational architecture for pnpr and
pnpm (Section C13 and Section F of https://github.com/pnpm/tasks/issues/131):
- Add Reverse proxy and TLS deployment guide (pnpr/docs/tls-and-reverse-proxy.md)
with architecture rationale and configuration recipes for Nginx, Caddy,
Traefik, and AWS ALB.
- Add Webhooks and event notifications guide (pnpr/docs/webhooks.md)
documenting the decoupled event architecture, structured audit logs
(pnpr::audit), and object storage bucket notifications.
- Document signals, readiness probe state transitions, process lifecycle, and
standard exit codes in pnpr/docs/cli.md.
- Document S3 commit journal lifecycle, multi-replica considerations, and
disaster recovery caveats in pnpr/docs/storage.md.
- Document the pnprServer workspace setting reference in
pnpm/docs/settings/dependency-resolution.md and pnpm11/docs/settings/dependency-resolution.md.
- Update sidebars and quick start navigation.
Related to https://github.com/pnpm/tasks/issues/131
* docs(pnpr): clarify pnprServer offloads resolution and streams package metadata
Clarify that pnprServer offloads dependency resolution rather than file
fetching: the server streams back resolved package metadata frames as it walks
the graph so the client can prefetch tarballs from registries in parallel.
* docs(pnpr): address review feedback on Vector remap and pnprServer tarball fetch boundary
- Add remap transform in Vector example in pnpr/docs/webhooks.md to parse
raw JSON from Docker container logs before filtering audit events.
- Clarify direct public tarball fetching and server-side private upstream
credential boundaries in pnpm/docs/settings/dependency-resolution.md and
pnpm11/docs/settings/dependency-resolution.md.
* docs(pnpr): correct probe endpoints, shutdown lifecycle, and log shippers
* docs(pnpr): correct S3 commit journal staging paths and write-ahead sequence
* docs(pnpr): clarify proxy hop coverage and orphan pruning scope
* docs(pnpr): distinguish X-Real-IP from hop traversal and document ALB target port restriction
Add maintenance subcommands and migration tooling for pnpr (Section C12 of
https://github.com/pnpm/tasks/issues/131):
- Implement `pnpr config check` (`pnpr config-check`) to validate configuration
and report diagnostic details on routes, upstreams, auth, storage, and surfaces.
- Implement `pnpr verify` to audit hosted package documents against storage
blobs, checking for missing files, corrupted checksums, and unreferenced orphans.
- Implement `pnpr export --out <dir>` to dump packages, documents, and blobs,
with optional `--include-auth` support.
- Implement `pnpr migrate-storage` to migrate hosted packages and blobs from local
filesystem storage to an S3-compatible object store.
- Support Apache/Verdaccio `{SHA}` format in `pnpr-auth`, automatically upgrading
authenticated users to bcrypt upon first login, and provide `pnpr import-htpasswd`.
- Add backup and disaster recovery documentation in `pnpr/docs/backup-and-restore.md`
and update CLI documentation.
Related to https://github.com/pnpm/tasks/issues/131
pnpr now serves its web UI at /-/ui/ from the same origin, so the UI
needs no CORS setup and no server URL. The UI ships as the separate
`@pnpm/pnpr-ui` package, an optional peer dependency of `@pnpm/pnpr`.
pnpr finds it next to its own package (npm and pnpm both link a resolved
peer beside the package that declares it), or reads it from `ui.dir`,
and `ui.enabled: false` turns it off.
- Serving: files from the UI directory, `index.html` for every other
path outside `assets/`, a 404 for a missing hashed asset. The page
gets a relative `<base>` so deep routes and path prefixes work without
an absolute Vite base. Responses carry a CSP that keeps scripts and
requests on this origin.
- The UI source stays on bit.cloud. `pnpr/ui` is a workspace of its own
that pins `@pnpm/pnpr.apps.pnpr-web` from bit.cloud's registry and
builds it into `pnpr/npm/pnpr-ui/dist`.
- Release: a `build-pnpr-ui` job builds the bundle. The verify and
publish jobs download it. The smoke test installs the UI beside the
wrapper and checks that pnpr serves it. `@pnpm/pnpr-ui` releases in a
fixed group with `@pnpm/pnpr`.
With `auth.scim.token`, pnpr serves the SCIM 2.0 `Users` endpoints and
discovery documents under `/-/pnpr/v0/scim/v2`, authenticated only by that
token.
An OIDC sign-in creates no account row and its session lives in one
replica's memory, so deleting an account is not enough to deprovision
anyone. The SCIM directory is therefore one record in the hosted store,
reloaded on the managed-state TTL like rosters and rules. Authentication
refuses any user identity the directory marks inactive, and so does the
npm login endpoint. Deactivating or deleting a user also revokes its
stored tokens, removes its password account, and drops this replica's
browser sessions for it.
A deleted user stays in the record as inactive and unlisted, so the
username keeps being refused until it is provisioned again. Provisioning
creates no password: the identity provider is the sign-in path.
Follow-up of pnpm/tasks#111.