Commit Graph

464 Commits

Author SHA1 Message Date
Zoltan Kochan
68a951006e test: update registry-mock to 6.0.0 stable and use pnpm view in tests (#11227)
* test: update registry-mock to 6.0.0 stable and use pnpm view in tests

Update @pnpm/registry-mock from 6.0.0-6 to 6.0.0 stable release.
Replace npm view with pnpm view in test helpers now that pnpm has
native view/dist-tag commands. Unskip the nodeRuntime test that was
blocked on the registry-mock republish.

* chore: update pnpm to beta 8

* feat: support versions, dist-tags, and time field selectors in pnpm view

The view command now exposes versions (as an array of version strings),
dist-tags, and time from registry metadata. Single-field --json output
returns the raw value instead of wrapping it in an object, matching npm
behavior. This allows tests to use pnpm view instead of npm view.
2026-04-08 15:14:53 +02:00
Zoltan Kochan
fb58648b00 test: update registry-mock to v6 and fix test fixtures (#11223)
- Update `@pnpm/registry-mock` from 5.2.4 to 6.0.0-6
- Fix auth tests to use bearer token from `globalSetup` instead of hardcoding credentials
- Replace hardcoded integrity checksums with `getIntegrity()` from registry-mock in `customResolvers` tests
- Add `prepareFixtureWithIntegrity()` helper in deps-restorer tests to dynamically patch `@pnpm.e2e` integrity values in fixture lockfiles at runtime, so they don't go stale when registry-mock is updated
- Fix `workspace-external-depends-deep` fixture's current lockfile (was missing `packages/f` and `packages/g` importers)
- Remove unnecessary credentials from `gitChecks` tests (they reject before any registry interaction)
2026-04-08 11:45:38 +02:00
Zoltan Kochan
853be661d8 feat: add native pnpm dist-tag command (#11218)
Implement dist-tag ls, add, and rm subcommands natively instead of
delegating to npm. Follows the same pattern as the recently added
deprecate and unpublish commands.
2026-04-07 10:22:03 +02:00
Zoltan Kochan
b103439d9a refactor(test): extract shared DEFAULT_OPTS into @pnpm/testing.command-defaults (#11208)
12 command test suites had near-identical ~50-field DEFAULT_OPTS objects
copy-pasted between them. Extract the common fields into a single shared
package so each suite only declares its overrides.
2026-04-05 21:22:24 +02:00
Zoltan Kochan
45a6cb6b2a refactor(auth): unify auth/SSL into structured configByUri (#11201)
Replaces the dual `authConfig` (raw .npmrc) + `authInfos` (parsed auth) + `sslConfigs` (parsed SSL) pattern with a single structured `configByUri: Record<string, RegistryConfig>` field on Config.

### New types (`@pnpm/types`)
- **`RegistryConfig`** — per-registry config: `{ creds?: Creds, tls?: TlsConfig }`
- **`Creds`** — auth credentials: `{ authToken?, basicAuth?, tokenHelper? }`
- **`TlsConfig`** — TLS config: `{ cert?, key?, ca? }`

### Key changes
- Rewrite `createGetAuthHeaderByURI` to accept `Record<string, RegistryConfig>` instead of raw .npmrc key-value pairs
- Eliminate duplicate auth parsing between `getAuthHeadersFromConfig` and `getNetworkConfigs`
- Remove `authConfig` from the install pipeline (`StrictInstallOptions`, `HeadlessOptions`), replaced by `configByUri`
- Remove `sslConfigs` from Config — SSL fields now live in `configByUri[uri].tls`
- Remove `authConfig['registry']` mutation in `extendInstallOptions` (default registry now passed directly to `createGetAuthHeaderByURI`)
- `authConfig` remains on Config only for raw .npmrc access (config commands, error reporting, config inheritance)

### Security
- tokenHelper in project .npmrc now throws instead of being silently stripped
- tokenHelper execution uses `shell: false` to prevent shell metacharacter injection
- Basic auth uses `Buffer.from().toString('base64')` instead of `btoa()` for Unicode safety
- Dispatcher only creates custom agents when entries actually have TLS fields
2026-04-05 20:15:10 +02:00
Zoltan Kochan
b5d93c6ba9 refactor(config): remove rawLocalConfig and force* hoist flags (#11199)
rawLocalConfig detected whether hoist settings were explicitly
set. In v11, config values are always authoritative.

- Remove rawLocalConfig from ConfigContext, config reader,
  inheritPickedConfig, UniversalOptions
- Remove forceHoistPattern, forcePublicHoistPattern,
  forceShamefullyHoist — validateModules always checks now
- Simplify save-workspace-protocol check
- Remove dead rawLocalConfig overrides in deploy/patchCommit
2026-04-05 11:36:36 +02:00
Zoltan Kochan
3033bee430 refactor(config): split Config interface into settings + runtime context (#11197)
* refactor(config): split Config interface into settings + runtime context

Create ConfigContext for runtime state (hooks, finders, workspace graph,
CLI metadata) and keep Config for user-facing settings only. Functions
use Pick<Config, ...> & Pick<ConfigContext, ...> to express which fields
they need from each interface.

getConfig() now returns { config, context, warnings }. The CLI wrapper
returns { config, context } and spreads both when calling command
handlers (to be refactored to separate params in follow-up PRs).

Closes #11195

* fix: address review feedback

- Initialize cliOptions on pnpmConfig so context.cliOptions is never undefined
- Move rootProjectManifestDir assignment before ignoreLocalSettings guard
- Add allProjectsGraph to INTERNAL_CONFIG_KEYS

* refactor: remove INTERNAL_CONFIG_KEYS from configToRecord

configToRecord now accepts Config and ConfigContext separately, so
context fields are never in scope. Only auth-related Config fields
(authConfig, authInfos, sslConfigs) need filtering.

* refactor: eliminate INTERNAL_CONFIG_KEYS from configToRecord

configToRecord now receives the clean Config object and explicitlySetKeys
separately (via opts.config and opts.context), so context fields are
never in scope. main.ts passes the original split objects alongside
the spread for command handlers that need them.

* fix: spelling

* fix: import sorting

* fix: --config.xxx nconf overrides conflicting with --config CLI flag

When `pnpm add` registers `config: Boolean`, nopt captures
--config.xxx=yyy as the --config flag value instead of treating it
as a nconf-style config override. Fix by extracting --config.xxx args
before nopt parsing and re-parsing them separately.

Also rename the split config/context properties on the command opts
object to _config/_context to avoid clashing with the --config CLI option.
2026-04-04 23:44:25 +02:00
Zoltan Kochan
96704a1c58 refactor(config): rename rawConfig to authConfig, add nodeDownloadMirrors, simplify config reader (#11194)
Major cleanup of the config system after migrating settings from `.npmrc` to `pnpm-workspace.yaml`.

### Config reader simplification
- Remove `checkUnknownSetting` (dead code, always `false`)
- Trim `npmConfigTypes` from ~127 to ~67 keys (remove unused npm config keys)
- Replace `rcOptions` iteration over all type keys with direct construction from defaults + auth overlay
- Remove `rcOptionsTypes` parameter from `getConfig()` and its assembly chain

### Rename `rawConfig` to `authConfig`
- `rawConfig` was a confusing mix of auth data and general settings
- Non-auth settings are already on the typed `Config` object — stop duplicating them in `rawConfig`
- Rename `rawConfig` → `authConfig` across the codebase to clarify it only contains auth/registry data from `.npmrc`

### Remove `rawConfig` from non-auth consumers
- **Lifecycle hooks**: replace `rawConfig: object` with `userAgent?: string` — only user-agent was read
- **Fetchers**: remove unused `rawConfig` from git fetcher, binary fetcher, tarball fetcher, prepare-package
- **Update command**: use `opts.production/dev/optional` instead of `rawConfig.*`
- **`pnpm init`**: accept typed init properties instead of parsing `rawConfig`

### Add `nodeDownloadMirrors` setting
- New `nodeDownloadMirrors?: Record<string, string>` on `PnpmSettings` and `Config`
- Replaces the `node-mirror:<channel>` pattern that was stored in `rawConfig`
- Configured in `pnpm-workspace.yaml`:
  ```yaml
  nodeDownloadMirrors:
    release: https://my-mirror.example.com/download/release/
  ```
- Remove unused `rawConfig` from deno-resolver and bun-resolver

### Refactor `pnpm config get/list`
- New `configToRecord()` builds display data from typed Config properties on the fly
- Excludes sensitive internals (`authInfos`, `sslConfigs`, etc.)
- Non-types keys (e.g., `package-extensions`) resolve through `configToRecord` instead of direct property access
- Delete `processConfig.ts` (replaced by `configToRecord.ts`)

### Pre-push hook improvement
- Add `compile-only` (`tsgo --build`) to pre-push hook to catch type errors before push
2026-04-04 20:33:43 +02:00
sotanengel
c7203b99ad feat!: set default minimumReleaseAge to 1 day (1440 minutes) (#11158)
set default minimumReleaseAge to 1 day

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-04-04 13:26:22 +02:00
Zoltan Kochan
8bba5c3858 refactor(config): only read auth/registry from .npmrc, add registries to pnpm-workspace.yaml (#11189)
Replace the unmaintained @pnpm/npm-conf package with a purpose-built
module that reads only auth/registry-related settings from .npmrc files
using read-ini-file + @pnpm/config.env-replace (both already deps).

All non-registry settings (hoist-pattern, node-linker, etc.) are now
only read from pnpm-workspace.yaml, CLI options, or environment
variables. Registry-related settings (auth tokens, registry URLs,
SSL certs, proxy settings) continue to be read from .npmrc for
migration compatibility, and can also be set in pnpm-workspace.yaml.

New modules:
- loadNpmrcFiles.ts: reads .npmrc from standard locations, filters to
  auth/registry keys, returns structured layers
- npmConfigTypes.ts: inlined npm config type definitions
- npmDefaults.ts: inlined npm defaults (registry, unsafe-perm, etc.)
2026-04-04 02:44:12 +02:00
Khải
de3dc74439 feat(auth): keyboard event to open browser (#11148)
* feat(auth): add "Press ENTER to open in browser" during web authentication

During web-based authentication (login, publish), users can now press
ENTER to open the authentication URL in their default browser. The
background token polling continues uninterrupted, so users who prefer
to authenticate on their phone can still do so without pressing anything.

The implementation uses Node's readline module (not raw mode), so Ctrl+C
and Ctrl+Z continue to work normally. It is fully error-tolerant: if the
keyboard listener or browser opening fails, a warning is printed and the
polling continues.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix(auth): inject readline and execFile directly, not wrapper functions

Address review feedback:
- Remove defaultListenForEnter and defaultOpenBrowser wrapper functions
- Inject readline module and execFile function directly via context
- DEFAULT_CONTEXT now references modules directly (no closures)
- Use switch for platform detection, default = no browser prompt
- Rename pollWithBrowserOpen → offerToOpenBrowser (clearer name)
- Add platform-specific tests (darwin, win32, linux, freebsd)
- Use PassThrough streams for stdin mocks in tests

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix(auth): fix CI type errors in test mocks

- Type jest.fn() mocks for readline.createInterface properly
- Use PassThrough streams for stdin mocks in releasing/commands tests

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* refactor(auth): use generic Stdin parameter to eliminate PassThrough in tests

Per review feedback, add a generic Stdin type parameter to context
interfaces. This ties process.stdin and readline.createInterface together
through the same type, so tests can use simple { isTTY: true } mocks
instead of requiring PassThrough streams.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix(auth): propagate Stdin generic to releasing/commands OtpContext

The OtpContext in releasing/commands extends BaseOtpContext from
web-auth. Now that BaseOtpContext is generic, the local OtpContext
and publishWithOtpHandling must also be generic so tests can use
simple stdin mocks without PassThrough.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix: sort imports in releasing/commands otp.ts

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* refactor(auth): use .bind() for readline injection instead of generics

Per review feedback, revert the generic Stdin approach and instead use
readline.createInterface.bind(null, { input: process.stdin }) as the
injectable dependency. This avoids generics proliferation while keeping
the context clean — no arrow functions or closures in DEFAULT_CONTEXT.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* feat(publish): add "Press ENTER to open in browser" during publish OTP

Wire up createReadlineInterface and execFile in the publish
SHARED_CONTEXT so that pnpm publish also offers to open the browser
during web-based OTP authentication.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix(auth): improve browser-open prompt message

Change "Press ENTER to open in browser..." to
"Press ENTER to open the URL in your browser."

The old message implied the user should press Enter. The new wording
presents it as an available action, not an instruction — users can
also scan the QR code or copy-paste the URL.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* style: remove unnecessary arrow wrapper around createMockReadlineInterface

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* docs: explain why Enter keypress is fire-and-forget, not awaited

Add a comment explaining that only pollPromise is awaited — the Enter
listener is intentionally not part of a Promise.all. This prevents a
future refactor from reintroducing the npm bug where authentication
blocks until Enter is pressed, even when the user authenticates on
another device.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* docs: add permalink to npm's Promise.all bug in comment

Link to the specific npm-profile commit (d1a48be4259) so the comment
remains accurate even if npm fixes the bug in the future.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix: correct line numbers in npm-profile permalink (L85-L98)

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* style: apply review suggestion for npm-profile permalink format

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* style: remove duplicate line in npm-profile comment

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix: shadow global process instead of renaming to proc

Destructure as `process` (not `proc`) so the global `process` is
shadowed, preventing accidental direct access to it.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix: merge process fields in test mock contexts

Restructure createMockContext to merge process fields instead of
replacing the entire object. Tests that only need to override
platform or stdin no longer need to redundantly provide the other.

Also adds a test for undefined platform (default: case).

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix: use Omit+Partial for process overrides in test mock contexts

The process field spread `...overrides?.process` merges at runtime but
TypeScript still requires all fields in the override type. Fix by typing
the process override as Partial via Omit<..., 'process'> & { process?: Partial<...> }.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* refactor: extract a type alias

* refactor: extract MockContextOverrides type alias in remaining tests

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* refactor(auth): extract process types, use NodeJS.Platform, clean up tests

- Extract OfferToOpenBrowserProcess interface from inline process type
- Extract LoginProcess interface from inline process type in LoginContext
- Use NodeJS.Platform instead of string for platform fields (prevents typos)
- Rename simulateEnter → simulateEnterKeypress (clarify it's the key)
- Convert single-return functions to arrow expressions in tests
- Update test descriptions to say "Enter key" / "Enter keypress"

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* refactor(auth): rename offerToOpenBrowser → promptBrowserOpen

Per review feedback, "offer to open browser" was mouthful. Renamed
function, file, and all associated types (OfferToOpenBrowser* →
PromptBrowserOpen*).

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* docs: drop "IMPORTANT"

* refactor(auth): extract OtpProcess interface from inline process type

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix(auth): validate authUrl before passing to execFile

On Windows, cmd.exe re-parses execFile arguments with full shell
grammar, so metacharacters (&, |, ^, etc.) in the URL would be
interpreted as operators. Validate that authUrl is a well-formed
http(s) URL before passing it to the platform browser command.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* test(auth): add regression test for URLs with query parameters on win32

Verifies that URLs containing & and other query string characters are
passed through to execFile as-is on the win32 platform.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix(auth): escape cmd.exe metacharacters in Windows browser open URL

On Windows, cmd.exe re-parses execFile arguments and treats & | < > ^ %
as operators. Escape these with ^ so query strings in auth URLs
(e.g. ?token=abc&redirect=...) are not split by cmd.exe.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix(auth): use canonicalized URL and expand cmd.exe escape set

- Use parsedUrl.href (canonicalized by new URL()) instead of the raw
  authUrl string, ensuring percent-encoding of spaces and special chars.
- Expand cmd.exe metacharacter escaping to include () and ! in addition
  to & | < > ^ %, covering grouping operators and delayed expansion.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* docs(auth): document Windows browser-opening edge cases

Explain why cmd /c start is used instead of ShellExecuteW (not
callable from Node.js without a native addon), why alternatives
like explorer.exe, rundll32, and PowerShell are unreliable, and
note that a Rust/N-API addon could replace this in the future.

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

* fix: fix cspell errors in Windows browser-open comment

Reword to avoid unknown words "rundll" and "metacharacter".

https://claude.ai/code/session_01UtDnjrNQ2Cc3GLAPR8BrrW

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-03 01:36:00 +02:00
Zoltan Kochan
d6b8e281b6 chore: use pn instead of pnpm (#11124) 2026-03-28 11:55:51 +01:00
Zoltan Kochan
36b3826f7b feat: make clean/setup/deploy prefer user scripts over built-in commands (#11118)
* feat: make clean/setup/deploy prefer user scripts over built-in commands

When a project's package.json has a script named "clean", "setup", or
"deploy", running `pnpm clean/setup/deploy` now executes the script
instead of the built-in command. This prevents surprising behavior for
users with existing scripts.

When running from a workspace subdirectory where the root package.json
has one of these scripts, an error is thrown with guidance on how to
proceed.

Added "purge" as an alias for the built-in clean command, which always
runs the built-in regardless of scripts.

Closes #6816

* feat: also make rebuild prefer user scripts over the built-in

* refactor: move scriptOverride to command definitions

Each command now declares `scriptOverride = true` instead of a
centralized list in main.ts. All command names including aliases
are overridable by same-named scripts.

* refactor: rename scriptOverride to overridableByScript

* test: add e2e tests for script override behavior in clean/purge

* fix: address review feedback

- Fix JSDoc to reflect that aliases are also overridable by scripts
- Update npm_command env var to 'run-script' when redirecting to run
- Add 'purge' alias to clean command help text
2026-03-27 20:04:52 +01:00
Zoltan Kochan
9496b2c61b fix: remove --workspace flag from version command (#11115)
* fix: remove --workspace flag from version command, use only --recursive

The --workspace/--workspaces flags were incorrectly added as synonyms for
--recursive in the version command. In pnpm, --recursive (-r) is the
standard convention for applying commands across workspace packages.
Recursive versioning now only activates with the explicit -r flag.

* test: improve version command test coverage

Add tests for major/patch bumps, --json output, --allow-same-version,
invalid version handling, missing name/version, empty params, and
recursive mode with workspace packages including JSON output, skipping
unnamed packages, and verifying --recursive is required.

* test: use expect().rejects instead of try/catch in version tests

Avoids silent passes when the handler doesn't throw.
2026-03-27 19:02:24 +01:00
Khải
d4a1d734b6 feat: pnpm login (#11094)
* refactor: extract web auth QR code and polling into @pnpm/network.web-auth

Extract generateQrCode() and pollForWebAuthToken() from releasing/commands
into a new shared package so that both `pnpm publish` and the upcoming
`pnpm login` can reuse the web-based authentication flow with QR code
display and doneUrl polling.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* feat: implement `pnpm login` command

Add `pnpm login` (and `pnpm adduser` alias) for authenticating with npm
registries. The command:

- Tries web-based login first (POST /-/v1/login), displaying a QR code
  and polling for the token using @pnpm/network.web-auth
- Falls back to classic username/password/email login (PUT /-/user/
  org.couchdb.user:<username>) when web login is not supported (404/405)
- Saves the received auth token to the user's global rc file

Also fixes a tsgo build issue in releasing/commands where
OtpWebAuthFetchOptions was used as a local type alias but was only
available as a re-exported name.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* fix: resolve spellcheck issues in login test

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* fix: correct alphabetical ordering for meta-updater

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* chore: add meta-updater generated tsconfig files

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* fix: add explicit return type to prompt mock for tsgo compatibility

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* fix: use @pnpm/network.fetch instead of globalThis.fetch

Switch from globalThis.fetch to fetchWithAgent from @pnpm/network.fetch
so that pnpm login respects proxy settings (httpProxy/httpsProxy/noProxy),
custom SSL certificates (ca/cert/key), strictSsl, and retry configuration.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: improve login fetch types and use URL constructor

- Type LoginContext.fetch using WebAuthFetchOptions/WebAuthFetchResponse
  from @pnpm/network.web-auth, extended with text() and wider method
- Replace regex-based URL construction with new URL() constructor
- Remove redundant LoginFetchInit type

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: match publish pattern for dependency injection

- Static DEFAULT_CONTEXT constant instead of createDefaultContext factory
- context = DEFAULT_CONTEXT default parameter instead of context?: Partial
- Destructure context in function signatures for natural calling
- Use plain fetch from @pnpm/network.fetch (like SHARED_CONTEXT in publish)
- Context contains only side-effect functions and modules, not config

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: use typeof fetch instead of custom fetch types

Remove LoginFetchOptions and LoginFetchResponse. Type LoginContext.fetch
as typeof fetch from @pnpm/network.fetch directly, eliminating all casts.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* fix: remove placeholder username from login success message

Web login doesn't return a username, so just report the registry.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: use tempDir from @pnpm/prepare instead of manual tmp dirs

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* chore: update tsconfig references for @pnpm/prepare

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: inject readSettings/writeSettings for fully pure tests

Add readSettings and writeSettings to LoginContext so tests need no
filesystem side effects. Remove @pnpm/prepare devDependency.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: remove DEFAULT_CONTEXT from tests, use pure test context

Tests now construct their own TEST_CONTEXT with all no-op mocks,
eliminating any reliance on real side-effectful functions.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* test: use distinct opts per test, assert URLs and config paths

Each test now uses a different registry and configDir to verify URL
construction, config key generation, and save path are correct for
non-default options.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* test: throw on unexpected mock calls instead of silent fallbacks

All mock functions in TEST_CONTEXT now throw on unexpected calls,
ensuring tests fail loudly if the code makes unanticipated side effects.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* test: use IANA-reserved example.com domains in test URLs

Replace custom.registry.io and private.reg.co with example.com and
example.org (RFC 2606 reserved) to prevent domain squatting risks.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* test: use deterministic Date mock instead of native Date

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* test: assert globalInfo calls, throw on unexpected ones

Default globalInfo in TEST_CONTEXT now throws. Each test overrides it
to capture messages and asserts the expected output.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* fix: use inferred type for fetch url parameter in tests

Drop explicit `string` annotation so the parameter matches the
`RequestInfo` type expected by the fetch signature.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* fix: resolve type errors in login test mock fetch

Use mockResponse helper with `as any` cast to satisfy the Response
type, and String(url) for RequestInfo-to-string conversion.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* chore: add tsconfig.lint.tsbuildinfo to .gitignore

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: replace typeof fetch with explicit LoginFetchResponse/LoginFetchOptions types

Derive the fetch signature from actual call-site usage instead of
coupling to the concrete @pnpm/network.fetch type. This lets test
mocks return plain objects without casts.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* chore: gitignore generated pn/pnpx/pnx artifacts

These files are created by setup.js during preinstall and should not
be tracked.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: remove unnecessary backwards-compat aliases from otp.ts

Remove Otp-prefixed re-exports (OtpWebAuthFetchOptions,
OtpWebAuthFetchResponse, OtpWebAuthTimeoutError) that only existed as
backwards-compatibility shims. Update the test to import directly from
@pnpm/network.web-auth. Restore the named OtpDate interface that was
unnecessarily inlined.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* test(web-auth): add comprehensive unit tests for @pnpm/network.web-auth

Add dependency-injected unit tests covering:
- WebAuthTimeoutError: properties, code, hint, message
- generateQrCode: basic output and input differentiation
- pollForWebAuthToken: happy path, fetch argument passing,
  Retry-After handling (valid, non-finite, null, sub-interval,
  capped to remaining timeout, timeout during retry wait),
  error recovery (fetch throws, non-ok response, json parse error,
  missing token, empty token, multiple consecutive errors),
  custom timeout, poll interval timing

All tests use fake Date.now() and setTimeout — no real timers or
side effects.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* fix(web-auth): fix TS2339 compile errors in test assertions

Replace `.catch((e: WebAuthTimeoutError) => e)` pattern with
`rejects.toMatchObject()` to avoid `string | WebAuthTimeoutError`
union type issue when accessing `.timeout` property.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* feat(web-auth,login): extract shared OTP handling and add OTP support to login

- Create `withOtpHandling<T>()` in `@pnpm/network.web-auth` that wraps
  any operation with EOTP challenge detection, web auth flow, and
  classic OTP prompting.
- Refactor `publishWithOtpHandling` to delegate to the shared function.
- Add OTP handling to `pnpm login`'s classic (CouchDB) login flow:
  detects 401 + `www-authenticate: otp` header and retries with the
  OTP code (or web auth token) in the `npm-otp` header.
- Remove overly strict `this: this` constraints from WebAuthFetchResponse
  interfaces to improve cross-package type compatibility.
- Add 13 unit tests for `withOtpHandling` (classic + webauth flows).
- Add 4 login OTP tests (classic OTP, webauth OTP, non-401, non-otp 401).

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* fix(login): use word-boundary regex for URL assertion in test

Replace `m.includes(url)` with a regex that checks the URL is
bounded by whitespace or string boundaries, addressing the CodeQL
"incomplete URL substring sanitization" finding.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor(login): use toContainEqual + stringMatching for URL assertion

Replace manual `.some()` with Jest's `toContainEqual(expect.stringMatching(...))`
for better error messages on failure.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor(web-auth): use expect.any(String) instead of typeof check

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor(web-auth): consolidate multi-property assertions

Use toMatchObject and toEqual instead of separate per-property expects.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* docs: explain why npm-auth-type header is sent unconditionally

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: remove unused re-exports and add missing test coverage

Remove dead re-exports of OtpHandlingPromptOptions and
OtpHandlingPromptResponse from releasing/commands/src/publish/otp.ts.

Add tests for:
- LOGIN_MISSING_CREDENTIALS (empty username in classic login)
- LOGIN_NO_TOKEN (registry returns success without token)
- LOGIN_INVALID_RESPONSE (web login returns incomplete response)
- isWebLoginNotSupported with 405 status code

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor(login): rename readSettings/writeSettings to safeReadIniFile/writeIniFile

Use the actual function names in the LoginContext interface instead of
abstract names, matching the implementations they wrap.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor(otp): remove unnecessary re-exports from otp.ts

OtpNonInteractiveError, OtpSecondChallengeError, and OtpHandlingEnquirer
were re-exported only for the test file, which can import them directly
from @pnpm/network.web-auth.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor(otp): remove unused SHARED_CONTEXT re-export

All consumers already import SHARED_CONTEXT directly from
./utils/shared-context.js, making this re-export dead code.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor(login): extract LoginDate and LoginEnquirer interfaces

Extract named interfaces for the Date and enquirer members of
LoginContext instead of inlining their types.

https://claude.ai/code/session_01YHYqGAAmZ1a9XMWoV7nG4S

* refactor: stop renaming

Claude Code Web didn't rename them thoroughly, so I had to do it myself

* docs: correct the lines

Why did Claude Code Web misaligned?

* refactor: strictly type `LoginFetchOptions.headers`

* docs: remove redundant comments

* refactor: inline `npm-otp`

* refactor: inline `headers`

* feat: add `WebLoginError.responseText`

* refactor: rename `statusCode` into `httpStatus`

* refactor(login): extract ClassicLoginError subclass from PnpmError

Extract the LOGIN_FAILED error into a dedicated ClassicLoginError class
with httpStatus and responseText properties, matching the WebLoginError
pattern.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: remove unnecessary import

* docs(changeset): correct a changeset

* docs(changeset): re-add `releasing.commands`

* refactor(web-auth): split monolithic test file into per-module files

Split index.test.ts into four files matching the source structure:
- WebAuthTimeoutError.test.ts
- generateQrCode.test.ts
- pollForWebAuthToken.test.ts
- withOtpHandling.test.ts

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: remove unnecessary `as const`

* refactor: remove unnecessary `as const`

* chore: undo Claude's BS

* refactor: extract `LoginEnquirerOptions`

* refactor: move types closer to their usesites

* refactor: remove simple type alias

* fix: type errors

* refactor(login): inject readIniFile instead of safeReadIniFile in context

The context object should only contain external dependencies. safeReadIniFile
is a local wrapper, not an external dependency, so inject readIniFile (from
read-ini-file) instead and pass it to safeReadIniFile as a parameter.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* test(login): add coverage for safeReadIniFile ENOENT handling

Test that login succeeds with empty settings when the config file does
not exist (ENOENT), and that non-ENOENT errors (e.g. EACCES) are
properly propagated.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: fix ugliness

* refactor: just pass context object

* refactor: destructure `context`

* refactor: pass the `context` object

* refactor: destructure `context`

* refactor: pass `context` object directly

* refactor: remove unnecessary parenthesis

* fix: remove unused import

* refactor: remove unnecessary parentheses from single-param arrows in tests

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: extract `LoginFetchResponseHeaders`

* fix(login): remove inline default from --registry option description

No other pnpm command includes "(default: ...)" in option descriptions.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor(tests): enforce realistic mock response behavior

- Add createMockResponse helpers that enforce single body consumption
  (calling text() or json() twice, or both, throws an error)
- Default headers.get to throwing on unexpected calls, forcing tests
  to explicitly provide headers when the code under test reads them
- Replace all inline response objects with createMockResponse calls

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix: formatting

* refactor: reuse

* docs: clarify what the error is actually about

* docs: consistent error message

* refactor: use consistent error message convention in test mocks

Capitalize and use "Unexpected call to <thing>" pattern instead of
AI-generated "unexpected X call" messages.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: expand inline process mock objects to multi-line

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor(login): extract PnpmError subclasses and use stricter test assertions

Extract LoginNonInteractiveError, LoginInvalidResponseError,
LoginMissingCredentialsError, and LoginNoTokenError subclasses instead
of throwing PnpmError directly.

Update test assertions to use the const promise pattern with
toHaveProperty checks on both code and message, matching the
convention used elsewhere in the codebase.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: undo ai's nonsensical deletion

* refactor: simplify

* refactor: rename OtpHandling* types to Otp* for brevity

OtpHandlingContext → OtpContext
OtpHandlingEnquirer → OtpEnquirer
OtpHandlingPromptOptions → OtpPromptOptions
OtpHandlingPromptResponse → OtpPromptResponse

The OtpHandling prefix was named after the function (withOtpHandling)
rather than the domain concept.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: extract `OtpDate`

* refactor: reuse

* fix: eslint

* refactor: add OtpRequiredError with body validation and globalWarn

- Add OtpRequiredError class with static fromUnknown() that validates
  the EOTP error body shape and returns either a validated error or an
  OtpBodyWarning when fields have unexpected types
- Add globalWarn to OtpContext so withOtpHandling can warn on bad body
  shapes instead of silently dropping them
- Update throwIfOtpRequired in login.ts to pass raw body through so
  validation happens in withOtpHandling via fromUnknown
- Add tests for bad body shapes (wrong types for authUrl/doneUrl)
- Add tests for OtpRequiredError.fromUnknown
- Propagate globalWarn through LoginContext, DEFAULT_CONTEXT,
  SHARED_CONTEXT, and all test mocks

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* docs: remove misleading comment from throwIfOtpRequired

The comment referenced downstream machinery (OtpRequiredError.fromUnknown)
that the reader shouldn't need to know about at this call site.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: replace Object.assign hack with OtpRequiredError in throwIfOtpRequired

throwIfOtpRequired now validates the raw response body via
OtpRequiredError.fromUnknown and throws a proper OtpRequiredError
instead of monkey-patching properties onto a plain Error.

withOtpHandling skips re-validation when the caught error is already
an OtpRequiredError instance.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* chore(git): revert an imperfect fix

This reverts commit f91efc1d9e.

* chore(git): revert would-be irrelevant change

This reverts commit 646c09cc66.

* chore(git): revert an imperfect fix

This reverts commit 45ff1ca601.

* refactor: replace Object.assign hack with ArtificialOtpError

Add ArtificialOtpError class that implements OtpError and validates
unknown body shapes via fromUnknownBody static method, warning on
unexpected types instead of silently dropping them.

Add globalWarn to OtpContext and propagate through LoginContext,
DEFAULT_CONTEXT, SHARED_CONTEXT, and all test mocks.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: rename ArtificialOtpError to SyntheticOtpError

"Synthetic" better conveys that the error is programmatically
constructed from raw data, not that it's fake.

Also fix grammatical error in JSDoc ("meant to thrown" → "meant to be thrown").

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix: eslint

Claude Code Web got it wrong this time

(or maybe because it inherited from my sketch diff? I'm not sure)

* fix: eslint

Ah! I got it. Claude Code Web was at fault here: It renamed "artificial"
to "synthetic" without re-ordering

Dumb AI!

* fix: formatting

Once again caused by Claude Code.

Anyway,

The exact equivalent refactor should have been `void warnings.push(msg)`,
if you really want to be pedantic, that is.

TypeScript, however, allows a `void` function to return any type. Reason
being that they shall all be discarded anyway.

* refactor: remove unnecessary re-assignment

* test: remove unnecessary assertion

* refactor: make default globalInfo and globalWarn mocks throw on unexpected calls

Replace no-op defaults with throwing mocks in createOtpMockContext
and createMockContext. Tests that expect these to be called now
explicitly override them.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: use toEqual with stringContaining for array assertions

Replace toHaveLength + indexed toContain pairs with single
toEqual([expect.stringContaining(...)]) assertions.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: replace globalInfo no-ops with jest.fn() and add assertions

For error tests: remove globalInfo override entirely, letting the
default throwing mock catch unexpected calls.

For success tests: use jest.fn() and assert globalInfo was called
with the expected arguments.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: replace manual array collectors with jest.fn()

Replace infoMessages/warnings arrays and push callbacks with
jest.fn() and assertions on .mock.calls. This is more idiomatic
and eliminates the boilerplate array + push pattern.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: replace remaining globalInfo no-ops with jest.fn() in otp.test.ts

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix(test): throw on unexpected second call instead of returning 'never'

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix(test): add missing globalInfo assertion in classic OTP test

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix(test): add missing globalInfo assertion in otp webauth polling test

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix(test): add @jest/globals import for jest.fn()

jest is not a global in ESM mode (--experimental-vm-modules).
Add import { jest } from '@jest/globals' to all test files using
jest.fn(), and add @jest/globals devDependency to network/web-auth.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* chore(deps): update lockfile

* fix: eslint

* fix(test): add globalInfo mock to EACCES readIniFile test

The test triggers web login (which calls globalInfo with the QR code)
before reaching readIniFile. Without a globalInfo override, the
default throwing mock causes the test to fail at the wrong point.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix(test): add missing globalInfo assertion in EACCES readIniFile test

Extract inline jest.fn() to const and assert it was called with
the web login QR code URL.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: convert functions with 3+ args to params objects

Per the style guide: "Functions should have no more than two or three
arguments. If a function needs more parameters, use a single options
object instead."

- withOtpHandling(operation, context, fetchOptions) → withOtpHandling({ operation, context, fetchOptions })
- pollForWebAuthToken(doneUrl, context, fetchOptions, timeoutMs) → pollForWebAuthToken({ doneUrl, context, fetchOptions, timeoutMs })
- webLogin(registry, fetchOptions, context) → webLogin({ registry, fetchOptions, context })
- classicLogin(registry, context, fetchOptions) → classicLogin({ registry, context, fetchOptions })

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: sort params object properties alphabetically

Sort interface properties, function signature destructuring, and
call site arguments in alphabetical order to match the convention
used by publishWithOtpHandling.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* refactor: adopt otp.test.ts patterns in login and web-auth tests

- Build context and opts as separate variables, then call login/
  withOtpHandling/pollForWebAuthToken on a clean line
- Add createMockContext to login.test.ts
- Convert createMockContext to arrow functions (single return
  expression), keep createMockResponse as function declaration
  (has local state)

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix: eslint

* refactor: inline the one-off function

* fix(login): avoid sending 'npm-otp: undefined' header on initial request

When otp is undefined (first attempt before OTP challenge), the header
'npm-otp': undefined could be coerced to the string "undefined" by
some HTTP implementations. Use conditional spread instead.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* docs(login): explain why npm-otp header is conditionally spread

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* docs(otp): explain why otp: undefined is safe in publishOptions spread

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix(test): use path.join in assertions for Windows compatibility

path.join produces backslashes on Windows, so hardcoded forward-slash
paths in assertions fail on Windows CI.

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

* fix: import order — standard library before external deps

https://claude.ai/code/session_0191GhgPWiD5TroLMoXAmkaZ

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-27 12:00:22 +01:00
Alessio Attilio
d5be835735 feat: implement native recursive version command (#10879)
* feat: implement non-interactive version command

* fix: address review issues in version command

- Fix changeset package name to @pnpm/releasing.commands
- Use writeProjectManifest instead of writeJsonFile to preserve formatting
- Remove dead updateWorkspaceDependencies placeholder function
- Remove unused imports (path, ProjectManifest, writeJsonFile)
- Add expect.assertions(1) to prevent silent test pass on no-throw

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 11:51:54 +00:00
Zoltan Kochan
421ceac0b3 chore: compile pnpm CLI bundle before tests that use it (#11059)
Packages whose tests spawn the local pnpm CLI (pnpm/bin/pnpm.mjs) need
the bundle (pnpm/dist/pnpm.mjs) to exist. Add `pnpm --filter pnpm run
compile` to their test scripts so the bundle is built before tests run.
2026-03-22 10:56:36 +01:00
Brandon Cheng
41dc031a67 test: use resolution-mode=highest in tests (#10989)
* fix: configure default resolution-mode to highest in pkg-manager/core

* test: update catalog tests for resolution-mode=highest

* test: fix `--fix-lockfile` test for new resolution-mode default

```
  ● fix broken lockfile with --fix-lockfile

    expect(received).toBeTruthy()

    Received: undefined

      55 |   const lockfile: LockfileFile = readYamlFileSync(WANTED_LOCKFILE)
      56 |   expect(Object.keys(lockfile.packages as PackageSnapshots)).toHaveLength(2)
    > 57 |   expect(lockfile.packages?.['@types/semver@5.3.31']).toBeTruthy()
         |                                                       ^
      58 |   expect(lockfile.packages?.['@types/semver@5.3.31']?.resolution).toEqual({
      59 |     integrity: 'sha512-WBv5F9HrWTyG800cB9M3veCVkFahqXN7KA7c3VUCYZm/xhNzzIFiXiq+rZmj75j7GvWelN3YNrLX7FjtqBvhMw==',
      60 |   })

      at Object.<anonymous> (test/install/fixLockfile.ts:57:55)
```

* test: fix lockfile conflict test

  ● a lockfile v6 with merge conflicts is autofixed

    expect(received).toHaveProperty(path, value)

    Expected path: "version"

    Expected value: "100.1.0"
    Received value: "101.0.0"

      1284 |
      1285 |   const lockfile = project.readLockfile()
    > 1286 |   expect(lockfile.importers?.['.'].dependencies?.['@pnpm.e2e/dep-of-pkg-with-1-dep']).toHaveProperty('version', '100.1.0')
           |                                                                                       ^
      1287 | })
      1288 |
      1289 | test('a lockfile with duplicate keys is fixed', async () => {

      at Object.<anonymous> (test/lockfile.ts:1286:87)

* test: fix deploy shared lockfile test

  ● deploy with a shared lockfile that has peer dependencies suffix in workspace package dependency paths

    expect(received).toMatchObject(expected)

    - Expected  - 6
    + Received  + 1

    @@ -1,11 +1,11 @@
      Object {
        "importers": Object {
          "packages/project-0": Object {
            "dependencies": Object {
              "project-1": Object {
    -           "version": "file:packages/project-1(is-negative@1.0.0)(project-2@file:packages/project-2(is-positive@1.0.0))",
    +           "version": "file:packages/project-1(is-negative@2.1.0)(project-2@file:packages/project-2(is-positive@1.0.0))",
              },
              "project-2": Object {
                "version": "file:packages/project-2(is-positive@1.0.0)",
              },
            },
    @@ -31,13 +31,8 @@
              "type": "directory",
            },
          },
        },
        "snapshots": Object {
    -     "project-1@file:packages/project-1(is-negative@1.0.0)(project-2@file:packages/project-2(is-positive@1.0.0))": Object {
    -       "dependencies": Object {
    -         "project-2": "file:packages/project-2(is-positive@1.0.0)",
    -       },
    -     },
          "project-2@file:packages/project-2(is-positive@1.0.0)": Object {},
        },
      }

      950 |     workspaceDir: process.cwd(),
      951 |   })
    > 952 |   expect(assertProject('.').readLockfile()).toMatchObject({
          |                                             ^
      953 |     importers: {
      954 |       'packages/project-0': {
      955 |         dependencies: {

      at Object.<anonymous> (test/shared-lockfile.test.ts:952:45)

* test: fix injectLocalPackages test
2026-03-21 23:21:04 +01:00
Zoltan Kochan
cd2dc7d481 refactor: prefix internal scripts with . to hide them (#11051)
* fix: ensure PNPM_HOME/bin is in PATH during pnpm setup

When upgrading from old pnpm (global bin = PNPM_HOME) to new pnpm
(global bin = PNPM_HOME/bin), `pnpm setup` would fail because the
spawned `pnpm add -g` checks that the global bin dir is in PATH.
Prepend PNPM_HOME/bin to PATH in the spawned process env so the
check passes during the transition.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update pnpm to v11 beta 2

* chore: update pnpm to v11 beta 2

* chore: update pnpm to v11 beta 2

* chore: update pnpm to v11 beta 2

* fix: lint

* refactor: rename _-prefixed scripts to .-prefixed scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update root package.json to use .test instead of _test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: update action-setup

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:30:56 +01:00
Zoltan Kochan
0d88df854f chore: update all dependencies to latest versions (#11032)
* chore: update all dependencies to latest versions

Update all outdated dependencies across the monorepo catalog and fix
breaking changes from major version bumps.

Notable updates:
- ESLint 9 → 10 (fix custom rule API, disable new no-useless-assignment)
- @stylistic/eslint-plugin 4 → 5 (auto-fixed indent changes)
- @cyclonedx/cyclonedx-library 9 → 10 (adapt to removed SPDX API)
- esbuild 0.25 → 0.27
- TypeScript 5.9.2 → 5.9.3
- Various @types packages, test utilities, and build tools

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update unified/remark/mdast imports for v11/v4 API changes

Update imports in get-release-text for the new ESM named exports:
- mdast-util-to-string: default → { toString }
- unified: default → { unified }

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: resolve typecheck errors from dependency updates

- isexe v4: use named import { sync } instead of default export
- remark-parse/remark-stringify v11: add vfile as packageExtension
  dependency so TypeScript can resolve type declarations
- get-release-text: remove unused @ts-expect-error directives

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: revert runtime dependency major version bumps

Revert major version bumps for runtime dependencies that are bundled
into pnpm to fix test failures where pnpm add silently fails:
- bin-links: keep ^5.0.0 (was ^6.0.0)
- cli-truncate: keep ^4.0.0 (was ^5.2.0)
- delay: keep ^6.0.0 (was ^7.0.0)
- filenamify: keep ^6.0.0 (was ^7.0.1)
- find-up: keep ^7.0.0 (was ^8.0.0)
- isexe: keep 2.0.0 (was 4.0.0)
- normalize-newline: keep 4.1.0 (was 5.0.0)
- p-queue: keep ^8.1.0 (was ^9.1.0)
- ps-list: keep ^8.1.1 (was ^9.0.0)
- string-length: keep ^6.0.0 (was ^7.0.1)
- symlink-dir: keep ^7.0.0 (was ^9.0.0)
- terminal-link: keep ^4.0.0 (was ^5.0.0)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: restore runtime dependency major version bumps

Re-apply all runtime dependency major version bumps that were
previously reverted. All packages maintain their default exports
except isexe v4 which needs named imports.

Updated runtime deps:
- bin-links: ^5.0.0 → ^6.0.0
- cli-truncate: ^4.0.0 → ^5.2.0
- delay: ^6.0.0 → ^7.0.0
- filenamify: ^6.0.0 → ^7.0.1
- find-up: ^7.0.0 → ^8.0.0
- isexe: 2.0.0 → 4.0.0 (fix: use named import { sync })
- normalize-newline: 4.1.0 → 5.0.0
- p-queue: ^8.1.0 → ^9.1.0
- ps-list: ^8.1.1 → ^9.0.0
- string-length: ^6.0.0 → ^7.0.1
- symlink-dir: ^7.0.0 → ^9.0.0
- terminal-link: ^4.0.0 → ^5.0.0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: revert tempy to 3.0.0 to fix bundle hang

tempy 3.2.0 pulls in temp-dir 3.0.0 which uses async fs.realpath()
inside its module init. When bundled by esbuild into the __esm lazy
init pattern, this causes a deadlock during module initialization,
making the pnpm binary hang silently on startup.

Keeping tempy at 3.0.0 which uses temp-dir 2.x (sync fs.realpathSync).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add comment explaining why tempy cannot be upgraded

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: revert nock to 13.3.4 for node-fetch compatibility

nock 14 changed its HTTP interception mechanism in a way that doesn't
properly intercept node-fetch requests, causing audit tests to hang
waiting for responses that are never intercepted.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add comment explaining why nock cannot be upgraded

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update symlink-dir imports for v10 ESM named exports

symlink-dir v10 removed the default export and switched to named
exports: { symlinkDir, symlinkDirSync }.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: revert @typescript/native-preview to working version

Newer tsgo dev builds (>= 20260318) have a regression where
@types/node cannot be resolved, breaking all node built-in types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: vulnerabilities

* fix: align comment indentation in runLifecycleHook

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: pin msgpackr to 1.11.8 for TypeScript 5.9 compatibility

msgpackr 1.11.9 has broken type definitions that use Iterable/Iterator
without required type arguments, causing compile errors with TS 5.9.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:28:53 +01:00
Zoltan Kochan
812cae93d6 test(releasing): fix 2026-03-19 19:02:17 +01:00
Zoltan Kochan
1701a65845 chore: reduce noisy warnings in test output (#11022)
* chore: reduce noisy warnings in test output

- Suppress ExperimentalWarning and DEP0169 via --disable-warning in NODE_OPTIONS
- Fix MaxListenersExceededWarning by raising limit in StoreIndex when adding exit listeners
- Update meta-updater to generate the new _test scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: stop streaming pnpm subprocess output during CLI tests

Buffer stdout/stderr from execPnpm instead of writing to the parent
process in real time. Output is still included in the error message on
failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: pipe all subprocess output in CLI tests

Use stdio: 'pipe' for all pnpm/pnpx spawn helpers so subprocess output
is buffered instead of printed. Output is still included in error
messages on failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove duplicate @pnpm/installing.env-installer in pnpm/package.json

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: use pipe stdio in dlx and errorHandler tests

Replace stdio: 'inherit' and [null, 'pipe', 'inherit'] with 'pipe' to
prevent subprocess output from leaking into test output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: skip maxListeners adjustment when set to unlimited (0)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:43:12 +01:00
Zoltan Kochan
88ad21dff8 feat(publish): handle OTP and web-based authentication flows (#11019)
* feat(publish): handle OTP and web-based authentication flows (#10834)

Add OTP handling to `pnpm publish` with support for:
- Classic OTP prompt (manual code entry)
- Web-based authentication flow with QR code display and doneUrl polling
- `npm-auth-type: web` header to signal web auth support to the registry

Extract OTP logic into a dedicated `otp.ts` module with dependency
injection for testability. Consolidate shared context for OIDC and OTP.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: KSXGitHub <11488886+KSXGitHub@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-18 23:11:17 +01:00
Zoltan Kochan
303ca410f5 feat!: stop reading settings from the pnpm field of package.json (#10086)
Settings should be read from pnpm-workspace.yaml
2026-03-18 14:46:07 +01:00
Zoltan Kochan
d0ae78821a refactor: rename workspace functions from packages to projects (#11002)
Align function, type, and file names with the packages-to-projects
rename in workspace packages (projects-filter, projects-reader,
projects-sorter).
2026-03-18 11:38:02 +01:00
Zoltan Kochan
dba4153767 refactor: rename packages and consolidate runtime resolvers (#10999)
* refactor: rename workspace.sort-packages and workspace.pkgs-graph

- workspace.sort-packages -> workspace.projects-sorter
- workspace.pkgs-graph -> workspace.projects-graph

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: rename packages/ to core/ and pkg-manifest.read-package-json to reader

- Rename packages/ directory to core/ for clarity
- Rename pkg-manifest/read-package-json to pkg-manifest/reader (@pnpm/pkg-manifest.reader)
- Update all tsconfig, package.json, and lockfile references

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: consolidate runtime resolvers under engine/runtime domain

- Remove unused @pnpm/engine.runtime.node.fetcher package
- Rename engine/runtime/node.resolver to node-resolver (dash convention)
- Move resolving/bun-resolver to engine/runtime/bun-resolver
- Move resolving/deno-resolver to engine/runtime/deno-resolver
- Update all package names, tsconfig paths, and lockfile references

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: update lockfile after removing node.fetcher

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: sort tsconfig references and package.json deps alphabetically

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: auto-fix import sorting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update __typings__ paths in tsconfig.lint.json for moved resolvers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove deno-resolver from deps of bun-resolver

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 00:19:58 +01:00
Zoltan Kochan
4a36b9a110 refactor: rename internal packages to @pnpm/<domain>.<leaf> convention (#10997)
## Summary

Rename all internal packages so their npm names follow the `@pnpm/<domain>.<leaf>` convention, matching their directory structure. Also rename directories to remove redundancy and improve clarity.

### Bulk rename (94 packages)

All `@pnpm/` packages now derive their name from their directory path using dot-separated segments. Exceptions: `packages/`, `__utils__/`, and `pnpm/artifacts/` keep leaf names only.

### Directory renames (removing redundant prefixes)

- `cli/cli-meta` → `cli/meta`, `cli/cli-utils` → `cli/utils`
- `config/config` → `config/reader`, `config/config-writer` → `config/writer`
- `fetching/fetching-types` → `fetching/types`
- `lockfile/lockfile-to-pnp` → `lockfile/to-pnp`
- `store/store-connection-manager` → `store/connection-manager`
- `store/store-controller-types` → `store/controller-types`
- `store/store-path` → `store/path`

### Targeted renames (clarity improvements)

- `deps/dependency-path` → `deps/path` (`@pnpm/deps.path`)
- `deps/calc-dep-state` → `deps/graph-hasher` (`@pnpm/deps.graph-hasher`)
- `deps/inspection/dependencies-hierarchy` → `deps/inspection/tree-builder` (`@pnpm/deps.inspection.tree-builder`)
- `bins/link-bins` → `bins/linker`, `bins/remove-bins` → `bins/remover`, `bins/package-bins` → `bins/resolver`
- `installing/get-context` → `installing/context`
- `store/package-store` → `store/controller`
- `pkg-manifest/manifest-utils` → `pkg-manifest/utils`

### Manifest reader/writer renames

- `workspace/read-project-manifest` → `workspace/project-manifest-reader` (`@pnpm/workspace.project-manifest-reader`)
- `workspace/write-project-manifest` → `workspace/project-manifest-writer` (`@pnpm/workspace.project-manifest-writer`)
- `workspace/read-manifest` → `workspace/workspace-manifest-reader` (`@pnpm/workspace.workspace-manifest-reader`)
- `workspace/manifest-writer` → `workspace/workspace-manifest-writer` (`@pnpm/workspace.workspace-manifest-writer`)

### Workspace package renames

- `workspace/find-packages` → `workspace/projects-reader`
- `workspace/find-workspace-dir` → `workspace/root-finder`
- `workspace/resolve-workspace-range` → `workspace/range-resolver`
- `workspace/filter-packages-from-dir` merged into `workspace/filter-workspace-packages` → `workspace/projects-filter`

### Domain moves

- `pkg-manifest/read-project-manifest` → `workspace/project-manifest-reader`
- `pkg-manifest/write-project-manifest` → `workspace/project-manifest-writer`
- `pkg-manifest/exportable-manifest` → `releasing/exportable-manifest`

### Scope

- 1206 files changed
- Updated: package.json names/deps, TypeScript imports, tsconfig references, changeset files, renovate.json, test fixtures, import ordering
2026-03-17 21:50:40 +01:00
Zoltan Kochan
7a304b17c4 refactor: rename directories and unify command packages per domain (#10993)
- Rename `installing/core` → `installing/deps-installer` and `installing/headless` → `installing/deps-restorer` for clearer naming
- Rename all `plugin-commands-*` directories to use `-commands` suffix convention
- Merge multiple command packages per domain into a single `commands/` directory (one commands package per domain rule):
  - `building/{build-commands,policy-commands}` → `building/commands`
  - `deps/compliance/{audit-commands,licenses-commands,sbom-commands}` → `deps/compliance/commands`
  - `deps/inspection/{listing-commands,outdated-commands}` → `deps/inspection/commands`
  - `store/{store-commands,inspecting-commands}` → `store/commands`
  - `releasing/{publish-commands,deploy-commands}` → `releasing/commands`
  - `cli/{completion-commands,doctor-commands}` → `cli/commands`
  - `engine/pm/{self-updater-commands,setup-commands}` → `engine/pm/commands`
  - `engine/runtime/{runtime-commands,env-commands}` → `engine/runtime/commands`
  - `cache/cache-commands` → `cache/commands`
- Fix relative paths in merged test files (pnpmBin, __typings__ references)
- Update jest config to ignore `utils/` dirs at any nesting depth under `test/`
- Fix stale package names in changeset files
2026-03-17 17:42:20 +01:00
Zoltan Kochan
f47ef4b125 refactor: reorganize monorepo domain structure (#10987)
Reorganize the monorepo's top-level domain directories for clarity:

- pkg-manager/ split into:
  - installing/ (core, headless, client, resolve-dependencies, etc.)
  - installing/linking/ (hoist, direct-dep-linker, modules-cleaner, etc.)
  - bins/ (link-bins, package-bins, remove-bins)
- completion/ merged into cli/
- dedupe/ moved to installing/dedupe/
- env/ renamed to engine/ with subdomains:
  - engine/runtime/ (node.fetcher, node.resolver, plugin-commands-env, etc.)
  - engine/pm/ (plugin-commands-setup, plugin-commands-self-updater)
- env.path moved to shell/
- tools/ and runtime/ dissolved
- reviewing/ and lockfile audit packages moved to deps/:
  - deps/inspection/ (list, outdated, dependencies-hierarchy)
  - deps/compliance/ (audit, licenses, sbom)
- registry/ moved to resolving/registry/
- semver/peer-range moved to deps/
- network/fetching-types moved to fetching/
- packages/ slimmed down, moving packages to proper domains:
  - calc-dep-state, dependency-path -> deps/
  - parse-wanted-dependency -> resolving/
  - git-utils -> network/
  - naming-cases -> text/
  - make-dedicated-lockfile -> lockfile/
  - render-peer-issues -> installing/
  - plugin-commands-doctor -> cli/
  - plugin-commands-init -> workspace/

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 13:45:54 +01:00
Zoltan Kochan
5d5818e44f style: enforce node: protocol for builtin imports (#10951)
Add n/prefer-node-protocol rule and autofix all bare builtin imports
to use the node: prefix. Simplify the simple-import-sort builtins
pattern to just ^node: since all imports now use the prefix.
2026-03-13 07:59:51 +01:00
Zoltan Kochan
1c8c4e49f5 style: add eslint-plugin-simple-import-sort (#10947)
Add eslint-plugin-simple-import-sort to enforce consistent import ordering:
- Node.js builtins first
- External packages second
- Relative imports last
- Named imports sorted alphabetically within each statement
2026-03-13 02:02:38 +01:00
Zoltan Kochan
3a5bfaa94f chore: update zkochan packages to latest versions (#10930)
Update all packages from zkochan/packages to their latest major versions
and exclude them from minimumReleaseAge requirement. This includes
updating catalog entries, adapting to breaking API changes (default
exports replaced with named exports, sync functions renamed with Sync
suffix), and updating type declarations.
2026-03-11 13:47:46 +01:00
Zoltan Kochan
aeb06caae9 refactor: simplify patchedDependencies lockfile format (#10911)
* refactor: simplify patchedDependencies lockfile format to map selectors to hashes

Remove the `path` field from patchedDependencies in the lockfile, changing the
format from `Record<string, { path: string, hash: string }>` to
`Record<string, string>` (selector → hash). The path was never consumed from
the lockfile — patch file paths come from user config, not the lockfile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: migrate old patchedDependencies format when reading lockfile

When reading a lockfile with the old `{ path, hash }` format for
patchedDependencies, extract just the hash string. This ensures
backwards compatibility with existing lockfiles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: carry patchFilePath through patch groups for runtime patch application

The previous commit removed `path` from the lockfile format but also
accidentally dropped it from the runtime PatchInfo type. This broke
patch application since `applyPatchToDir` needs the file path.

- Add optional `patchFilePath` to `PatchInfo` for runtime use
- Build patch groups with resolved file paths in install
- Fix `build-modules` to use `patchFilePath` instead of `file.path`
- Fix `calcPatchHashes` call site in `checkDepsStatus` (extra arg)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update remaining references to old PatchFile type

- Update getPatchInfo tests to use { hash, key } instead of { file, key }
- Fix createDeployFiles to handle patchedDependencies as hash strings
- Fix configurationalDependencies test assertion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: throw when patch exists but patchFilePath is missing

Also guard against undefined patchedDependencies entry when
ignorePackageManifest is true.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: don't join lockfileDir with already-absolute patch file paths

opts.patchedDependencies values are already absolute paths, so
path.join(opts.lockfileDir, absolutePath) created invalid doubled
paths like /project/home/runner/work/pnpm/...

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use path.resolve for patch file paths and address Copilot review

- Use path.resolve instead of path.join to correctly handle both
  relative and absolute patch file paths
- Use PnpmError instead of plain Error for missing patch file path
- Only copy patchedDependencies to deploy output when manifest
  provides the patch file paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: pass rootProjectManifest in deploy patchedDependencies test

The test was missing rootProjectManifest, so createDeployFiles could
not find the manifest's patchedDependencies to propagate to the
deploy output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:26:48 +01:00
Brandon Cheng
01914345d5 build: enable @typescript-eslint/no-import-type-side-effects (#10630)
* build: enable `@typescript-eslint/no-import-type-side-effects`

* build: disable `@typescript-eslint/consistent-type-imports`

* chore: apply fixes for `no-import-type-side-effects`

pnpm exec eslint "**/src/**/*.ts" "**/test/**/*.ts" --fix
2026-03-08 00:02:48 +01:00
Zoltan Kochan
5979bb7b0c test: replace sinon with built-in jest spying across the repo (#10849)
Replace all sinon.spy/match/withArgs usage with jest.fn, toHaveBeenCalledWith,
mockClear, and mock.calls filtering. Remove sinon and @types/sinon from all
package.json files and the workspace catalog.
2026-03-04 15:00:25 +01:00
Zoltan Kochan
84075f96bf fix: update npm-packlist (#10658) 2026-02-25 11:33:52 +01:00
Zoltan Kochan
e18a879d72 feat!: drop Node.js 22.12 support 2026-02-18 14:54:09 +01:00
Khải
52556a858a refactor(test): some small polishments (#10603)
* test: full message

* refactor: consistent indentation

* docs: remove extraneous comment

* test: more cases
2026-02-12 22:54:13 +01:00
Khải
cc7c0d22df refactor!: replace npm publish with libnpmpublish (#10591)
* chore(deps): add `libnpmpublish` to catalog

* chore(deps): install `libnpmpublish`

* feat: publishableManifest (wip)

* feat: publishableManifest (wip)

* chore(cspell): libnpmpublish

* test: fix

* feat: validate field and version

* chore: @npm/types

* chore: todo

* refactor: reorganize

* feat: transformRequiredFields

* chore(deps): patch `libnpmpublish`

* fix: `BaseManifest.config`

* fix: eslint

* chore(git): revert a patch that doesn't work

This reverts commit 45f2c6a6c2.

We will use type casting

* feat: `engines.runtime`

* feat: normalize bin

* fix: `bin === ''`

* test: fix

* refactor: inference friendly

* feat: `peerDependenciesMeta`

* refactor: group into a directory

* refactor: use `ramda.pipe`

* refactor: less intrusive type assertion

* feat!: returning `ExportedManifest`

* refactor: remove unnecessary file

* docs: add a todo

* refactor: getNetworkConfigs (#10458)

Some tests are added as a bonus

* feat: `publishPackedPkg` (wip)

* feat: replace `\t` with 4 spaces

* fix: newline

* fix: newline

* refactor: extract `FailedToPublishError`

* test: FailedToPublishError

* feat: registryConfigKeys

* feat: `publishPackedPkg` (wip)

* feat(config/getNetworkConfigs): load auth info

* feat(config/getNetworkConfigs): load auth info (#10491)

* feat: `publishPackedPkg` (wip)

* refactor: extract a `static` function

* fix: inheritance, override, and merge

* feat: `executeTokenHelper`

* fix: use the visible `globalWarn`

* feat: add options

* feat: add more options

* docs: more links

* fix: private packages

* fix: --dry-run

* feat: log more things

* fix: name

* fix: tag

* refactor: remove extraneous `assertPublicPackage`

* feat: use `publishPackedPkg` for directories

* refactor: require only necessary fields

* refactor: extractManifestFromPacked

* fix: extractManifestFromPacked

* test: extractManifestFromPacked

* feat: isTarballPath

* feat: use `publishPackedPkg` for tarballs

* style: add an empty line for clarity

* refactor: remove unnecessary works

* feat: --otp

* feat: PNPM_CONFIG_OTP

* feat: oidc

* test: fix name collision

* fix: eslint

* test: disable a false test

* feat: set `provenance`

* docs(todo): auto provenance

* refactor: run oidc in `createPublishOptions`

* fix: correct auth keys for `libnpmpublish`

* docs: changeset

* fix: incorrect `password` field

* fix: typo, grammar

* chore(git): resolve merge conflict ahead of time

In preparation for https://github.com/pnpm/pnpm/pull/10385

* fix: field name

* fix(config): decoding `_password`

* fix: edge case of partial `cert`/`key`

* fix: ensure `registry` always match its config key

* fix: `_password`

* test: correct a name

* test: more specific assertions

* fix: grammar

* docs(changeset): fix grammar

* docs: fix grammar

* fix: clean up after failure

* test: fix windows

* feat(provenance): auto detect

* refactor: consistent name

* fix: correct error names

* refactor: extract the `provenance` code

* feat: show code and body of an error

* refactor: use `encodeURIComponent`

* refactor: rename a type

* refactor: use the try-catch model

* refactor: move `normalizeBinObject`

* refactor: split `oidc` into `idToken` and `authToken`

* refactor: run `next` on `stream`'s `'end'`

* fix: use the correct encoding

* feat: guard against weird names

* test: `transform/engines`

Closes https://github.com/pnpm/pnpm/pull/10599

* test: `transformPeerDependenciesMeta`

Closes https://github.com/pnpm/pnpm/pull/10600

* refactor: dependency inject the `Date` too

* refactor: export an interface

* test: oidc

Closes https://github.com/pnpm/pnpm/pull/10598

* refactor: re-arrange imports

* refactor: remove unnecessary type casts

* refactor: improve test
2026-02-12 21:10:54 +01:00
Brandon Cheng
4c6c26a7e8 fix: disable global virtual store during pnpm deploy (#10577) 2026-02-11 02:19:43 +01:00
Zoltan Kochan
1b4df57a01 feat!: drop Node.js 20 and 21 support (#10569) 2026-02-08 19:16:24 +01:00
Zoltan Kochan
57e99b6996 chore: update pnpm-lock.yaml (#10558)
---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-06 03:28:39 +01:00
Johan Quan Vo
7b1c189f2e feat!: remove deprecated patch options (#10505)
* refactor: remove allowNonAppliedPatches

* refactor: remove ignorePatchFailures

* refactor: remove `strict` field in groupPatchedDependencies

* test: update test failure in package patching

* test: fix

* docs: update changesets

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-01-27 17:08:45 +01:00
Zoltan Kochan
1b1d984eec test: improve publish test isolation 2026-01-18 19:33:34 +01:00
btea
623634537d fix: audit (#10475)
* fix: audit

* fix: update

* fix: update
2026-01-17 12:14:02 +01:00
Zoltan Kochan
a00f9e515c chore: use typescript-go (#10452) 2026-01-14 01:18:13 +01:00
Zoltan Kochan
c5d4d81f56 refactor: rename FilesIndex to FilesMap (#10427) 2026-01-08 18:17:57 +01:00
Zoltan Kochan
8b4bdf9a83 refactor: replace onlyBuiltDependencies and ignoredBuiltDependencies with allowBuilds (#10401) 2026-01-02 23:21:17 +01:00
Zoltan Kochan
cb367b9515 feat!: deprecate old settings that were replaced by allowBuilds (#10382) 2026-01-02 12:22:42 +01:00
Zoltan Kochan
71de2b3f2b feat!: remove use-node-version CLI option and pnpm.executionEnv.nodeVersion manifest field (#10373) 2025-12-27 22:41:53 +01:00