* chore(release): 11.28.7, pacquet 12.15.0, pnpr 0.1.0-alpha.16
* docs(release): curate 11.28.7, pacquet 12.15.0, and pnpr 0.1.0-alpha.16 release notes
Add lead paragraphs and group the patch entries by what the reader was
doing, with security fixes first on each page.
- v11: lead with the registry metadata name check, pinned pnpm
trustPolicy check, maxTarballUnpackedSize, and the removal of registry
revisions; merge overlapping entries for minimumReleaseAge metadata
revalidation, frozen-lockfile directory dependency checks,
syncInjectedDepsAfterScripts, verifyDepsBeforeRun, pnpm sbom, and
unreadable config settings.
- v12: order minor highlights from config includes and
lockfile.integrityTarget down to interactive update styling; drop the
pnpr-only distribution note from the CLI changelog; merge overlapping
entries for workspace and pnpr install speedups, minimumReleaseAge and
If-Modified-Since revalidation, frozen-lockfile and injected package
checks, verifyDepsBeforeRun, pnpm prune, pnpm pack, pnpm licenses
list, pnpm self-update, pinned pnpm flag forwarding, and WebContainer
fixes.
- pnpr: lead the minor section with the breaking ecosystem URL prefix,
hosted storage layout, artifacts.orgs, and strict config schema
changes; fold dist.pnpr tarball metadata into one entry and drop the
redundant /metrics note; lead the patch section with reserved-username
and auth security fixes.
- Use one issue-link label style across the release pages.
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
The hosted store shared one key space between packages, orgs and blobs:
a registry without an org stored packages at the store root, an org's
registry stored them in `<org>/`, a package's blobs sat beside its
document, and a nested image repository sat inside its parent's
directory. So an org collided with an unscoped package of the same name
(an unpublish of that package removed the org's whole namespace), the
implicit `<ecosystem>~<name>` org of a grouped registry was a valid npm
name, and OCI GC and verify needed ad-hoc exclusion lists. On S3,
object_store percent-encodes `~` in keys while the upload sweep compared
raw prefixes, so grouped OCI registries were never swept. This is part
of section A4 of pnpm/tasks#131.
The new layout (pnpr_storage::layout), the same on disk and in a bucket:
layout.json {"layout": 1}
default/packages/<name>/document.json
default/packages/<name>/blobs/<file>
orgs/<org>/packages/...
Every name, org and file name is one segment: `[a-z0-9._-]` as is,
every other byte as `!` and two hex digits. That keeps nested names
siblings, separates names that differ only in case on case-insensitive
filesystems, and leaves nothing for object_store to escape, so a key is
byte for byte the local path. Per-namespace records stay inside their
namespace; records every namespace shares stay at the root. Listing is
one directory read, so the `.package-index` workaround is gone, and the
blob inventory reports package and blob names instead of paths.
Startup refuses a store marked with another layout or an unmarked store
holding data, and marks an empty one. The proxy cache uses the same
package layout and is emptied once when its marker is missing.
`pnpr upgrade-storage` converts an earlier store on disk or in a bucket,
telling org directories from packages by the configured orgs; it moves
blobs before documents so an interrupted run can resume, and refuses a
directory that is both an org and a package. export, verify and
migrate-storage check the layout, and migrate-storage marks its target.
The registry fixtures the pnpm test suites serve are built in the new
layout, and the cached build is keyed by the layout version.
pnpr served npm at the server root when npm was the only configured
ecosystem and moved it under /npm/ as soon as a second ecosystem was
added. Adding an ecosystem therefore broke every .npmrc registry URL,
every tarball URL already written into a lockfile, named-registry URLs,
and OIDC workload publish paths, and /npm meant the package `npm` on one
server and the ecosystem prefix on another. This settles section A1 of
pnpm/tasks#131: every ecosystem is always prefixed.
- Ecosystem::base_path is now independent of the configuration. The
per-configuration Registries::base_path and is_only_ecosystem are gone,
and the routes, the resolver's tarball URLs, OIDC workload paths and
pnpr's own-origin route classification all use it.
- The default image registry still answers at /v2/ on the host root; an
image client cannot be pointed at a prefix. The registry directory keeps
its `prefixed` and `namedPrefixed` flags for the web UI.
- The read-only token allowlist matched the npm audit endpoints at the
root only, so read-only tokens were already refused for audits on
multi-ecosystem servers. It now matches them under the npm prefix.
- /metrics no longer switches between Prometheus metrics and the npm
package `metrics` on the Accept header; the package is /npm/metrics.
- The pnpm v11 and v12 test harnesses, the registry-mock crate and the
integrated benchmark address the fixture registry at /npm/ and keep the
server origin for the pnpr protocol endpoints. The benchmark asks each
revision mock's registry directory whether npm is prefixed, so it can
still compare against a pnpr revision from before this change.
* chore(release): 11.28.6, pacquet 12.14.0
* docs(release): curate 11.28.6 and pacquet 12.14.0 release notes
Add lead paragraphs and group the patch entries by what the reader was
doing, with security first on the v11 page.
- v11: lead with the NPM_ID_TOKEN audience check and the invalid file
name warning as security fixes; say the `pnpm setup` message was
printed, since v11 reports it as a warning.
- v12: merge the stdout and stderr broken-pipe entries and the two
optional-peer entries; say the Windows Rust toolchain change undoes
the MinGW fallback a MinGW-built pnpm used since 12.13.0; correct the
`browser` packing claim; drop the reference to another release line.
- Use one issue-link label style on both pages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): smooth two sentences in the 11.28.6 and 12.14.0 notes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): say sideEffectsCache.exclude covers the local and remote cache
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: give sideEffectsCache.exclude an example a cache key cannot cover
An environment variable such as JAVA_HOME could be added to the cache
key, so it does not justify excluding a package. Name the system
libraries a native addon links against instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(release): 11.28.5, pacquet 12.10.0
* docs(release): curate the 11.28.5 and 12.10.0 release notes
Add a lead paragraph to each page and group the patch entries under
subject headings, with the security fixes first.
- Merge the unpublish path-boundary fix into the unpublish entry, the
legacy metadata cache prune into the metadata cache entry, the two
binary size entries, and the two 64 MiB archive limits on the v11 page.
- Drop the manifest-utils saveType entry from the CLI page: the CLI
only passes saveType values derived from its own flags, so no CLI user
can reach the fixed path.
- Rewrite mechanism-only entries (PAX header validation, bundled
dependency symlinks, custom resolutions under name@version keys, proxy
setting validation) in terms of what the user sees.
- Use one link style for pnpm/pnpm issues.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(release): 11.28.4, pacquet 12.9.1
* docs(release): curate 11.28.4 and pacquet 12.9.1 release notes
Add a lead paragraph to both pages. Move the two credential-leak fixes
in 11.28.4 to the top and group the remaining 27 entries by what the
reader was doing. Merge entries that described one change: the two
INVALID_SETTING validations, the two metadata revalidation fixes, the
two hoisted filtered-install fixes, and, in pacquet 12.9.1, the two
[<since>] selector fixes. Order pacquet 12.9.1 so the `@pnpm/wasm` move,
which WebContainer users must act on, comes first.
Normalize issue links to the [#N] form and link the ETag fix to
pnpm/pnpm#16506.
Every fix was checked against the code released in 11.28.3 and
pacquet 12.9.0; none fixes a defect that never shipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): describe the frozen-lockfile fixes accurately in the 11.28.4 lead
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(release): 11.28.3
* docs(changelog): curate the 11.28.3 release notes
Merge the eleven entries about names such as `constructor` into one,
group the patch changes by what the reader was doing, and add a lead
paragraph.
Drop the zlib-rs entry: that change only touched Cargo.toml, and the
TypeScript CLI does not use the Rust engine. It belongs to the next
pacquet release.
Rewrite the store index entry for CLI users. `ReadOnlyStoreIndex` and
`ImmutableStoreIndex` are library API documented in the
`@pnpm/store.index` changelog.
Say what the store prune mark-phase fix changes for the user.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Add TypeScript ports of the perfectionist rules that the Rust workspace
enforces through dylint.toml to @pnpm/eslint-config, with the same limits,
and fix every finding that needs no refactor.
The size and shape rules (function length, cognitive complexity, nesting,
local bindings, file length) are enforced for packages that already meet
them. The packages that do not are listed in PENDING_SIZE_AND_SHAPE_REFACTOR
in eslint.config.mjs and are refactored in follow-up changes.
The custom rules mirror perfectionist's semantics rather than reusing
sonarjs or max-lines-per-function, so that one limit means the same thing
in both codebases: a closure is a level of the body that contains it, a
nested function declaration is measured on its own, and a test-framework
callback plays the role of a #[test] function.
Bugs found and fixed along the way:
- a registry error body cut at exactly 64 KiB lost its truncation marker
- removing a dependency could leave dangling .bin shims
- constructor/__proto__ names crashed the projects graph, were skipped by
the injected-deps syncer, and were dropped from writeWantedLockfile's
returned lockfile
The CI chunk runner learns to run the node:test suite of the ESLint
config package.
* chore(release): 11.28.1, pacquet 12.8.0, pnpr 0.1.0-alpha.14
* docs(release): park Rust changelogs and curate release notes
The release bump ran with pnpm 12.7.0, which since pnpm/pnpm#14934
writes the changelog of every private project to a committed
CHANGELOG.md. pacquet, `@pnpm/napi` and `@pnpm/pnpr` are private
in-repo but published, and release.yml and the publish-time changelog
composer both read their parked section. Move the three sections back
to .changeset/changelogs so the GitHub release bodies and the npm
tarball changelogs are not empty. The tooling follow-up is recorded
on pnpm/tasks#38.
Curate the pnpm 11.28.1, pnpm 12.8.0 and pnpr 0.1.0-alpha.14 pages:
add lead paragraphs, group patch entries by subject, merge entries
describing one change, drop internals no CLI user sees, and fix
"instead of" tails, implementation names and link placement. This
addresses both Qodo findings on the catalog entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Under `resolutionMode: time-based`, both stacks merge the time-based
cutoff (newest direct dependency publish date plus one hour) and the
`minimumReleaseAge` cutoff into one `publishedBy`, keeping the tighter.
The npm resolver uses that date to pick versions and also to flag
`minimumReleaseAge` violations, so a subdependency newer than only the
time-based cutoff was reported as immature. Strict installs failed with
ERR_PNPM_NO_MATURE_MATCHING_VERSION and loose installs added the version
to `minimumReleaseAgeExclude`.
Keep the merged cutoff for picking. Where the dependency tree collects
resolver-inline violations, check each `minimumReleaseAge` violation
again against the `minimumReleaseAge` cutoff and exclude alone. The
picking cutoff is never later than the `minimumReleaseAge` one, so the
recheck can only drop violations that the time-based cutoff produced.
A deeper alternative is to pass the resolver a separate detection
cutoff. That touches the resolve options and cache keys in both stacks,
so the recheck at the single collection point is the smaller change.
Closespnpm/pnpm#13569
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(release): 11.28.0, pacquet 12.7.0, pnpr 0.1.0-alpha.13
* docs(release): curate the 11.28.0 and 12.7.0 release pages
Group both pages under subject headings with a lead paragraph that
names the headline changes and the security fixes, and move the
security entries to the top of the patch section.
Merge entries that describe one change: the node shim version files,
ranged selectors without a package.json, SemVer build metadata,
completion injection, custom modulesDir command lookup,
list --only-projects, store status, npm_execpath, catalog and npm-alias
workspace edges, the macOS CA fallback, and the prepare/devPreinstall
skips.
Drop entries that describe no change a published version could show:
the test-only --no-optional entry on both pages, the exported
CreateNewStoreControllerOptions type, the publish availability-probe
fix for a flag first shipping in 12.7.0, and the executable-bit check
the Rust CLI never had wrong.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): describe the bin shim part of the modulesDir entry accurately
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`pnpm unpublish` sent every registry mutation without `npm-auth-type` and
turned any 401 into ERR_PNPM_UNAUTHORIZED, so an account with 2FA
enforced could never unpublish even though it was logged in: the registry
answered with an OTP challenge the command did not recognize.
Both stacks now run the packument PUT and every tarball/packument DELETE
through the shared OTP session: the first attempt carries a configured
`--otp` (under `npm-auth-type: legacy`), otherwise `npm-auth-type: web`
requests the web-based challenge; a 401 whose body carries
`authUrl`/`doneUrl` starts the browser flow, one mentioning the classic
"one-time pass" wording prompts for a code, and the obtained password is
reused by the remaining requests of the run. Any other 401 stays a plain
authentication failure, now including the registry's body.
The 401-body classification that `dist-tag` and `setDistTag` each carried
privately moves to the web-auth packages
(`SyntheticOtpError.fromUnauthorizedBody` in TypeScript,
`otp_challenge_from_unauthorized_body` in Rust) so all call sites share
it. The Rust unpublish command becomes generic over the web-auth host so
its unit tests can script the challenge flow against a mocked registry.
Closespnpm/pnpm#14464
A test's options object is the entire input to the subject under test, so a
key nothing reads does not fail: it quietly runs the default instead of the
case the test is named for. Both install helpers accepted anything — the
headless one took `opts?: any`, and the install one takes `opts?: T & {...}`,
where an unknown key is absorbed into the inferred `T`. That is how the
`registries` -> `registriesByScope` rename left seven suites pointed at the
wrong registry with a green type-check, and only CI to say so.
The headless helper now takes a `Partial<HeadlessOptions>`. Everything that
surfaced was real:
- Seven fields `HeadlessOptions` requires and reads — `configByUri`,
`globalVirtualStoreDir`, `pruneStore`, `sideEffectsCacheRead`/`Write`,
`userAgent`, `virtualStoreDirMaxLength` — were never set, so every headless
test ran with them `undefined`. They now carry the values the install
behaved as.
- `verifyStoreIntegrity` is a package-store option, not a headless one. The
three tests that "disable" it were setting a key nobody read; it is now
forwarded to the store.
- `hoistPattern: '*'` and `publicHoistPattern: '*'` are `string[]`. A
one-character string iterates like a one-element array, which is the only
reason they worked.
- `development`, `optional`, `production` predate `include`, which the same
calls already set, and `sideEffectsCache` predates the read/write split.
Constraining the install helper's `T` is a bigger job — 162 errors, mostly
unrelated to options keys — so it keeps its generic and gains a narrow guard
instead: the three renamed keys are declared with a literal type that names
the replacement. It caught one more live case on the way in.
Registries do not all lay out tarball URLs the way the npm registry does.
JFrog Artifactory repeats the scope in a scoped package's tarball filename
(`@acme/widget/-/@acme/widget-1.0.0.tgz`) where npm strips it. pnpm cannot
rebuild such a URL, so it writes it out for every scoped package instead of
omitting it, and the lockfile carries a host-specific URL per dependency.
pnpm had no place to record such a fact, because it had no place to
describe a registry at all — only three ways to name one. `registries`
mapped a scope to a URL, `namedRegistries` mapped a bare-specifier prefix
to a URL, and neither could carry anything else.
`registries` now declares a registry once, keyed by its URL, with every
fact about it in the entry: a `serverType`, the `scopes` routed to it,
and the `prefix` it answers to. `serverType` has three states:
undeclared strict; only the exact canonical URL is reconstructible
npm also serves the percent-encoded scoped path
artifactory repeats the scope in the tarball filename
registry.npmjs.org resolves to `npm` as a built-in, so its behavior is
unchanged and the old hostname check becomes that one default rather than a
special case in the predicate. `npm` cannot be the default: asserting
npmjs-compatibility is a claim only the operator can make.
The URL is the key because every fact in an entry is a fact about that
server. Keying the layout by scope would bind it to whoever the scope
currently points at, so two developers whose scope resolves differently
would write lockfiles that disagree about which URLs may be omitted.
`scopes` and `prefix` are routes to the registry and are inverted at
config-read time into the two lookups the rest of pnpm already queries,
leaving the resolver, installer, and lockfile layers untouched and the
precedence chain (builtin < .npmrc < yaml < `_auth` < CLI) unchanged.
The layout is declared, never inferred. Sniffing the registry URL cannot work:
a virtual repository serves both layouts at once, depending on whether each
package was synced from upstream or published locally, so no registry-level
signal — route, response header, or probe — decides it. Declaring it also
keeps a wrong guess a fixable misconfiguration instead of a silent breakage.
`serverType` feeds a single URL builder that both sides of the lockfile use:
the writer omits a tarball URL only when the builder reproduces it, and the
reader rebuilds it with the same call. They therefore agree by construction,
so pnpm never has to assume a registry serves some second URL as well.
The setting lives in pnpm-workspace.yaml rather than .npmrc because the
lockfile depends on it: one developer omitting URLs that another reconstructs
differently would break a frozen install. A `serverType` in the global
config.yaml is ignored for the same reason, while the routes declared
alongside it are kept. Credentials are rejected there — the file is
committed — and still belong in .npmrc. The registry URL is the map key, so
the request-destination env gate applies to keys as well as values.
Credentials and unknown fields are refused after parsing, since a parse
error renders the offending source line verbatim.
A map whose values are all strings is the older `<scope>: <url>` shape and
is still read as one. Mixing the two shapes in one map is refused, and so is
a URL-keyed entry written as a string. `namedRegistries` is deprecated in
favor of `prefix` and is read only for prefixes `registries` does not
declare; a prefix stays singular because it is the registry's identity in a
lockfile dep path.
An entry that routes nothing to itself and matches no configured registry is
reported as a warning rather than silently ignored; it is a warning and not
an error because a shared config dependency can legitimately describe
registries a given project does not use.
Config dependencies and pnpr-server-mode resolution pass no server type; in
both, the writer and the reader share that default, so they stay consistent.
Closespnpm/get-npm-tarball-url#16. Supersedes pnpm/pnpm#13920.
Remove the legacy repository changelog files now that release changelog storage defaults to the registry. The publish path composes and injects CHANGELOG.md into release tarballs, so keeping historical copies in source control duplicates generated release data.
Update adm-zip to the patched 0.6 release and override vulnerable transitive versions after the dependency audit began rejecting versions below 0.6.0.
`pacquet add <name>` without a version and `pacquet update --latest`
fetched the raw `latest` dist-tag, so with an active
`minimumReleaseAge` they could write a range into `package.json` that
the follow-up install rejects (related to pnpm/pnpm#11165).
Resolve the tag through the same package-picking path as install. The
maturity filter repoints `latest` to the newest mature version, keeping
the manifest and lockfile consistent and matching the TypeScript CLI.
Share one lazily constructed `LatestPicker` across every selector in a
command. This preserves command-validation and unmatched-selector error
ordering while reusing the policy, metadata cache, fetch locker, and
registries map. Report invalid `minimumReleaseAgeExclude` values with
`ERR_PNPM_INVALID_MINIMUM_RELEASE_AGE_EXCLUDE`, matching install and the
TypeScript CLI.
Add TypeScript and Rust regression coverage for bare update, update
with `--latest`, and add without a version.
---------
Co-authored-by: Manuel Pelloni <manuel.pelloni@m4ss.net>
* fix(pnpr): route the registry mock by exact name and restore its write ACL
The full-purity registry-mock config (pnpm/pnpm#12747) broke the TypeScript
test suite in ways TS CI never caught (it was path-filter-skipped on that
pnpr-only merge):
- The @zkochan/* and @pnpm/* routes claimed those entire REAL npm scopes
with no fall-through, 404ing real packages that proxied dependency trees
need (@zkochan/async-regex-replace, @pnpm/error). The fixture packages in
those scopes are now routed individually; the rest of each scope proxies
npm again.
- Unscoped names tests publish to the mock (test-publish-*, batch-*,
project-100, ...) routed to the npmjs upstream, where a write is
rejected. They are enumerated exactly; @pnpmtest/* covers
dynamically-suffixed publish tests. Deliberately no unscoped prefix
wildcards: a test-* route would swallow real packages like test-exclude
(istanbul's dependency tree).
- The migration dropped the '**' ACL entry, and the built-in default
admits no one to unpublish, so unpublish tests got 403. Restored:
$all access, $authenticated publish and unpublish.
* test(pnpm11): stop dist-tagging and publishing over real npm packages
Under the mounts model a write to an upstream-routed name is rejected, and
the old materialize-on-write overlay is gone on purpose — so tests may only
write to packages the mock hosts. Migrate every real-npm write target to a
dedicated fixture:
- @pnpm.e2e/multi-version-{a,b,c} replace is-negative/is-positive/micromatch
in the update, overwrite, and interactive-update tests.
- @pnpm.e2e/circular-{iterator,ext,symbol} replace the
es6-iterator/es5-ext/es6-symbol circular trio; circular-ext requires
^2.0.1 so both circular-iterator versions land in the tree, which is the
point of the concurrency test.
- @pnpm.e2e/function-with-clone replaces lodash where the test executes the
installed code (module and module.clone are functions).
- @scoped/exports-function replaces @rstacruz/tap-spec in the scoped
devDependencies-save test.
- @pnpm.e2e/has-build-metadata{,-dep} replace @monorepolint/{core,cli}: the
dependency range carries build metadata (^0.5.0-alpha.51+f10fea0), which
is what pnpm/pnpm#2928 is about; the hardcoded real-npm integrity becomes
getIntegrity().
- The search tests query a hosted fixture (search scans hosted stores only).
- Dynamically-suffixed publish names move into the @pnpmtest scope, since
exact routes cannot cover generated names.
- The vestigial addDistTag('foo') calls in the workspace-protocol tests are
dropped; those resolve via workspace:, never the registry.
Read-only usages of real npm packages are untouched — they keep proxying.
getIntegrity() in the registry-mock helper also learns the proxy cache's
post-mounts layout (.pnpr-cache/~public/<digest>/), which the patch tests
depend on for proxied is-positive.
* fix(registry-mock): re-enumerate proxy-cache namespaces on every getIntegrity retry
The ~public namespace directory is created lazily together with the first
cached packument, so a candidate list built once before the retry loop could
never discover a namespace that appears while the retries are running.
* fix(pnpr): align Config::proxy routing with the bundled registry-mock config
Route the @pnpm and @zkochan fixture packages by exact name in
REGISTRY_MOCK_LOCAL_PATTERNS too, so pacquet's in-process test registry
proxies the rest of those real npm scopes exactly like the bundled
config.yaml does. Also filter the getIntegrity() proxy-cache namespace
enumeration to directories, so a stray file under ~public/ cannot turn a
retryable miss into an ENOTDIR error.
pnpr no longer accepts HTTP Basic (`_auth`) on requests, so test helpers
that authenticated with Basic credentials started returning 401 once CI
ran against a bearer-only pnpr build.
Switch the registry-mock `addDistTag` helper and the
publish/deprecate/dist-tag/unpublish suites to the bearer token that the
with-registry globalSetup already mints (`REGISTRY_MOCK_TOKEN`), exposed
through a new `getRegistryMockToken()` helper.
The two install/auth.ts tests that cover pnpm's own Basic `_auth` client
support now run against a small local registry proxy that enforces Basic
auth and forwards to pnpr with a bearer token, so that coverage is kept.
The TypeScript pnpm CLI freezes at v11; pnpm 12 will be the Rust pacquet
port. To make that split legible, all TypeScript source, test, and build
directories move under a new top-level pnpm11/ directory. The name states
the version boundary rather than implying a behavioral fork, since the two
stacks are meant to behave identically.
Scope is source-only: the shared workspace root stays at the repo root.
pnpm-workspace.yaml, package.json, pnpm-lock.yaml, .pnpmfile.cjs,
.meta-updater, __patches__, .changeset, .husky, and the lint/spell configs
remain in place, so one pnpm workspace and one Cargo workspace still span
all three products. pnpr/client and pacquet/tasks/registry-mock stay as
cross-product workspace members.
Rewiring the move required:
- pnpm-workspace.yaml globs prefixed with pnpm11/
- root package.json script paths, eslint.config.mjs, tsconfig.lint.json,
.gitignore, and CODEOWNERS updated
- .meta-updater/src/index.ts literals repointed (pnpm11/pnpm/package.json,
pnpm11/__utils__, pnpm11/__typings__, and the main package directory)
- regenerated every moved package's repository/homepage URL via meta-updater
- pnpm11/pnpm/bundle-deps.ts and __utils__/scripts/src/typecheck-only.ts
climb one more level to reach the repo root
.meta-updater stays at the repo root because @pnpm/meta-updater resolves
its config at <cwd>/.meta-updater/main.mjs.
TS CI (.github/workflows/ci.yml) now only runs when pnpm11/-relevant paths
change, via a dorny/paths-filter changes job plus a TS CI / Success
aggregate gate; branch protection should require only that gate.