Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tap-snapshots/test/lib/commands/config.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna
"name": null,
"maxsockets": 15,
"message": "%s",
"min-release-age": null,
"node-gyp": "{CWD}/node_modules/node-gyp/bin/node-gyp.js",
"node-options": null,
"noproxy": [
Expand Down Expand Up @@ -280,6 +281,7 @@ logs-max = 10
; long = false ; overridden by cli
maxsockets = 15
message = "%s"
min-release-age = null
name = null
node-gyp = "{CWD}/node_modules/node-gyp/bin/node-gyp.js"
node-options = null
Expand Down
37 changes: 29 additions & 8 deletions tap-snapshots/test/lib/docs.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ If the requested version is a \`dist-tag\` and the given tag does not pass the
will be used. For example, \`foo@latest\` might install \`foo@1.2\` even though
\`latest\` is \`2.0\`.
This config cannot be used with: \`min-release-age\`
#### \`bin-links\`
Expand Down Expand Up @@ -1121,6 +1121,21 @@ Any "%s" in the message will be replaced with the version number.
#### \`min-release-age\`
* Default: null
* Type: null or Number
If set, npm will build the npm tree such that only versions that were
available more than the given number of days ago will be installed. If there
Copy link
Contributor

@styfle styfle Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you chose "days" instead of "minutes" like pnpm?

https://pnpm.io/supply-chain-security

I was really confused when I tried this config today since the name is nearly identical but the units are different.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because its analog (before) was already a date, and dependabot also uses days for its similar feature.

are no versions available for the current set of dependencies, the command
will error.
This flag is a complement to \`before\`, which accepts an exact date instead
of a relative number of days.
This config cannot be used with: \`before\`
#### \`name\`
* Default: null
Expand Down Expand Up @@ -2318,6 +2333,7 @@ Array [
"name",
"maxsockets",
"message",
"min-release-age",
"node-gyp",
"node-options",
"noproxy",
Expand Down Expand Up @@ -2474,6 +2490,7 @@ Array [
"name",
"maxsockets",
"message",
"min-release-age",
"node-gyp",
"noproxy",
"offline",
Expand Down Expand Up @@ -3475,8 +3492,8 @@ Options:
[--include <prod|dev|optional|peer> [--include <prod|dev|optional|peer> ...]]
[--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only]
[--foreground-scripts] [--ignore-scripts] [--allow-git <all|none|root>]
[--no-audit] [--before <date>] [--no-bin-links] [--no-fund] [--dry-run]
[--cpu <cpu>] [--os <os>] [--libc <libc>]
[--no-audit] [--before <date>|--min-release-age <days>] [--no-bin-links]
[--no-fund] [--dry-run] [--cpu <cpu>] [--os <os>] [--libc <libc>]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[--workspaces] [--include-workspace-root] [--install-links]
Expand Down Expand Up @@ -3507,6 +3524,7 @@ aliases: add, i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall
#### \`allow-git\`
#### \`audit\`
#### \`before\`
#### \`min-release-age\`
#### \`bin-links\`
#### \`fund\`
#### \`dry-run\`
Expand Down Expand Up @@ -3578,8 +3596,8 @@ Options:
[--include <prod|dev|optional|peer> [--include <prod|dev|optional|peer> ...]]
[--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only]
[--foreground-scripts] [--ignore-scripts] [--allow-git <all|none|root>]
[--no-audit] [--before <date>] [--no-bin-links] [--no-fund] [--dry-run]
[--cpu <cpu>] [--os <os>] [--libc <libc>]
[--no-audit] [--before <date>|--min-release-age <days>] [--no-bin-links]
[--no-fund] [--dry-run] [--cpu <cpu>] [--os <os>] [--libc <libc>]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[--workspaces] [--include-workspace-root] [--install-links]
Expand Down Expand Up @@ -3610,6 +3628,7 @@ alias: it
#### \`allow-git\`
#### \`audit\`
#### \`before\`
#### \`min-release-age\`
#### \`bin-links\`
#### \`fund\`
#### \`dry-run\`
Expand Down Expand Up @@ -3858,7 +3877,7 @@ npm outdated [<package-spec> ...]
Options:
[-a|--all] [--json] [-l|--long] [-p|--parseable] [-g|--global]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[--before <date>]
[--before <date>|--min-release-age <days>]
Run "npm help outdated" for more info
Expand All @@ -3873,6 +3892,7 @@ npm outdated [<package-spec> ...]
#### \`global\`
#### \`workspace\`
#### \`before\`
#### \`min-release-age\`
`

exports[`test/lib/docs.js TAP usage owner > must match snapshot 1`] = `
Expand Down Expand Up @@ -4634,8 +4654,8 @@ Options:
[--omit <dev|optional|peer> [--omit <dev|optional|peer> ...]]
[--include <prod|dev|optional|peer> [--include <prod|dev|optional|peer> ...]]
[--strict-peer-deps] [--no-package-lock] [--foreground-scripts]
[--ignore-scripts] [--no-audit] [--before <date>] [--no-bin-links] [--no-fund]
[--dry-run]
[--ignore-scripts] [--no-audit] [--before <date>|--min-release-age <days>]
[--no-bin-links] [--no-fund] [--dry-run]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[--workspaces] [--include-workspace-root] [--install-links]
Expand All @@ -4662,6 +4682,7 @@ aliases: up, upgrade, udpate
#### \`ignore-scripts\`
#### \`audit\`
#### \`before\`
#### \`min-release-age\`
#### \`bin-links\`
#### \`fund\`
#### \`dry-run\`
Expand Down
23 changes: 23 additions & 0 deletions workspaces/config/lib/definitions/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ const definitions = {
default: null,
hint: '<date>',
type: [null, Date],
exclusive: ['min-release-age'],
description: `
If passed to \`npm install\`, will rebuild the npm tree such that only
versions that were available **on or before** the given date are
Expand Down Expand Up @@ -1347,6 +1348,28 @@ const definitions = {
`,
flatten,
}),
'min-release-age': new Definition('min-release-age', {
default: null,
hint: '<days>',
type: [null, Number],
exclusive: ['before'],
description: `
If set, npm will build the npm tree such that only versions that were
available more than the given number of days ago will be installed. If
there are no versions available for the current set of dependencies, the
command will error.
This flag is a complement to \`before\`, which accepts an exact date
instead of a relative number of days.
`,
flatten: (key, obj, flatOptions) => {
if (obj['min-release-age'] !== null) {
flatOptions.before = new Date(Date.now() - (86400000 * obj['min-release-age']))
obj.before = flatOptions.before
delete obj['min-release-age']
}
},
}),
'node-gyp': new Definition('node-gyp', {
default: (() => {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,10 @@ Object {
"message": Array [
Function String(),
],
"min-release-age": Array [
null,
"numeric value",
],
"name": Array [
null,
Function String(),
Expand Down
16 changes: 16 additions & 0 deletions workspaces/config/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1587,3 +1587,19 @@ t.test('abbreviation expansion warnings', async t => {
['warn', 'Expanding --bef to --before. This will stop working in the next major version of npm'],
], 'Warns about expanded abbreviations')
})

t.test('before and min-release-age', async t => {
const path = t.testdir()
const config = new Config({
npmPath: `${path}/npm`,
env: {},
argv: [process.execPath, __filename, '--min-release-age', '30'],
cwd: path,
definitions,
shorthands,
flatten,
})
await config.load()
// Simple gut check to make sure we didn't do + instead of -
t.ok(config.flat.before < Date.now(), 'before date is in the past not the future')
})
Loading