Skip to content

prerelease-link.sh: writes one .npmrc at the project root, but repins sub-projects that are independent install roots #325

Description

@dmealing

Found while evaluating 0.24.0-rc.3 in an adopter project.

Summary

link_npm() writes exactly one file — $PROJECT/.npmrc — and unlink strips only that one. But repin_npm() repins every package.json it finds.

In a repo where a sub-directory is its own install root (its own lockfile, not an npm/bun workspace member), that sub-project receives the pre-release pin but no registry configuration. Neither npm nor bun walks up parent directories for .npmrc — they read the current directory and the user-level file — so the sub-project resolves the vendor scope against the public registry and fails.

Observed

Repo with two independent roots (./ and ./<sub>/, each with its own lockfile, no workspaces). After a link that reported success:

$ cd <sub> && bun install
error: No version matching "0.24.0-rc.3" found for specifier "@metaobjectsdev/sdk" (but package exists)
error: @metaobjectsdev/sdk@0.24.0-rc.3 failed to resolve

This is exactly the notarget failure the tooling's docs warn about, reached from the opposite direction: link reports success, and the breakage surfaces only at install time inside the sub-project.

The tell

The check verb already understands sub-projects — it scanned and reported on <sub>/bun.lock. So the detector walks nested install roots while link does not. That asymmetry is the bug in one line.

Relatedly, link dropped only the root lockfile (dropped lockfile(s): bun.lock) and left the sub-project's lockfile in place, so the two roots can disagree about the resolved version.

Suggested fix

Write — and on unlink, strip — a managed .npmrc beside every manifest repin_npm actually changed; or, more conservatively, beside every directory that owns a lockfile. Each needs the same local_exclude treatment. Lockfile dropping should follow the same set.

Workaround for adopters today

After link, hand-create the same managed block in each sub-project root:

# >>> metaobjects prerelease (managed) >>>
@metaobjectsdev:registry=<registry>/api/packages/<owner>/npm/
# <<< metaobjects prerelease (managed) <<<

Note that unlink will not remove these, since it strips only $PROJECT/.npmrc — they must be deleted by hand, or the project keeps pointing at the private registry after unlinking.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions