Tamp.Npm.V10 0.2.1

Prefix Reserved
dotnet add package Tamp.Npm.V10 --version 0.2.1
                    
NuGet\Install-Package Tamp.Npm.V10 -Version 0.2.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Tamp.Npm.V10" Version="0.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Tamp.Npm.V10" Version="0.2.1" />
                    
Directory.Packages.props
<PackageReference Include="Tamp.Npm.V10" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Tamp.Npm.V10 --version 0.2.1
                    
#r "nuget: Tamp.Npm.V10, 0.2.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Tamp.Npm.V10@0.2.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Tamp.Npm.V10&version=0.2.1
                    
Install as a Cake Addin
#tool nuget:?package=Tamp.Npm.V10&version=0.2.1
                    
Install as a Cake Tool

Tamp.Npm.V10

Tamp wrapper for the npm CLI (Node 22+ / npm 10+ era). Sibling to Tamp.Yarn.V4 for adopters whose frontend toolchain is npm-based.

Package Status
Tamp.Npm.V10 0.1.0 (initial)

Install

dotnet add package Tamp.Npm.V10

Multi-targets net8 / net9 / net10.

Quick start

using Tamp;
using Tamp.Npm.V10;

class Build : TampBuild
{
    public static int Main(string[] args) => Execute<Build>(args);

    [FromPath("npm")] readonly Tool Npm = null!;

    Target Install => _ => _.Executes(() => Npm.Ci(s => s
        .SetWorkingDirectory(RootDirectory / "frontend")));

    Target Build => _ => _
        .DependsOn(Install)
        .Executes(() => Npm.Run(s => s
            .SetScript("build")
            .SetWorkingDirectory(RootDirectory / "frontend")));

    Target Test => _ => _
        .DependsOn(Install)
        .Executes(() => Npm.Run(s => s
            .SetScript("test")
            .AddScriptArgs("--coverage")
            .SetWorkingDirectory(RootDirectory / "frontend")));
}

Verb surface

Tamp method npm command Notes
Npm.Install(...) npm install [package...] Defaults to --no-fund. Set IgnoreScripts=true for supply-chain safety on CI.
Npm.Ci(...) npm ci The CI-recommended invocation. Defaults: --no-audit, --no-fund.
Npm.Run(...) npm run <script> [-- args...] Forwards extra args after --.
Npm.Publish(...) npm publish Otp is Secret-typed and redacted from logs.
Npm.Audit(...) npm audit [fix] Gating-friendly; supports --audit-level for CI threshold checks.
Npm.SetVersion(...) npm version <ver> --no-git-tag-version --allow-same-version Idempotent (0.2.0+). Stamp package.json from a StampVersion target. Safe to call repeatedly with the same version — no-op succeeds (raw npm version exits 1 on no-op).
Npm.Raw(...) npm <anything> Escape hatch — file a ticket if you reach for it often.

Npm.SetVersion worked example

Target StampVersion => _ => _
    .Before(nameof(BuildFrontend))    // stamp before anything reads the version
    .Description("[Pack] Sync version across every manifest the build embeds")
    .Executes(() =>
    {
        Cargo.SetPackageVersion(ServiceCrate / "Cargo.toml", Version);
        Msix.SetAppxManifestVersion(AppxManifest, Version);
        Npm.SetVersion(NpmBin, Version);
    });

Why Npm.SetVersion exists as a typed verb instead of Npm.Raw(NpmBin, "version", Version): raw npm version exits 1 when package.json is already at the target version, which kills CI retry loops and "rebuild after small change" inner loops. SetVersion always passes --allow-same-version so no-op succeeds, and --no-git-tag-version to keep npm from mid-build commit-tagging.

Auth — private registries

Tamp.Npm.V10 injects an npm-registry auth token via the NPM_TOKEN environment variable on the spawned process (the var the npm CLI's auth path reads). The token is Secret-typed and registered with the runner's redaction table:

[Secret("Internal npm token", EnvironmentVariable = "INTERNAL_NPM_TOKEN")]
readonly Secret NpmToken = null!;

Target Restore => _ => _.Executes(() => Npm.Ci(s => s
    .SetNpmAuthToken(NpmToken)
    .SetWorkingDirectory(RootDirectory / "frontend")));

If your registry needs a .npmrc config beyond the token, drop a file at the project root (or workspace root) — npm picks it up automatically. Tamp doesn't try to manage .npmrc itself.

Windows shim

npm ships as npm.cmd on Windows. The Tamp Tool resolution via [FromPath("npm")] finds the .cmd shim correctly via the standard PATHEXT probe. The npm self-resolution bug (where npm hunts for npm-cli.js in CWD/node_modules/npm/bin/ instead of the install dir) is triggered when the .cmd shim is invoked through bare ProcessStartInfo with UseShellExecute=false — outside Tamp's normal path. The wrapper here uses Tamp's standard CommandPlan invocation which doesn't trigger the bug.

If you do hit it (e.g. invoking npm yourself in custom Executes(Action) code), the fix is Tool.FromPath("npm.cmd") or letting the system PATH resolution find it through cmd /c. The Tamp [FromPath("npm")] attribute does the right thing automatically.

Sibling packages

  • Tamp.Yarn.V4 — Yarn Berry. Same shape, different CLI.
  • Tamp.Turbo.V2 — Turborepo. Pairs with either npm or yarn for monorepo builds.
  • Tamp.Vite.V5 — Vite + Vitest. Common chain: Npm.Ci → Vite.Build → Vite.Test.

Releasing

Releases follow the Tamp dogfood pattern: bump <Version> in Directory.Build.props, tag v<X.Y.Z>, GitHub Actions runs dotnet tamp Ci then dotnet tamp Push.

Settings authoring style

Examples above use the fluent Set*-chain shape. Every wrapper verb also accepts a new XxxSettings { ... } object-init form — both produce identical CommandPlans. The fluent shape stays canonical in docs and the tamp init template; opt into object-init scaffolding via tamp init --settings-style=init.

See Build Script Authoring → Two authoring styles on the wiki for the side-by-side comparison.

License

MIT. See LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.1 93 9/27/2026
0.2.0 136 5/13/2026
0.1.0 120 5/13/2026