Before fetching package metadata from the registry, stat the local cache
file and send its mtime as an If-Modified-Since header. If the registry
returns 304 Not Modified, read the local cache instead of downloading
the full response body. This saves bandwidth and latency for packages
whose metadata hasn't changed since the last fetch.
Registries that don't support If-Modified-Since simply return 200 as
before, so there is no behavior change for unsupported registries.
- Enable Happy Eyeballs (`autoSelectFamily`) for faster dual-stack (IPv4/IPv6) connection establishment
- Increase keep-alive timeouts (30s idle, 10min max) to reduce connection churn during install
- Set optimized global dispatcher so requests without custom options still benefit
- Pre-allocate `SharedArrayBuffer` for tarball downloads when `Content-Length` is known, avoiding intermediate chunk array and double-copy
Replace node-fetch with native undici for HTTP requests throughout pnpm.
Key changes:
- Replace node-fetch with undici's fetch() and dispatcher system
- Replace @pnpm/network.agent with a new dispatcher module in @pnpm/network.fetch
- Cache dispatchers via LRU cache keyed by connection parameters
- Handle proxies via undici ProxyAgent instead of http/https-proxy-agent
- Convert test mocking from nock to undici MockAgent where applicable
- Add minimatch@9 override to fix ESM incompatibility with brace-expansion
* 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>
* fix(auth-header): decode _password from base64 for default registry auth
* fix(auth): prepend 'Bearer ' to auth token generated by tokenHelper
* test: skip flaky parallel dlx test on Node 25
* fix(auth): improve tokenHelper Bearer prefix with validation and generic scheme detection
- Throw an error when the token helper returns an empty token instead of
producing an invalid "Bearer " header
- Use a generic auth scheme regex instead of hardcoding only Bearer/Basic,
so other schemes (Token, Negotiate, etc.) are preserved as-is
- Add tests for raw token prefixing, existing scheme preservation, and
empty token error
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
* 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>
* 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>
* 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>
* 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>
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.
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
* chore: `package.json` add type field
* chore: add type field to every package.json
* chore: add type field to every package.json
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>