@verdaccio/package-filter 13.1.0 → 13.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +10 -2
  2. package/build/config/parser.js +2 -0
  3. package/build/config/parser.js.map +1 -1
  4. package/build/config/parser.mjs +2 -0
  5. package/build/config/parser.mjs.map +1 -1
  6. package/build/config/types.d.ts +6 -0
  7. package/build/filtering/deprecated.d.ts +6 -0
  8. package/build/filtering/deprecated.js +27 -0
  9. package/build/filtering/deprecated.js.map +1 -0
  10. package/build/filtering/deprecated.mjs +25 -0
  11. package/build/filtering/deprecated.mjs.map +1 -0
  12. package/build/filtering/matcher.d.ts +9 -0
  13. package/build/filtering/matcher.js +12 -0
  14. package/build/filtering/matcher.js.map +1 -1
  15. package/build/filtering/matcher.mjs +12 -1
  16. package/build/filtering/matcher.mjs.map +1 -1
  17. package/build/filtering/packageVersion.d.ts +2 -1
  18. package/build/filtering/packageVersion.js +3 -4
  19. package/build/filtering/packageVersion.js.map +1 -1
  20. package/build/filtering/packageVersion.mjs +4 -5
  21. package/build/filtering/packageVersion.mjs.map +1 -1
  22. package/build/filtering/publishDate.d.ts +2 -2
  23. package/build/filtering/publishDate.js +3 -5
  24. package/build/filtering/publishDate.js.map +1 -1
  25. package/build/filtering/publishDate.mjs +4 -6
  26. package/build/filtering/publishDate.mjs.map +1 -1
  27. package/build/packageFilter.js +12 -4
  28. package/build/packageFilter.js.map +1 -1
  29. package/build/packageFilter.mjs +12 -4
  30. package/build/packageFilter.mjs.map +1 -1
  31. package/build/utils/manifestUtils.js +1 -0
  32. package/build/utils/manifestUtils.js.map +1 -1
  33. package/build/utils/manifestUtils.mjs +1 -1
  34. package/build/utils/manifestUtils.mjs.map +1 -1
  35. package/package.json +8 -8
package/README.md CHANGED
@@ -7,8 +7,6 @@
7
7
  [![Documentation](https://img.shields.io/badge/Help-Verdaccio?style=flat&logo=Verdaccio&label=Verdaccio&color=cd4000)](https://verdaccio.org/docs)
8
8
  [![Discord](https://img.shields.io/badge/Chat-Discord?style=flat&logo=Discord&label=Discord&color=cd4000)](https://discord.com/channels/388674437219745793)
9
9
 
10
- > **Note:** This package is only intended to be used with Verdaccio 6.x.
11
-
12
10
  A built-in Verdaccio filter plugin for controlling which package versions are visible to consumers. It intercepts every manifest response and removes or replaces versions that match configurable rules.
13
11
 
14
12
  ## Use Cases
@@ -69,6 +67,16 @@ filters:
69
67
 
70
68
  When both `minAgeDays` and `dateThreshold` are set, the **earlier** cutoff wins (more versions are filtered).
71
69
 
70
+ ### Exclude Deprecated Versions
71
+
72
+ Hide versions whose metadata contains a non-empty `deprecated` notice.
73
+
74
+ ```yaml
75
+ filters:
76
+ '@verdaccio/package-filter':
77
+ excludeDeprecated: true
78
+ ```
79
+
72
80
  ### Block by Scope
73
81
 
74
82
  Block all packages under a scope.
@@ -43,9 +43,11 @@ function parseConfig(config) {
43
43
  if (isNaN(minAgeDays) || minAgeDays < 0) throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);
44
44
  minAgeMs = minAgeDays * 24 * 60 * 60 * 1e3;
45
45
  }
46
+ const excludeDeprecated = config.excludeDeprecated === true;
46
47
  return {
47
48
  dateThreshold,
48
49
  minAgeMs,
50
+ excludeDeprecated,
49
51
  blockRules: blockMap,
50
52
  allowRules: allowMap
51
53
  };
@@ -1 +1 @@
1
- {"version":3,"file":"parser.js","names":[],"sources":["../../src/config/parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range } from 'semver';\n\nimport type { ConfigRule, ParsedConfig, ParsedRule, PluginConfig } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:config');\n\nfunction parseConfigRules(configRules: ConfigRule[]): Map<string, ParsedRule> {\n const ruleMap = new Map<string, ParsedRule>();\n for (const rule of configRules) {\n if ('scope' in rule && typeof rule.scope === 'string') {\n if (!rule.scope.startsWith('@')) {\n throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);\n }\n\n ruleMap.set(rule.scope, 'scope');\n continue;\n }\n\n if ('package' in rule && !('versions' in rule)) {\n ruleMap.set(rule.package, 'package');\n continue;\n }\n\n if ('package' in rule && 'versions' in rule) {\n const previousConfig = ruleMap.get(rule.package) || { versions: [] };\n\n if (typeof previousConfig === 'string') {\n throw new Error(\n `Package ${rule.package} is already specified by another strict rule ${previousConfig}`\n );\n }\n\n // Merge version ranges of the rules for the same package\n const range = new Range(rule.versions);\n ruleMap.set(rule.package, {\n versions: [...previousConfig.versions, range],\n strategy: rule.strategy ?? 'block',\n });\n\n continue;\n }\n\n throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);\n }\n\n return ruleMap;\n}\n\nexport function parseConfig(config: PluginConfig): ParsedConfig {\n debug('parsing config: %o', config);\n const blockMap = parseConfigRules(config.block ?? []);\n const allowMap = parseConfigRules(config.allow ?? []);\n debug('parsed %d block rules, %d allow rules', blockMap.size, allowMap.size);\n const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;\n if (dateThreshold && isNaN(dateThreshold.getTime())) {\n throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);\n }\n\n const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;\n let minAgeMs: number | null = null;\n if (minAgeDays !== null) {\n if (isNaN(minAgeDays) || minAgeDays < 0) {\n throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);\n }\n\n minAgeMs = minAgeDays * 24 * 60 * 60 * 1000;\n }\n\n return {\n dateThreshold,\n minAgeMs,\n blockRules: blockMap,\n allowRules: allowMap,\n };\n}\n"],"mappings":";;;;;AAKA,IAAM,WAAA,GAAA,MAAA,SAAmB,wCAAwC;AAEjE,SAAS,iBAAiB,aAAoD;CAC5E,MAAM,0BAAU,IAAI,IAAwB;CAC5C,KAAK,MAAM,QAAQ,aAAa;EAC9B,IAAI,WAAW,QAAQ,OAAO,KAAK,UAAU,UAAU;GACrD,IAAI,CAAC,KAAK,MAAM,WAAW,GAAG,GAC5B,MAAM,IAAI,UAAU,yCAAyC,KAAK,OAAO;GAG3E,QAAQ,IAAI,KAAK,OAAO,OAAO;GAC/B;EACF;EAEA,IAAI,aAAa,QAAQ,EAAE,cAAc,OAAO;GAC9C,QAAQ,IAAI,KAAK,SAAS,SAAS;GACnC;EACF;EAEA,IAAI,aAAa,QAAQ,cAAc,MAAM;GAC3C,MAAM,iBAAiB,QAAQ,IAAI,KAAK,OAAO,KAAK,EAAE,UAAU,CAAC,EAAE;GAEnE,IAAI,OAAO,mBAAmB,UAC5B,MAAM,IAAI,MACR,WAAW,KAAK,QAAQ,+CAA+C,gBACzE;GAIF,MAAM,QAAQ,IAAI,OAAA,MAAM,KAAK,QAAQ;GACrC,QAAQ,IAAI,KAAK,SAAS;IACxB,UAAU,CAAC,GAAG,eAAe,UAAU,KAAK;IAC5C,UAAU,KAAK,YAAY;GAC7B,CAAC;GAED;EACF;EAEA,MAAM,IAAI,UAAU,wBAAwB,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG;CAC7E;CAEA,OAAO;AACT;AAEA,SAAgB,YAAY,QAAoC;CAC9D,QAAM,sBAAsB,MAAM;CAClC,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,QAAM,yCAAyC,SAAS,MAAM,SAAS,IAAI;CAC3E,MAAM,gBAAgB,OAAO,gBAAgB,IAAI,KAAK,OAAO,aAAa,IAAI;CAC9E,IAAI,iBAAiB,MAAM,cAAc,QAAQ,CAAC,GAChD,MAAM,IAAI,UAAU,gBAAgB,OAAO,cAAc,gCAAgC;CAG3F,MAAM,aAAa,OAAO,aAAa,OAAO,OAAO,UAAU,IAAI;CACnE,IAAI,WAA0B;CAC9B,IAAI,eAAe,MAAM;EACvB,IAAI,MAAM,UAAU,KAAK,aAAa,GACpC,MAAM,IAAI,UAAU,kBAAkB,OAAO,WAAW,6BAA6B;EAGvF,WAAW,aAAa,KAAK,KAAK,KAAK;CACzC;CAEA,OAAO;EACL;EACA;EACA,YAAY;EACZ,YAAY;CACd;AACF"}
1
+ {"version":3,"file":"parser.js","names":[],"sources":["../../src/config/parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range } from 'semver';\n\nimport type { ConfigRule, ParsedConfig, ParsedRule, PluginConfig } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:config');\n\nfunction parseConfigRules(configRules: ConfigRule[]): Map<string, ParsedRule> {\n const ruleMap = new Map<string, ParsedRule>();\n for (const rule of configRules) {\n if ('scope' in rule && typeof rule.scope === 'string') {\n if (!rule.scope.startsWith('@')) {\n throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);\n }\n\n ruleMap.set(rule.scope, 'scope');\n continue;\n }\n\n if ('package' in rule && !('versions' in rule)) {\n ruleMap.set(rule.package, 'package');\n continue;\n }\n\n if ('package' in rule && 'versions' in rule) {\n const previousConfig = ruleMap.get(rule.package) || { versions: [] };\n\n if (typeof previousConfig === 'string') {\n throw new Error(\n `Package ${rule.package} is already specified by another strict rule ${previousConfig}`\n );\n }\n\n // Merge version ranges of the rules for the same package\n const range = new Range(rule.versions);\n ruleMap.set(rule.package, {\n versions: [...previousConfig.versions, range],\n strategy: rule.strategy ?? 'block',\n });\n\n continue;\n }\n\n throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);\n }\n\n return ruleMap;\n}\n\nexport function parseConfig(config: PluginConfig): ParsedConfig {\n debug('parsing config: %o', config);\n const blockMap = parseConfigRules(config.block ?? []);\n const allowMap = parseConfigRules(config.allow ?? []);\n debug('parsed %d block rules, %d allow rules', blockMap.size, allowMap.size);\n const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;\n if (dateThreshold && isNaN(dateThreshold.getTime())) {\n throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);\n }\n\n const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;\n let minAgeMs: number | null = null;\n if (minAgeDays !== null) {\n if (isNaN(minAgeDays) || minAgeDays < 0) {\n throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);\n }\n\n minAgeMs = minAgeDays * 24 * 60 * 60 * 1000;\n }\n\n const excludeDeprecated = config.excludeDeprecated === true;\n\n return {\n dateThreshold,\n minAgeMs,\n excludeDeprecated,\n blockRules: blockMap,\n allowRules: allowMap,\n };\n}\n"],"mappings":";;;;;AAKA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,wCAAwC;AAEjE,SAAS,iBAAiB,aAAoD;CAC5E,MAAM,0BAAU,IAAI,IAAwB;CAC5C,KAAK,MAAM,QAAQ,aAAa;EAC9B,IAAI,WAAW,QAAQ,OAAO,KAAK,UAAU,UAAU;GACrD,IAAI,CAAC,KAAK,MAAM,WAAW,GAAG,GAC5B,MAAM,IAAI,UAAU,yCAAyC,KAAK,OAAO;GAG3E,QAAQ,IAAI,KAAK,OAAO,OAAO;GAC/B;EACF;EAEA,IAAI,aAAa,QAAQ,EAAE,cAAc,OAAO;GAC9C,QAAQ,IAAI,KAAK,SAAS,SAAS;GACnC;EACF;EAEA,IAAI,aAAa,QAAQ,cAAc,MAAM;GAC3C,MAAM,iBAAiB,QAAQ,IAAI,KAAK,OAAO,KAAK,EAAE,UAAU,CAAC,EAAE;GAEnE,IAAI,OAAO,mBAAmB,UAC5B,MAAM,IAAI,MACR,WAAW,KAAK,QAAQ,+CAA+C,gBACzE;GAIF,MAAM,QAAQ,IAAI,OAAA,MAAM,KAAK,QAAQ;GACrC,QAAQ,IAAI,KAAK,SAAS;IACxB,UAAU,CAAC,GAAG,eAAe,UAAU,KAAK;IAC5C,UAAU,KAAK,YAAY;GAC7B,CAAC;GAED;EACF;EAEA,MAAM,IAAI,UAAU,wBAAwB,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG;CAC7E;CAEA,OAAO;AACT;AAEA,SAAgB,YAAY,QAAoC;CAC9D,QAAM,sBAAsB,MAAM;CAClC,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,QAAM,yCAAyC,SAAS,MAAM,SAAS,IAAI;CAC3E,MAAM,gBAAgB,OAAO,gBAAgB,IAAI,KAAK,OAAO,aAAa,IAAI;CAC9E,IAAI,iBAAiB,MAAM,cAAc,QAAQ,CAAC,GAChD,MAAM,IAAI,UAAU,gBAAgB,OAAO,cAAc,gCAAgC;CAG3F,MAAM,aAAa,OAAO,aAAa,OAAO,OAAO,UAAU,IAAI;CACnE,IAAI,WAA0B;CAC9B,IAAI,eAAe,MAAM;EACvB,IAAI,MAAM,UAAU,KAAK,aAAa,GACpC,MAAM,IAAI,UAAU,kBAAkB,OAAO,WAAW,6BAA6B;EAGvF,WAAW,aAAa,KAAK,KAAK,KAAK;CACzC;CAEA,MAAM,oBAAoB,OAAO,sBAAsB;CAEvD,OAAO;EACL;EACA;EACA;EACA,YAAY;EACZ,YAAY;CACd;AACF"}
@@ -41,9 +41,11 @@ function parseConfig(config) {
41
41
  if (isNaN(minAgeDays) || minAgeDays < 0) throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);
42
42
  minAgeMs = minAgeDays * 24 * 60 * 60 * 1e3;
43
43
  }
44
+ const excludeDeprecated = config.excludeDeprecated === true;
44
45
  return {
45
46
  dateThreshold,
46
47
  minAgeMs,
48
+ excludeDeprecated,
47
49
  blockRules: blockMap,
48
50
  allowRules: allowMap
49
51
  };
@@ -1 +1 @@
1
- {"version":3,"file":"parser.mjs","names":[],"sources":["../../src/config/parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range } from 'semver';\n\nimport type { ConfigRule, ParsedConfig, ParsedRule, PluginConfig } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:config');\n\nfunction parseConfigRules(configRules: ConfigRule[]): Map<string, ParsedRule> {\n const ruleMap = new Map<string, ParsedRule>();\n for (const rule of configRules) {\n if ('scope' in rule && typeof rule.scope === 'string') {\n if (!rule.scope.startsWith('@')) {\n throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);\n }\n\n ruleMap.set(rule.scope, 'scope');\n continue;\n }\n\n if ('package' in rule && !('versions' in rule)) {\n ruleMap.set(rule.package, 'package');\n continue;\n }\n\n if ('package' in rule && 'versions' in rule) {\n const previousConfig = ruleMap.get(rule.package) || { versions: [] };\n\n if (typeof previousConfig === 'string') {\n throw new Error(\n `Package ${rule.package} is already specified by another strict rule ${previousConfig}`\n );\n }\n\n // Merge version ranges of the rules for the same package\n const range = new Range(rule.versions);\n ruleMap.set(rule.package, {\n versions: [...previousConfig.versions, range],\n strategy: rule.strategy ?? 'block',\n });\n\n continue;\n }\n\n throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);\n }\n\n return ruleMap;\n}\n\nexport function parseConfig(config: PluginConfig): ParsedConfig {\n debug('parsing config: %o', config);\n const blockMap = parseConfigRules(config.block ?? []);\n const allowMap = parseConfigRules(config.allow ?? []);\n debug('parsed %d block rules, %d allow rules', blockMap.size, allowMap.size);\n const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;\n if (dateThreshold && isNaN(dateThreshold.getTime())) {\n throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);\n }\n\n const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;\n let minAgeMs: number | null = null;\n if (minAgeDays !== null) {\n if (isNaN(minAgeDays) || minAgeDays < 0) {\n throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);\n }\n\n minAgeMs = minAgeDays * 24 * 60 * 60 * 1000;\n }\n\n return {\n dateThreshold,\n minAgeMs,\n blockRules: blockMap,\n allowRules: allowMap,\n };\n}\n"],"mappings":";;;AAKA,IAAM,QAAQ,WAAW,wCAAwC;AAEjE,SAAS,iBAAiB,aAAoD;CAC5E,MAAM,0BAAU,IAAI,IAAwB;CAC5C,KAAK,MAAM,QAAQ,aAAa;EAC9B,IAAI,WAAW,QAAQ,OAAO,KAAK,UAAU,UAAU;GACrD,IAAI,CAAC,KAAK,MAAM,WAAW,GAAG,GAC5B,MAAM,IAAI,UAAU,yCAAyC,KAAK,OAAO;GAG3E,QAAQ,IAAI,KAAK,OAAO,OAAO;GAC/B;EACF;EAEA,IAAI,aAAa,QAAQ,EAAE,cAAc,OAAO;GAC9C,QAAQ,IAAI,KAAK,SAAS,SAAS;GACnC;EACF;EAEA,IAAI,aAAa,QAAQ,cAAc,MAAM;GAC3C,MAAM,iBAAiB,QAAQ,IAAI,KAAK,OAAO,KAAK,EAAE,UAAU,CAAC,EAAE;GAEnE,IAAI,OAAO,mBAAmB,UAC5B,MAAM,IAAI,MACR,WAAW,KAAK,QAAQ,+CAA+C,gBACzE;GAIF,MAAM,QAAQ,IAAI,MAAM,KAAK,QAAQ;GACrC,QAAQ,IAAI,KAAK,SAAS;IACxB,UAAU,CAAC,GAAG,eAAe,UAAU,KAAK;IAC5C,UAAU,KAAK,YAAY;GAC7B,CAAC;GAED;EACF;EAEA,MAAM,IAAI,UAAU,wBAAwB,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG;CAC7E;CAEA,OAAO;AACT;AAEA,SAAgB,YAAY,QAAoC;CAC9D,MAAM,sBAAsB,MAAM;CAClC,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,MAAM,yCAAyC,SAAS,MAAM,SAAS,IAAI;CAC3E,MAAM,gBAAgB,OAAO,gBAAgB,IAAI,KAAK,OAAO,aAAa,IAAI;CAC9E,IAAI,iBAAiB,MAAM,cAAc,QAAQ,CAAC,GAChD,MAAM,IAAI,UAAU,gBAAgB,OAAO,cAAc,gCAAgC;CAG3F,MAAM,aAAa,OAAO,aAAa,OAAO,OAAO,UAAU,IAAI;CACnE,IAAI,WAA0B;CAC9B,IAAI,eAAe,MAAM;EACvB,IAAI,MAAM,UAAU,KAAK,aAAa,GACpC,MAAM,IAAI,UAAU,kBAAkB,OAAO,WAAW,6BAA6B;EAGvF,WAAW,aAAa,KAAK,KAAK,KAAK;CACzC;CAEA,OAAO;EACL;EACA;EACA,YAAY;EACZ,YAAY;CACd;AACF"}
1
+ {"version":3,"file":"parser.mjs","names":[],"sources":["../../src/config/parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range } from 'semver';\n\nimport type { ConfigRule, ParsedConfig, ParsedRule, PluginConfig } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:config');\n\nfunction parseConfigRules(configRules: ConfigRule[]): Map<string, ParsedRule> {\n const ruleMap = new Map<string, ParsedRule>();\n for (const rule of configRules) {\n if ('scope' in rule && typeof rule.scope === 'string') {\n if (!rule.scope.startsWith('@')) {\n throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);\n }\n\n ruleMap.set(rule.scope, 'scope');\n continue;\n }\n\n if ('package' in rule && !('versions' in rule)) {\n ruleMap.set(rule.package, 'package');\n continue;\n }\n\n if ('package' in rule && 'versions' in rule) {\n const previousConfig = ruleMap.get(rule.package) || { versions: [] };\n\n if (typeof previousConfig === 'string') {\n throw new Error(\n `Package ${rule.package} is already specified by another strict rule ${previousConfig}`\n );\n }\n\n // Merge version ranges of the rules for the same package\n const range = new Range(rule.versions);\n ruleMap.set(rule.package, {\n versions: [...previousConfig.versions, range],\n strategy: rule.strategy ?? 'block',\n });\n\n continue;\n }\n\n throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);\n }\n\n return ruleMap;\n}\n\nexport function parseConfig(config: PluginConfig): ParsedConfig {\n debug('parsing config: %o', config);\n const blockMap = parseConfigRules(config.block ?? []);\n const allowMap = parseConfigRules(config.allow ?? []);\n debug('parsed %d block rules, %d allow rules', blockMap.size, allowMap.size);\n const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;\n if (dateThreshold && isNaN(dateThreshold.getTime())) {\n throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);\n }\n\n const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;\n let minAgeMs: number | null = null;\n if (minAgeDays !== null) {\n if (isNaN(minAgeDays) || minAgeDays < 0) {\n throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);\n }\n\n minAgeMs = minAgeDays * 24 * 60 * 60 * 1000;\n }\n\n const excludeDeprecated = config.excludeDeprecated === true;\n\n return {\n dateThreshold,\n minAgeMs,\n excludeDeprecated,\n blockRules: blockMap,\n allowRules: allowMap,\n };\n}\n"],"mappings":";;;AAKA,IAAM,QAAQ,WAAW,wCAAwC;AAEjE,SAAS,iBAAiB,aAAoD;CAC5E,MAAM,0BAAU,IAAI,IAAwB;CAC5C,KAAK,MAAM,QAAQ,aAAa;EAC9B,IAAI,WAAW,QAAQ,OAAO,KAAK,UAAU,UAAU;GACrD,IAAI,CAAC,KAAK,MAAM,WAAW,GAAG,GAC5B,MAAM,IAAI,UAAU,yCAAyC,KAAK,OAAO;GAG3E,QAAQ,IAAI,KAAK,OAAO,OAAO;GAC/B;EACF;EAEA,IAAI,aAAa,QAAQ,EAAE,cAAc,OAAO;GAC9C,QAAQ,IAAI,KAAK,SAAS,SAAS;GACnC;EACF;EAEA,IAAI,aAAa,QAAQ,cAAc,MAAM;GAC3C,MAAM,iBAAiB,QAAQ,IAAI,KAAK,OAAO,KAAK,EAAE,UAAU,CAAC,EAAE;GAEnE,IAAI,OAAO,mBAAmB,UAC5B,MAAM,IAAI,MACR,WAAW,KAAK,QAAQ,+CAA+C,gBACzE;GAIF,MAAM,QAAQ,IAAI,MAAM,KAAK,QAAQ;GACrC,QAAQ,IAAI,KAAK,SAAS;IACxB,UAAU,CAAC,GAAG,eAAe,UAAU,KAAK;IAC5C,UAAU,KAAK,YAAY;GAC7B,CAAC;GAED;EACF;EAEA,MAAM,IAAI,UAAU,wBAAwB,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG;CAC7E;CAEA,OAAO;AACT;AAEA,SAAgB,YAAY,QAAoC;CAC9D,MAAM,sBAAsB,MAAM;CAClC,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,MAAM,yCAAyC,SAAS,MAAM,SAAS,IAAI;CAC3E,MAAM,gBAAgB,OAAO,gBAAgB,IAAI,KAAK,OAAO,aAAa,IAAI;CAC9E,IAAI,iBAAiB,MAAM,cAAc,QAAQ,CAAC,GAChD,MAAM,IAAI,UAAU,gBAAgB,OAAO,cAAc,gCAAgC;CAG3F,MAAM,aAAa,OAAO,aAAa,OAAO,OAAO,UAAU,IAAI;CACnE,IAAI,WAA0B;CAC9B,IAAI,eAAe,MAAM;EACvB,IAAI,MAAM,UAAU,KAAK,aAAa,GACpC,MAAM,IAAI,UAAU,kBAAkB,OAAO,WAAW,6BAA6B;EAGvF,WAAW,aAAa,KAAK,KAAK,KAAK;CACzC;CAEA,MAAM,oBAAoB,OAAO,sBAAsB;CAEvD,OAAO;EACL;EACA;EACA;EACA,YAAY;EACZ,YAAY;CACd;AACF"}
@@ -22,6 +22,11 @@ export interface PluginConfig {
22
22
  * the earlier (more restrictive) date wins.
23
23
  */
24
24
  minAgeDays?: number;
25
+ /**
26
+ * When true, versions whose metadata contains a deprecation notice
27
+ * will be removed from the manifest.
28
+ */
29
+ excludeDeprecated?: boolean;
25
30
  block?: ConfigRule[];
26
31
  allow?: ConfigRule[];
27
32
  }
@@ -34,6 +39,7 @@ export type ParsedRule = ParsedConfigRule | PackageScopeLevel;
34
39
  export interface ParsedConfig {
35
40
  dateThreshold: Date | null;
36
41
  minAgeMs: number | null;
42
+ excludeDeprecated: boolean;
37
43
  blockRules: Map<string, ParsedRule>;
38
44
  allowRules: Map<string, ParsedRule>;
39
45
  }
@@ -0,0 +1,6 @@
1
+ import type { Manifest } from '@verdaccio/types';
2
+ import type { MatchResult } from './types';
3
+ /**
4
+ * Filter out all package versions that have a deprecation notice.
5
+ */
6
+ export declare function filterDeprecatedVersions(manifest: Manifest, allowMatch: MatchResult | undefined): Manifest;
@@ -0,0 +1,27 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.js");
2
+ const require_matcher = require("./matcher.js");
3
+ let debug = require("debug");
4
+ debug = require_runtime.__toESM(debug);
5
+ //#region src/filtering/deprecated.ts
6
+ var debug$1 = (0, debug.default)("verdaccio:plugin:package-filter:filter");
7
+ /**
8
+ * Filter out all package versions that have a deprecation notice.
9
+ */
10
+ function filterDeprecatedVersions(manifest, allowMatch) {
11
+ const { allowAll, whitelistedVersions } = require_matcher.resolveAllowList(allowMatch);
12
+ if (allowAll) return manifest;
13
+ const removedVersions = [];
14
+ Object.entries(manifest.versions).forEach(([version, versionData]) => {
15
+ if (whitelistedVersions.includes(version)) return;
16
+ if (typeof versionData.deprecated === "string" && versionData.deprecated.length > 0) {
17
+ removedVersions.push(version);
18
+ delete manifest.versions[version];
19
+ }
20
+ });
21
+ if (removedVersions.length > 0) debug$1("deprecated filter removed %d versions from %s: %o", removedVersions.length, manifest.name, removedVersions);
22
+ return manifest;
23
+ }
24
+ //#endregion
25
+ exports.filterDeprecatedVersions = filterDeprecatedVersions;
26
+
27
+ //# sourceMappingURL=deprecated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deprecated.js","names":[],"sources":["../../src/filtering/deprecated.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport { resolveAllowList } from './matcher';\nimport type { MatchResult } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all package versions that have a deprecation notice.\n */\nexport function filterDeprecatedVersions(\n manifest: Manifest,\n allowMatch: MatchResult | undefined\n): Manifest {\n const { allowAll, whitelistedVersions } = resolveAllowList(allowMatch);\n if (allowAll) {\n return manifest;\n }\n\n const removedVersions: string[] = [];\n\n Object.entries(manifest.versions).forEach(([version, versionData]) => {\n if (whitelistedVersions.includes(version)) {\n return;\n }\n\n if (typeof versionData.deprecated === 'string' && versionData.deprecated.length > 0) {\n removedVersions.push(version);\n delete manifest.versions[version];\n }\n });\n\n if (removedVersions.length > 0) {\n debug(\n 'deprecated filter removed %d versions from %s: %o',\n removedVersions.length,\n manifest.name,\n removedVersions\n );\n }\n\n return manifest;\n}\n"],"mappings":";;;;;AAOA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,wCAAwC;;;;AAKjE,SAAgB,yBACd,UACA,YACU;CACV,MAAM,EAAE,UAAU,wBAAwB,gBAAA,iBAAiB,UAAU;CACrE,IAAI,UACF,OAAO;CAGT,MAAM,kBAA4B,CAAC;CAEnC,OAAO,QAAQ,SAAS,QAAQ,CAAC,CAAC,SAAS,CAAC,SAAS,iBAAiB;EACpE,IAAI,oBAAoB,SAAS,OAAO,GACtC;EAGF,IAAI,OAAO,YAAY,eAAe,YAAY,YAAY,WAAW,SAAS,GAAG;GACnF,gBAAgB,KAAK,OAAO;GAC5B,OAAO,SAAS,SAAS;EAC3B;CACF,CAAC;CAED,IAAI,gBAAgB,SAAS,GAC3B,QACE,qDACA,gBAAgB,QAChB,SAAS,MACT,eACF;CAGF,OAAO;AACT"}
@@ -0,0 +1,25 @@
1
+ import { resolveAllowList } from "./matcher.mjs";
2
+ import buildDebug from "debug";
3
+ //#region src/filtering/deprecated.ts
4
+ var debug = buildDebug("verdaccio:plugin:package-filter:filter");
5
+ /**
6
+ * Filter out all package versions that have a deprecation notice.
7
+ */
8
+ function filterDeprecatedVersions(manifest, allowMatch) {
9
+ const { allowAll, whitelistedVersions } = resolveAllowList(allowMatch);
10
+ if (allowAll) return manifest;
11
+ const removedVersions = [];
12
+ Object.entries(manifest.versions).forEach(([version, versionData]) => {
13
+ if (whitelistedVersions.includes(version)) return;
14
+ if (typeof versionData.deprecated === "string" && versionData.deprecated.length > 0) {
15
+ removedVersions.push(version);
16
+ delete manifest.versions[version];
17
+ }
18
+ });
19
+ if (removedVersions.length > 0) debug("deprecated filter removed %d versions from %s: %o", removedVersions.length, manifest.name, removedVersions);
20
+ return manifest;
21
+ }
22
+ //#endregion
23
+ export { filterDeprecatedVersions };
24
+
25
+ //# sourceMappingURL=deprecated.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deprecated.mjs","names":[],"sources":["../../src/filtering/deprecated.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport { resolveAllowList } from './matcher';\nimport type { MatchResult } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all package versions that have a deprecation notice.\n */\nexport function filterDeprecatedVersions(\n manifest: Manifest,\n allowMatch: MatchResult | undefined\n): Manifest {\n const { allowAll, whitelistedVersions } = resolveAllowList(allowMatch);\n if (allowAll) {\n return manifest;\n }\n\n const removedVersions: string[] = [];\n\n Object.entries(manifest.versions).forEach(([version, versionData]) => {\n if (whitelistedVersions.includes(version)) {\n return;\n }\n\n if (typeof versionData.deprecated === 'string' && versionData.deprecated.length > 0) {\n removedVersions.push(version);\n delete manifest.versions[version];\n }\n });\n\n if (removedVersions.length > 0) {\n debug(\n 'deprecated filter removed %d versions from %s: %o',\n removedVersions.length,\n manifest.name,\n removedVersions\n );\n }\n\n return manifest;\n}\n"],"mappings":";;;AAOA,IAAM,QAAQ,WAAW,wCAAwC;;;;AAKjE,SAAgB,yBACd,UACA,YACU;CACV,MAAM,EAAE,UAAU,wBAAwB,iBAAiB,UAAU;CACrE,IAAI,UACF,OAAO;CAGT,MAAM,kBAA4B,CAAC;CAEnC,OAAO,QAAQ,SAAS,QAAQ,CAAC,CAAC,SAAS,CAAC,SAAS,iBAAiB;EACpE,IAAI,oBAAoB,SAAS,OAAO,GACtC;EAGF,IAAI,OAAO,YAAY,eAAe,YAAY,YAAY,WAAW,SAAS,GAAG;GACnF,gBAAgB,KAAK,OAAO;GAC5B,OAAO,SAAS,SAAS;EAC3B;CACF,CAAC;CAED,IAAI,gBAAgB,SAAS,GAC3B,MACE,qDACA,gBAAgB,QAChB,SAAS,MACT,eACF;CAGF,OAAO;AACT"}
@@ -6,3 +6,12 @@ import type { MatchResult } from './types';
6
6
  * If found, returns the rule and the matched package versions from the manifest.
7
7
  */
8
8
  export declare function matchRules(manifest: Manifest, rules: Map<string, ParsedRule>): MatchResult | undefined;
9
+ /**
10
+ * Derive the allow-list outcome from a precomputed allow-rule match:
11
+ * whether the whole package/scope is allow-listed, and which versions
12
+ * (if any) are individually whitelisted.
13
+ */
14
+ export declare function resolveAllowList(allowMatch: MatchResult | undefined): {
15
+ allowAll: boolean;
16
+ whitelistedVersions: string[];
17
+ };
@@ -65,7 +65,19 @@ function matchRules(manifest, rules) {
65
65
  versions: matchedVersions
66
66
  };
67
67
  }
68
+ /**
69
+ * Derive the allow-list outcome from a precomputed allow-rule match:
70
+ * whether the whole package/scope is allow-listed, and which versions
71
+ * (if any) are individually whitelisted.
72
+ */
73
+ function resolveAllowList(allowMatch) {
74
+ return {
75
+ allowAll: !!allowMatch && (allowMatch.type === require_types.MatchType.SCOPE || allowMatch.type === require_types.MatchType.PACKAGE),
76
+ whitelistedVersions: allowMatch?.versions ?? []
77
+ };
78
+ }
68
79
  //#endregion
69
80
  exports.matchRules = matchRules;
81
+ exports.resolveAllowList = resolveAllowList;
70
82
 
71
83
  //# sourceMappingURL=matcher.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"matcher.js","names":[],"sources":["../../src/filtering/matcher.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { satisfies } from 'semver';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Split a package name into name itself and scope.\n */\nfunction splitName(name: string): { name: string; scope?: string } {\n if (!name) {\n return { name: '' };\n }\n\n const parts = name.split('/');\n\n if (parts.length > 1) {\n return {\n scope: parts[0],\n name: parts[1],\n };\n } else {\n return {\n name: parts[0],\n };\n }\n}\n\n/**\n * Try to find a rule that matches the package.\n * If found, returns the rule and the matched package versions from the manifest.\n */\nexport function matchRules(\n manifest: Manifest,\n rules: Map<string, ParsedRule>\n): MatchResult | undefined {\n const { scope } = splitName(manifest.name);\n if (scope) {\n const rule = rules.get(scope);\n if (rule === 'scope') {\n debug('scope match: %s matched rule for %s', manifest.name, scope);\n return {\n type: MatchType.SCOPE,\n rule,\n scope,\n versions: Object.keys(manifest.versions),\n };\n }\n }\n\n const rule = rules.get(manifest.name);\n if (!rule) {\n // No match\n return undefined;\n }\n\n if (rule === 'package') {\n debug('package match: %s', manifest.name);\n return {\n type: MatchType.PACKAGE,\n rule,\n package: manifest.name,\n versions: Object.keys(manifest.versions),\n };\n }\n\n if (rule === 'scope') {\n throw new Error('Unexpected case - rule for package should never be \"scope\"');\n }\n\n const versionRanges = rule.versions;\n if (versionRanges.length === 0) {\n // No match\n return undefined;\n }\n\n const matchedVersions: string[] = [];\n Object.keys(manifest.versions).forEach((version) => {\n versionRanges.forEach((versionRange) => {\n if (\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n matchedVersions.push(version);\n }\n });\n });\n\n if (matchedVersions.length > 0) {\n debug(\n 'version match: %s matched %d versions: %o',\n manifest.name,\n matchedVersions.length,\n matchedVersions\n );\n }\n\n return {\n type: MatchType.VERSIONS,\n rule,\n versions: matchedVersions,\n };\n}\n"],"mappings":";;;;;;AASA,IAAM,WAAA,GAAA,MAAA,SAAmB,wCAAwC;;;;AAKjE,SAAS,UAAU,MAAgD;CACjE,IAAI,CAAC,MACH,OAAO,EAAE,MAAM,GAAG;CAGpB,MAAM,QAAQ,KAAK,MAAM,GAAG;CAE5B,IAAI,MAAM,SAAS,GACjB,OAAO;EACL,OAAO,MAAM;EACb,MAAM,MAAM;CACd;MAEA,OAAO,EACL,MAAM,MAAM,GACd;AAEJ;;;;;AAMA,SAAgB,WACd,UACA,OACyB;CACzB,MAAM,EAAE,UAAU,UAAU,SAAS,IAAI;CACzC,IAAI,OAAO;EACT,MAAM,OAAO,MAAM,IAAI,KAAK;EAC5B,IAAI,SAAS,SAAS;GACpB,QAAM,uCAAuC,SAAS,MAAM,KAAK;GACjE,OAAO;IACL,MAAM,cAAA,UAAU;IAChB;IACA;IACA,UAAU,OAAO,KAAK,SAAS,QAAQ;GACzC;EACF;CACF;CAEA,MAAM,OAAO,MAAM,IAAI,SAAS,IAAI;CACpC,IAAI,CAAC,MAEH;CAGF,IAAI,SAAS,WAAW;EACtB,QAAM,qBAAqB,SAAS,IAAI;EACxC,OAAO;GACL,MAAM,cAAA,UAAU;GAChB;GACA,SAAS,SAAS;GAClB,UAAU,OAAO,KAAK,SAAS,QAAQ;EACzC;CACF;CAEA,IAAI,SAAS,SACX,MAAM,IAAI,MAAM,8DAA4D;CAG9E,MAAM,gBAAgB,KAAK;CAC3B,IAAI,cAAc,WAAW,GAE3B;CAGF,MAAM,kBAA4B,CAAC;CACnC,OAAO,KAAK,SAAS,QAAQ,EAAE,SAAS,YAAY;EAClD,cAAc,SAAS,iBAAiB;GACtC,KAAA,GAAA,OAAA,WACY,SAAS,cAAc;IAC/B,mBAAmB;IACnB,OAAO;GACT,CAAC,GAED,gBAAgB,KAAK,OAAO;EAEhC,CAAC;CACH,CAAC;CAED,IAAI,gBAAgB,SAAS,GAC3B,QACE,6CACA,SAAS,MACT,gBAAgB,QAChB,eACF;CAGF,OAAO;EACL,MAAM,cAAA,UAAU;EAChB;EACA,UAAU;CACZ;AACF"}
1
+ {"version":3,"file":"matcher.js","names":[],"sources":["../../src/filtering/matcher.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { satisfies } from 'semver';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Split a package name into name itself and scope.\n */\nfunction splitName(name: string): { name: string; scope?: string } {\n if (!name) {\n return { name: '' };\n }\n\n const parts = name.split('/');\n\n if (parts.length > 1) {\n return {\n scope: parts[0],\n name: parts[1],\n };\n } else {\n return {\n name: parts[0],\n };\n }\n}\n\n/**\n * Try to find a rule that matches the package.\n * If found, returns the rule and the matched package versions from the manifest.\n */\nexport function matchRules(\n manifest: Manifest,\n rules: Map<string, ParsedRule>\n): MatchResult | undefined {\n const { scope } = splitName(manifest.name);\n if (scope) {\n const rule = rules.get(scope);\n if (rule === 'scope') {\n debug('scope match: %s matched rule for %s', manifest.name, scope);\n return {\n type: MatchType.SCOPE,\n rule,\n scope,\n versions: Object.keys(manifest.versions),\n };\n }\n }\n\n const rule = rules.get(manifest.name);\n if (!rule) {\n // No match\n return undefined;\n }\n\n if (rule === 'package') {\n debug('package match: %s', manifest.name);\n return {\n type: MatchType.PACKAGE,\n rule,\n package: manifest.name,\n versions: Object.keys(manifest.versions),\n };\n }\n\n if (rule === 'scope') {\n throw new Error('Unexpected case - rule for package should never be \"scope\"');\n }\n\n const versionRanges = rule.versions;\n if (versionRanges.length === 0) {\n // No match\n return undefined;\n }\n\n const matchedVersions: string[] = [];\n Object.keys(manifest.versions).forEach((version) => {\n versionRanges.forEach((versionRange) => {\n if (\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n matchedVersions.push(version);\n }\n });\n });\n\n if (matchedVersions.length > 0) {\n debug(\n 'version match: %s matched %d versions: %o',\n manifest.name,\n matchedVersions.length,\n matchedVersions\n );\n }\n\n return {\n type: MatchType.VERSIONS,\n rule,\n versions: matchedVersions,\n };\n}\n\n/**\n * Derive the allow-list outcome from a precomputed allow-rule match:\n * whether the whole package/scope is allow-listed, and which versions\n * (if any) are individually whitelisted.\n */\nexport function resolveAllowList(allowMatch: MatchResult | undefined): {\n allowAll: boolean;\n whitelistedVersions: string[];\n} {\n const allowAll =\n !!allowMatch && (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE);\n return { allowAll, whitelistedVersions: allowMatch?.versions ?? [] };\n}\n"],"mappings":";;;;;;AASA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,wCAAwC;;;;AAKjE,SAAS,UAAU,MAAgD;CACjE,IAAI,CAAC,MACH,OAAO,EAAE,MAAM,GAAG;CAGpB,MAAM,QAAQ,KAAK,MAAM,GAAG;CAE5B,IAAI,MAAM,SAAS,GACjB,OAAO;EACL,OAAO,MAAM;EACb,MAAM,MAAM;CACd;MAEA,OAAO,EACL,MAAM,MAAM,GACd;AAEJ;;;;;AAMA,SAAgB,WACd,UACA,OACyB;CACzB,MAAM,EAAE,UAAU,UAAU,SAAS,IAAI;CACzC,IAAI,OAAO;EACT,MAAM,OAAO,MAAM,IAAI,KAAK;EAC5B,IAAI,SAAS,SAAS;GACpB,QAAM,uCAAuC,SAAS,MAAM,KAAK;GACjE,OAAO;IACL,MAAM,cAAA,UAAU;IAChB;IACA;IACA,UAAU,OAAO,KAAK,SAAS,QAAQ;GACzC;EACF;CACF;CAEA,MAAM,OAAO,MAAM,IAAI,SAAS,IAAI;CACpC,IAAI,CAAC,MAEH;CAGF,IAAI,SAAS,WAAW;EACtB,QAAM,qBAAqB,SAAS,IAAI;EACxC,OAAO;GACL,MAAM,cAAA,UAAU;GAChB;GACA,SAAS,SAAS;GAClB,UAAU,OAAO,KAAK,SAAS,QAAQ;EACzC;CACF;CAEA,IAAI,SAAS,SACX,MAAM,IAAI,MAAM,8DAA4D;CAG9E,MAAM,gBAAgB,KAAK;CAC3B,IAAI,cAAc,WAAW,GAE3B;CAGF,MAAM,kBAA4B,CAAC;CACnC,OAAO,KAAK,SAAS,QAAQ,CAAC,CAAC,SAAS,YAAY;EAClD,cAAc,SAAS,iBAAiB;GACtC,KAAA,GAAA,OAAA,UAAA,CACY,SAAS,cAAc;IAC/B,mBAAmB;IACnB,OAAO;GACT,CAAC,GAED,gBAAgB,KAAK,OAAO;EAEhC,CAAC;CACH,CAAC;CAED,IAAI,gBAAgB,SAAS,GAC3B,QACE,6CACA,SAAS,MACT,gBAAgB,QAChB,eACF;CAGF,OAAO;EACL,MAAM,cAAA,UAAU;EAChB;EACA,UAAU;CACZ;AACF;;;;;;AAOA,SAAgB,iBAAiB,YAG/B;CAGA,OAAO;EAAE,UADP,CAAC,CAAC,eAAe,WAAW,SAAS,cAAA,UAAU,SAAS,WAAW,SAAS,cAAA,UAAU;EACrE,qBAAqB,YAAY,YAAY,CAAC;CAAE;AACrE"}
@@ -63,7 +63,18 @@ function matchRules(manifest, rules) {
63
63
  versions: matchedVersions
64
64
  };
65
65
  }
66
+ /**
67
+ * Derive the allow-list outcome from a precomputed allow-rule match:
68
+ * whether the whole package/scope is allow-listed, and which versions
69
+ * (if any) are individually whitelisted.
70
+ */
71
+ function resolveAllowList(allowMatch) {
72
+ return {
73
+ allowAll: !!allowMatch && (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE),
74
+ whitelistedVersions: allowMatch?.versions ?? []
75
+ };
76
+ }
66
77
  //#endregion
67
- export { matchRules };
78
+ export { matchRules, resolveAllowList };
68
79
 
69
80
  //# sourceMappingURL=matcher.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"matcher.mjs","names":[],"sources":["../../src/filtering/matcher.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { satisfies } from 'semver';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Split a package name into name itself and scope.\n */\nfunction splitName(name: string): { name: string; scope?: string } {\n if (!name) {\n return { name: '' };\n }\n\n const parts = name.split('/');\n\n if (parts.length > 1) {\n return {\n scope: parts[0],\n name: parts[1],\n };\n } else {\n return {\n name: parts[0],\n };\n }\n}\n\n/**\n * Try to find a rule that matches the package.\n * If found, returns the rule and the matched package versions from the manifest.\n */\nexport function matchRules(\n manifest: Manifest,\n rules: Map<string, ParsedRule>\n): MatchResult | undefined {\n const { scope } = splitName(manifest.name);\n if (scope) {\n const rule = rules.get(scope);\n if (rule === 'scope') {\n debug('scope match: %s matched rule for %s', manifest.name, scope);\n return {\n type: MatchType.SCOPE,\n rule,\n scope,\n versions: Object.keys(manifest.versions),\n };\n }\n }\n\n const rule = rules.get(manifest.name);\n if (!rule) {\n // No match\n return undefined;\n }\n\n if (rule === 'package') {\n debug('package match: %s', manifest.name);\n return {\n type: MatchType.PACKAGE,\n rule,\n package: manifest.name,\n versions: Object.keys(manifest.versions),\n };\n }\n\n if (rule === 'scope') {\n throw new Error('Unexpected case - rule for package should never be \"scope\"');\n }\n\n const versionRanges = rule.versions;\n if (versionRanges.length === 0) {\n // No match\n return undefined;\n }\n\n const matchedVersions: string[] = [];\n Object.keys(manifest.versions).forEach((version) => {\n versionRanges.forEach((versionRange) => {\n if (\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n matchedVersions.push(version);\n }\n });\n });\n\n if (matchedVersions.length > 0) {\n debug(\n 'version match: %s matched %d versions: %o',\n manifest.name,\n matchedVersions.length,\n matchedVersions\n );\n }\n\n return {\n type: MatchType.VERSIONS,\n rule,\n versions: matchedVersions,\n };\n}\n"],"mappings":";;;;AASA,IAAM,QAAQ,WAAW,wCAAwC;;;;AAKjE,SAAS,UAAU,MAAgD;CACjE,IAAI,CAAC,MACH,OAAO,EAAE,MAAM,GAAG;CAGpB,MAAM,QAAQ,KAAK,MAAM,GAAG;CAE5B,IAAI,MAAM,SAAS,GACjB,OAAO;EACL,OAAO,MAAM;EACb,MAAM,MAAM;CACd;MAEA,OAAO,EACL,MAAM,MAAM,GACd;AAEJ;;;;;AAMA,SAAgB,WACd,UACA,OACyB;CACzB,MAAM,EAAE,UAAU,UAAU,SAAS,IAAI;CACzC,IAAI,OAAO;EACT,MAAM,OAAO,MAAM,IAAI,KAAK;EAC5B,IAAI,SAAS,SAAS;GACpB,MAAM,uCAAuC,SAAS,MAAM,KAAK;GACjE,OAAO;IACL,MAAM,UAAU;IAChB;IACA;IACA,UAAU,OAAO,KAAK,SAAS,QAAQ;GACzC;EACF;CACF;CAEA,MAAM,OAAO,MAAM,IAAI,SAAS,IAAI;CACpC,IAAI,CAAC,MAEH;CAGF,IAAI,SAAS,WAAW;EACtB,MAAM,qBAAqB,SAAS,IAAI;EACxC,OAAO;GACL,MAAM,UAAU;GAChB;GACA,SAAS,SAAS;GAClB,UAAU,OAAO,KAAK,SAAS,QAAQ;EACzC;CACF;CAEA,IAAI,SAAS,SACX,MAAM,IAAI,MAAM,8DAA4D;CAG9E,MAAM,gBAAgB,KAAK;CAC3B,IAAI,cAAc,WAAW,GAE3B;CAGF,MAAM,kBAA4B,CAAC;CACnC,OAAO,KAAK,SAAS,QAAQ,EAAE,SAAS,YAAY;EAClD,cAAc,SAAS,iBAAiB;GACtC,IACE,UAAU,SAAS,cAAc;IAC/B,mBAAmB;IACnB,OAAO;GACT,CAAC,GAED,gBAAgB,KAAK,OAAO;EAEhC,CAAC;CACH,CAAC;CAED,IAAI,gBAAgB,SAAS,GAC3B,MACE,6CACA,SAAS,MACT,gBAAgB,QAChB,eACF;CAGF,OAAO;EACL,MAAM,UAAU;EAChB;EACA,UAAU;CACZ;AACF"}
1
+ {"version":3,"file":"matcher.mjs","names":[],"sources":["../../src/filtering/matcher.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { satisfies } from 'semver';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Split a package name into name itself and scope.\n */\nfunction splitName(name: string): { name: string; scope?: string } {\n if (!name) {\n return { name: '' };\n }\n\n const parts = name.split('/');\n\n if (parts.length > 1) {\n return {\n scope: parts[0],\n name: parts[1],\n };\n } else {\n return {\n name: parts[0],\n };\n }\n}\n\n/**\n * Try to find a rule that matches the package.\n * If found, returns the rule and the matched package versions from the manifest.\n */\nexport function matchRules(\n manifest: Manifest,\n rules: Map<string, ParsedRule>\n): MatchResult | undefined {\n const { scope } = splitName(manifest.name);\n if (scope) {\n const rule = rules.get(scope);\n if (rule === 'scope') {\n debug('scope match: %s matched rule for %s', manifest.name, scope);\n return {\n type: MatchType.SCOPE,\n rule,\n scope,\n versions: Object.keys(manifest.versions),\n };\n }\n }\n\n const rule = rules.get(manifest.name);\n if (!rule) {\n // No match\n return undefined;\n }\n\n if (rule === 'package') {\n debug('package match: %s', manifest.name);\n return {\n type: MatchType.PACKAGE,\n rule,\n package: manifest.name,\n versions: Object.keys(manifest.versions),\n };\n }\n\n if (rule === 'scope') {\n throw new Error('Unexpected case - rule for package should never be \"scope\"');\n }\n\n const versionRanges = rule.versions;\n if (versionRanges.length === 0) {\n // No match\n return undefined;\n }\n\n const matchedVersions: string[] = [];\n Object.keys(manifest.versions).forEach((version) => {\n versionRanges.forEach((versionRange) => {\n if (\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n matchedVersions.push(version);\n }\n });\n });\n\n if (matchedVersions.length > 0) {\n debug(\n 'version match: %s matched %d versions: %o',\n manifest.name,\n matchedVersions.length,\n matchedVersions\n );\n }\n\n return {\n type: MatchType.VERSIONS,\n rule,\n versions: matchedVersions,\n };\n}\n\n/**\n * Derive the allow-list outcome from a precomputed allow-rule match:\n * whether the whole package/scope is allow-listed, and which versions\n * (if any) are individually whitelisted.\n */\nexport function resolveAllowList(allowMatch: MatchResult | undefined): {\n allowAll: boolean;\n whitelistedVersions: string[];\n} {\n const allowAll =\n !!allowMatch && (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE);\n return { allowAll, whitelistedVersions: allowMatch?.versions ?? [] };\n}\n"],"mappings":";;;;AASA,IAAM,QAAQ,WAAW,wCAAwC;;;;AAKjE,SAAS,UAAU,MAAgD;CACjE,IAAI,CAAC,MACH,OAAO,EAAE,MAAM,GAAG;CAGpB,MAAM,QAAQ,KAAK,MAAM,GAAG;CAE5B,IAAI,MAAM,SAAS,GACjB,OAAO;EACL,OAAO,MAAM;EACb,MAAM,MAAM;CACd;MAEA,OAAO,EACL,MAAM,MAAM,GACd;AAEJ;;;;;AAMA,SAAgB,WACd,UACA,OACyB;CACzB,MAAM,EAAE,UAAU,UAAU,SAAS,IAAI;CACzC,IAAI,OAAO;EACT,MAAM,OAAO,MAAM,IAAI,KAAK;EAC5B,IAAI,SAAS,SAAS;GACpB,MAAM,uCAAuC,SAAS,MAAM,KAAK;GACjE,OAAO;IACL,MAAM,UAAU;IAChB;IACA;IACA,UAAU,OAAO,KAAK,SAAS,QAAQ;GACzC;EACF;CACF;CAEA,MAAM,OAAO,MAAM,IAAI,SAAS,IAAI;CACpC,IAAI,CAAC,MAEH;CAGF,IAAI,SAAS,WAAW;EACtB,MAAM,qBAAqB,SAAS,IAAI;EACxC,OAAO;GACL,MAAM,UAAU;GAChB;GACA,SAAS,SAAS;GAClB,UAAU,OAAO,KAAK,SAAS,QAAQ;EACzC;CACF;CAEA,IAAI,SAAS,SACX,MAAM,IAAI,MAAM,8DAA4D;CAG9E,MAAM,gBAAgB,KAAK;CAC3B,IAAI,cAAc,WAAW,GAE3B;CAGF,MAAM,kBAA4B,CAAC;CACnC,OAAO,KAAK,SAAS,QAAQ,CAAC,CAAC,SAAS,YAAY;EAClD,cAAc,SAAS,iBAAiB;GACtC,IACE,UAAU,SAAS,cAAc;IAC/B,mBAAmB;IACnB,OAAO;GACT,CAAC,GAED,gBAAgB,KAAK,OAAO;EAEhC,CAAC;CACH,CAAC;CAED,IAAI,gBAAgB,SAAS,GAC3B,MACE,6CACA,SAAS,MACT,gBAAgB,QAChB,eACF;CAGF,OAAO;EACL,MAAM,UAAU;EAChB;EACA,UAAU;CACZ;AACF;;;;;;AAOA,SAAgB,iBAAiB,YAG/B;CAGA,OAAO;EAAE,UADP,CAAC,CAAC,eAAe,WAAW,SAAS,UAAU,SAAS,WAAW,SAAS,UAAU;EACrE,qBAAqB,YAAY,YAAY,CAAC;CAAE;AACrE"}
@@ -1,5 +1,6 @@
1
1
  import type { Logger, Manifest } from '@verdaccio/types';
2
2
  import type { ParsedRule } from '../config/types';
3
+ import type { MatchResult } from './types';
3
4
  /**
4
5
  * Filter out all blocked package versions.
5
6
  * If package or scope is blocked, then block all versions.
@@ -17,4 +18,4 @@ import type { ParsedRule } from '../config/types';
17
18
  *
18
19
  * Today the only workaround is using awkward ranges like ">=1.0.0-0 <1.0.0".
19
20
  */
20
- export declare function filterBlockedVersions(manifest: Manifest, blockRules: Map<string, ParsedRule>, allowRules: Map<string, ParsedRule>, logger: Logger): Manifest;
21
+ export declare function filterBlockedVersions(manifest: Manifest, blockRules: Map<string, ParsedRule>, allowMatch: MatchResult | undefined, logger: Logger): Manifest;
@@ -23,9 +23,9 @@ var debug$1 = (0, debug.default)("verdaccio:plugin:package-filter:filter");
23
23
  *
24
24
  * Today the only workaround is using awkward ranges like ">=1.0.0-0 <1.0.0".
25
25
  */
26
- function filterBlockedVersions(manifest, blockRules, allowRules, logger) {
27
- const allowMatch = require_matcher.matchRules(manifest, allowRules);
28
- if (allowMatch && (allowMatch.type === require_types.MatchType.SCOPE || allowMatch.type === require_types.MatchType.PACKAGE)) {
26
+ function filterBlockedVersions(manifest, blockRules, allowMatch, logger) {
27
+ const { allowAll, whitelistedVersions } = require_matcher.resolveAllowList(allowMatch);
28
+ if (allowAll) {
29
29
  logger.trace({ name: manifest.name }, "package @{name} is allow-listed, skipping block rules");
30
30
  return manifest;
31
31
  }
@@ -35,7 +35,6 @@ function filterBlockedVersions(manifest, blockRules, allowRules, logger) {
35
35
  name: manifest.name,
36
36
  type: blockMatch.type
37
37
  }, "block rule matched for @{name} (type: @{type})");
38
- const whitelistedVersions = allowMatch ? allowMatch.versions : [];
39
38
  let blockRule = {
40
39
  versions: [new semver.Range("*")],
41
40
  strategy: "block"
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","names":[],"sources":["../../src/filtering/packageVersion.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range, satisfies } from 'semver';\n\nimport type { Logger, Manifest } from '@verdaccio/types';\n\nimport type { ParsedConfigRule, ParsedRule } from '../config/types';\nimport { matchRules } from './matcher';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all blocked package versions.\n * If package or scope is blocked, then block all versions.\n *\n * TODO: consider adding a `prerelease` filter option to block/allow\n * prerelease versions independently. Currently prereleases are matched by\n * semver ranges with `includePrerelease: true`, but there's no dedicated toggle.\n *\n * Example config (not yet implemented):\n * block:\n * - package: 'foo'\n * prerelease: true # block 1.0.0-beta.1, 2.0.0-rc.1, keep 1.0.0, 2.0.0\n * - package: 'bar'\n * prerelease: false # block 1.0.0, 2.0.0, keep 1.0.0-beta.1\n *\n * Today the only workaround is using awkward ranges like \">=1.0.0-0 <1.0.0\".\n */\nexport function filterBlockedVersions(\n manifest: Manifest,\n blockRules: Map<string, ParsedRule>,\n allowRules: Map<string, ParsedRule>,\n logger: Logger\n): Manifest {\n const allowMatch = matchRules(manifest, allowRules);\n if (\n allowMatch &&\n (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE)\n ) {\n // An entire scope or package is whitelisted\n logger.trace({ name: manifest.name }, 'package @{name} is allow-listed, skipping block rules');\n return manifest;\n }\n\n const blockMatch = matchRules(manifest, blockRules);\n if (!blockMatch) {\n // No rule is blocking this package\n return manifest;\n }\n\n logger.trace(\n { name: manifest.name, type: blockMatch.type },\n 'block rule matched for @{name} (type: @{type})'\n );\n\n const whitelistedVersions: string[] = allowMatch ? allowMatch.versions : [];\n let blockRule: ParsedConfigRule = {\n versions: [new Range('*')],\n strategy: 'block',\n };\n\n if (blockMatch.type === MatchType.SCOPE) {\n if (whitelistedVersions.length === 0) {\n debug('blocking all versions of %s (scope %s blocked)', manifest.name, blockMatch.scope);\n logger.trace(\n { name: manifest.name, scope: blockMatch.scope },\n 'all versions of @{name} blocked (scope @{scope})'\n );\n return {\n ...manifest,\n versions: {},\n readme: `All packages in scope ${blockMatch.scope} are blocked by rule`,\n };\n }\n } else if (blockMatch.type === MatchType.PACKAGE) {\n if (whitelistedVersions.length === 0) {\n debug('blocking all versions of %s (package blocked)', manifest.name);\n logger.trace({ name: manifest.name }, 'all versions of @{name} blocked (package rule)');\n return {\n ...manifest,\n versions: {},\n readme: `All package versions are blocked by rule`,\n };\n }\n } else {\n blockRule = { ...blockRule, ...blockMatch.rule };\n }\n\n const versionRanges = blockRule.versions;\n\n if (blockRule.strategy === 'block') {\n const blockedVersions = blockMatch.versions.filter((v) => !whitelistedVersions.includes(v));\n for (const version of blockedVersions) {\n delete manifest.versions[version];\n }\n\n if (blockedVersions.length > 0) {\n debug(\n 'blocked %d versions of %s: %o',\n blockedVersions.length,\n manifest.name,\n blockedVersions\n );\n logger.trace(\n {\n name: manifest.name,\n count: blockedVersions.length,\n versions: blockedVersions.join(', '),\n },\n '@{count} versions of @{name} blocked: @{versions}'\n );\n // Add debug info for devs\n manifest.readme =\n (manifest.readme || '') +\n `\\nSome versions(${blockedVersions.length}) of package are blocked by rules: ${versionRanges.map(\n (range) => range.raw\n )}`;\n }\n\n return manifest;\n }\n\n // Process block rule strategy 'replace'.\n // We assume that the order of versions is already sorted.\n const nonBlockedVersions = { ...manifest.versions };\n const newVersionsMapping: Record<string, string | null> = {};\n\n versionRanges.forEach((versionRange) => {\n const allVersions = Object.keys(nonBlockedVersions);\n\n let lastNonBlockedVersion: string | null = null;\n\n allVersions.forEach((version) => {\n if (\n !whitelistedVersions.includes(version) &&\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n delete nonBlockedVersions[version];\n newVersionsMapping[version] = lastNonBlockedVersion;\n } else {\n lastNonBlockedVersion = version;\n }\n });\n });\n\n debug('replacing versions for %s: %o', manifest.name, newVersionsMapping);\n\n const removedVersions = Object.entries(newVersionsMapping).filter(\n ([_, replace]) => replace === null\n ) as [string, null][];\n const replacedVersions = Object.entries(newVersionsMapping).filter(\n ([_, replace]) => replace !== null\n ) as [string, string][];\n\n removedVersions.forEach(([version]) => {\n debug('no version to replace %s in %s', version, manifest.name);\n logger.trace(\n { name: manifest.name, version },\n 'version @{version} of @{name} removed (no replacement available)'\n );\n delete manifest.versions[version];\n });\n\n replacedVersions.forEach(([version, replaceVersion]) => {\n logger.trace(\n { name: manifest.name, version, replaceVersion },\n 'version @{version} of @{name} replaced with @{replaceVersion}'\n );\n manifest.versions[version] = {\n ...manifest.versions[replaceVersion],\n version,\n };\n });\n\n if (removedVersions.length > 0) {\n manifest.readme +=\n `\\nSome versions of package could not be replaced and thus are fully blocked (${removedVersions.length}):` +\n ` ${removedVersions.map((a) => a[0])}`;\n }\n\n if (replacedVersions.length > 0) {\n manifest.readme +=\n `\\nSome versions of package are replaced by other(${replacedVersions.length}):` +\n ` ${replacedVersions.map((a) => `${a[0]} => ${a[1]}`)}`;\n }\n\n return manifest;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"packageVersion.js","names":[],"sources":["../../src/filtering/packageVersion.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range, satisfies } from 'semver';\n\nimport type { Logger, Manifest } from '@verdaccio/types';\n\nimport type { ParsedConfigRule, ParsedRule } from '../config/types';\nimport { matchRules, resolveAllowList } from './matcher';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all blocked package versions.\n * If package or scope is blocked, then block all versions.\n *\n * TODO: consider adding a `prerelease` filter option to block/allow\n * prerelease versions independently. Currently prereleases are matched by\n * semver ranges with `includePrerelease: true`, but there's no dedicated toggle.\n *\n * Example config (not yet implemented):\n * block:\n * - package: 'foo'\n * prerelease: true # block 1.0.0-beta.1, 2.0.0-rc.1, keep 1.0.0, 2.0.0\n * - package: 'bar'\n * prerelease: false # block 1.0.0, 2.0.0, keep 1.0.0-beta.1\n *\n * Today the only workaround is using awkward ranges like \">=1.0.0-0 <1.0.0\".\n */\nexport function filterBlockedVersions(\n manifest: Manifest,\n blockRules: Map<string, ParsedRule>,\n allowMatch: MatchResult | undefined,\n logger: Logger\n): Manifest {\n const { allowAll, whitelistedVersions } = resolveAllowList(allowMatch);\n if (allowAll) {\n // An entire scope or package is whitelisted\n logger.trace({ name: manifest.name }, 'package @{name} is allow-listed, skipping block rules');\n return manifest;\n }\n\n const blockMatch = matchRules(manifest, blockRules);\n if (!blockMatch) {\n // No rule is blocking this package\n return manifest;\n }\n\n logger.trace(\n { name: manifest.name, type: blockMatch.type },\n 'block rule matched for @{name} (type: @{type})'\n );\n\n let blockRule: ParsedConfigRule = {\n versions: [new Range('*')],\n strategy: 'block',\n };\n\n if (blockMatch.type === MatchType.SCOPE) {\n if (whitelistedVersions.length === 0) {\n debug('blocking all versions of %s (scope %s blocked)', manifest.name, blockMatch.scope);\n logger.trace(\n { name: manifest.name, scope: blockMatch.scope },\n 'all versions of @{name} blocked (scope @{scope})'\n );\n return {\n ...manifest,\n versions: {},\n readme: `All packages in scope ${blockMatch.scope} are blocked by rule`,\n };\n }\n } else if (blockMatch.type === MatchType.PACKAGE) {\n if (whitelistedVersions.length === 0) {\n debug('blocking all versions of %s (package blocked)', manifest.name);\n logger.trace({ name: manifest.name }, 'all versions of @{name} blocked (package rule)');\n return {\n ...manifest,\n versions: {},\n readme: `All package versions are blocked by rule`,\n };\n }\n } else {\n blockRule = { ...blockRule, ...blockMatch.rule };\n }\n\n const versionRanges = blockRule.versions;\n\n if (blockRule.strategy === 'block') {\n const blockedVersions = blockMatch.versions.filter((v) => !whitelistedVersions.includes(v));\n for (const version of blockedVersions) {\n delete manifest.versions[version];\n }\n\n if (blockedVersions.length > 0) {\n debug(\n 'blocked %d versions of %s: %o',\n blockedVersions.length,\n manifest.name,\n blockedVersions\n );\n logger.trace(\n {\n name: manifest.name,\n count: blockedVersions.length,\n versions: blockedVersions.join(', '),\n },\n '@{count} versions of @{name} blocked: @{versions}'\n );\n // Add debug info for devs\n manifest.readme =\n (manifest.readme || '') +\n `\\nSome versions(${blockedVersions.length}) of package are blocked by rules: ${versionRanges.map(\n (range) => range.raw\n )}`;\n }\n\n return manifest;\n }\n\n // Process block rule strategy 'replace'.\n // We assume that the order of versions is already sorted.\n const nonBlockedVersions = { ...manifest.versions };\n const newVersionsMapping: Record<string, string | null> = {};\n\n versionRanges.forEach((versionRange) => {\n const allVersions = Object.keys(nonBlockedVersions);\n\n let lastNonBlockedVersion: string | null = null;\n\n allVersions.forEach((version) => {\n if (\n !whitelistedVersions.includes(version) &&\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n delete nonBlockedVersions[version];\n newVersionsMapping[version] = lastNonBlockedVersion;\n } else {\n lastNonBlockedVersion = version;\n }\n });\n });\n\n debug('replacing versions for %s: %o', manifest.name, newVersionsMapping);\n\n const removedVersions = Object.entries(newVersionsMapping).filter(\n ([_, replace]) => replace === null\n ) as [string, null][];\n const replacedVersions = Object.entries(newVersionsMapping).filter(\n ([_, replace]) => replace !== null\n ) as [string, string][];\n\n removedVersions.forEach(([version]) => {\n debug('no version to replace %s in %s', version, manifest.name);\n logger.trace(\n { name: manifest.name, version },\n 'version @{version} of @{name} removed (no replacement available)'\n );\n delete manifest.versions[version];\n });\n\n replacedVersions.forEach(([version, replaceVersion]) => {\n logger.trace(\n { name: manifest.name, version, replaceVersion },\n 'version @{version} of @{name} replaced with @{replaceVersion}'\n );\n manifest.versions[version] = {\n ...manifest.versions[replaceVersion],\n version,\n };\n });\n\n if (removedVersions.length > 0) {\n manifest.readme +=\n `\\nSome versions of package could not be replaced and thus are fully blocked (${removedVersions.length}):` +\n ` ${removedVersions.map((a) => a[0])}`;\n }\n\n if (replacedVersions.length > 0) {\n manifest.readme +=\n `\\nSome versions of package are replaced by other(${replacedVersions.length}):` +\n ` ${replacedVersions.map((a) => `${a[0]} => ${a[1]}`)}`;\n }\n\n return manifest;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { MatchType } from "./types.mjs";
2
- import { matchRules } from "./matcher.mjs";
2
+ import { matchRules, resolveAllowList } from "./matcher.mjs";
3
3
  import buildDebug from "debug";
4
4
  import { Range, satisfies } from "semver";
5
5
  //#region src/filtering/packageVersion.ts
@@ -21,9 +21,9 @@ var debug = buildDebug("verdaccio:plugin:package-filter:filter");
21
21
  *
22
22
  * Today the only workaround is using awkward ranges like ">=1.0.0-0 <1.0.0".
23
23
  */
24
- function filterBlockedVersions(manifest, blockRules, allowRules, logger) {
25
- const allowMatch = matchRules(manifest, allowRules);
26
- if (allowMatch && (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE)) {
24
+ function filterBlockedVersions(manifest, blockRules, allowMatch, logger) {
25
+ const { allowAll, whitelistedVersions } = resolveAllowList(allowMatch);
26
+ if (allowAll) {
27
27
  logger.trace({ name: manifest.name }, "package @{name} is allow-listed, skipping block rules");
28
28
  return manifest;
29
29
  }
@@ -33,7 +33,6 @@ function filterBlockedVersions(manifest, blockRules, allowRules, logger) {
33
33
  name: manifest.name,
34
34
  type: blockMatch.type
35
35
  }, "block rule matched for @{name} (type: @{type})");
36
- const whitelistedVersions = allowMatch ? allowMatch.versions : [];
37
36
  let blockRule = {
38
37
  versions: [new Range("*")],
39
38
  strategy: "block"
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.mjs","names":[],"sources":["../../src/filtering/packageVersion.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range, satisfies } from 'semver';\n\nimport type { Logger, Manifest } from '@verdaccio/types';\n\nimport type { ParsedConfigRule, ParsedRule } from '../config/types';\nimport { matchRules } from './matcher';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all blocked package versions.\n * If package or scope is blocked, then block all versions.\n *\n * TODO: consider adding a `prerelease` filter option to block/allow\n * prerelease versions independently. Currently prereleases are matched by\n * semver ranges with `includePrerelease: true`, but there's no dedicated toggle.\n *\n * Example config (not yet implemented):\n * block:\n * - package: 'foo'\n * prerelease: true # block 1.0.0-beta.1, 2.0.0-rc.1, keep 1.0.0, 2.0.0\n * - package: 'bar'\n * prerelease: false # block 1.0.0, 2.0.0, keep 1.0.0-beta.1\n *\n * Today the only workaround is using awkward ranges like \">=1.0.0-0 <1.0.0\".\n */\nexport function filterBlockedVersions(\n manifest: Manifest,\n blockRules: Map<string, ParsedRule>,\n allowRules: Map<string, ParsedRule>,\n logger: Logger\n): Manifest {\n const allowMatch = matchRules(manifest, allowRules);\n if (\n allowMatch &&\n (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE)\n ) {\n // An entire scope or package is whitelisted\n logger.trace({ name: manifest.name }, 'package @{name} is allow-listed, skipping block rules');\n return manifest;\n }\n\n const blockMatch = matchRules(manifest, blockRules);\n if (!blockMatch) {\n // No rule is blocking this package\n return manifest;\n }\n\n logger.trace(\n { name: manifest.name, type: blockMatch.type },\n 'block rule matched for @{name} (type: @{type})'\n );\n\n const whitelistedVersions: string[] = allowMatch ? allowMatch.versions : [];\n let blockRule: ParsedConfigRule = {\n versions: [new Range('*')],\n strategy: 'block',\n };\n\n if (blockMatch.type === MatchType.SCOPE) {\n if (whitelistedVersions.length === 0) {\n debug('blocking all versions of %s (scope %s blocked)', manifest.name, blockMatch.scope);\n logger.trace(\n { name: manifest.name, scope: blockMatch.scope },\n 'all versions of @{name} blocked (scope @{scope})'\n );\n return {\n ...manifest,\n versions: {},\n readme: `All packages in scope ${blockMatch.scope} are blocked by rule`,\n };\n }\n } else if (blockMatch.type === MatchType.PACKAGE) {\n if (whitelistedVersions.length === 0) {\n debug('blocking all versions of %s (package blocked)', manifest.name);\n logger.trace({ name: manifest.name }, 'all versions of @{name} blocked (package rule)');\n return {\n ...manifest,\n versions: {},\n readme: `All package versions are blocked by rule`,\n };\n }\n } else {\n blockRule = { ...blockRule, ...blockMatch.rule };\n }\n\n const versionRanges = blockRule.versions;\n\n if (blockRule.strategy === 'block') {\n const blockedVersions = blockMatch.versions.filter((v) => !whitelistedVersions.includes(v));\n for (const version of blockedVersions) {\n delete manifest.versions[version];\n }\n\n if (blockedVersions.length > 0) {\n debug(\n 'blocked %d versions of %s: %o',\n blockedVersions.length,\n manifest.name,\n blockedVersions\n );\n logger.trace(\n {\n name: manifest.name,\n count: blockedVersions.length,\n versions: blockedVersions.join(', '),\n },\n '@{count} versions of @{name} blocked: @{versions}'\n );\n // Add debug info for devs\n manifest.readme =\n (manifest.readme || '') +\n `\\nSome versions(${blockedVersions.length}) of package are blocked by rules: ${versionRanges.map(\n (range) => range.raw\n )}`;\n }\n\n return manifest;\n }\n\n // Process block rule strategy 'replace'.\n // We assume that the order of versions is already sorted.\n const nonBlockedVersions = { ...manifest.versions };\n const newVersionsMapping: Record<string, string | null> = {};\n\n versionRanges.forEach((versionRange) => {\n const allVersions = Object.keys(nonBlockedVersions);\n\n let lastNonBlockedVersion: string | null = null;\n\n allVersions.forEach((version) => {\n if (\n !whitelistedVersions.includes(version) &&\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n delete nonBlockedVersions[version];\n newVersionsMapping[version] = lastNonBlockedVersion;\n } else {\n lastNonBlockedVersion = version;\n }\n });\n });\n\n debug('replacing versions for %s: %o', manifest.name, newVersionsMapping);\n\n const removedVersions = Object.entries(newVersionsMapping).filter(\n ([_, replace]) => replace === null\n ) as [string, null][];\n const replacedVersions = Object.entries(newVersionsMapping).filter(\n ([_, replace]) => replace !== null\n ) as [string, string][];\n\n removedVersions.forEach(([version]) => {\n debug('no version to replace %s in %s', version, manifest.name);\n logger.trace(\n { name: manifest.name, version },\n 'version @{version} of @{name} removed (no replacement available)'\n );\n delete manifest.versions[version];\n });\n\n replacedVersions.forEach(([version, replaceVersion]) => {\n logger.trace(\n { name: manifest.name, version, replaceVersion },\n 'version @{version} of @{name} replaced with @{replaceVersion}'\n );\n manifest.versions[version] = {\n ...manifest.versions[replaceVersion],\n version,\n };\n });\n\n if (removedVersions.length > 0) {\n manifest.readme +=\n `\\nSome versions of package could not be replaced and thus are fully blocked (${removedVersions.length}):` +\n ` ${removedVersions.map((a) => a[0])}`;\n }\n\n if (replacedVersions.length > 0) {\n manifest.readme +=\n `\\nSome versions of package are replaced by other(${replacedVersions.length}):` +\n ` ${replacedVersions.map((a) => `${a[0]} => ${a[1]}`)}`;\n }\n\n return manifest;\n}\n"],"mappings":";;;;;AASA,IAAM,QAAQ,WAAW,wCAAwC;;;;;;;;;;;;;;;;;;AAmBjE,SAAgB,sBACd,UACA,YACA,YACA,QACU;CACV,MAAM,aAAa,WAAW,UAAU,UAAU;CAClD,IACE,eACC,WAAW,SAAS,UAAU,SAAS,WAAW,SAAS,UAAU,UACtE;EAEA,OAAO,MAAM,EAAE,MAAM,SAAS,KAAK,GAAG,uDAAuD;EAC7F,OAAO;CACT;CAEA,MAAM,aAAa,WAAW,UAAU,UAAU;CAClD,IAAI,CAAC,YAEH,OAAO;CAGT,OAAO,MACL;EAAE,MAAM,SAAS;EAAM,MAAM,WAAW;CAAK,GAC7C,gDACF;CAEA,MAAM,sBAAgC,aAAa,WAAW,WAAW,CAAC;CAC1E,IAAI,YAA8B;EAChC,UAAU,CAAC,IAAI,MAAM,GAAG,CAAC;EACzB,UAAU;CACZ;CAEA,IAAI,WAAW,SAAS,UAAU;MAC5B,oBAAoB,WAAW,GAAG;GACpC,MAAM,kDAAkD,SAAS,MAAM,WAAW,KAAK;GACvF,OAAO,MACL;IAAE,MAAM,SAAS;IAAM,OAAO,WAAW;GAAM,GAC/C,kDACF;GACA,OAAO;IACL,GAAG;IACH,UAAU,CAAC;IACX,QAAQ,yBAAyB,WAAW,MAAM;GACpD;EACF;QACK,IAAI,WAAW,SAAS,UAAU;MACnC,oBAAoB,WAAW,GAAG;GACpC,MAAM,iDAAiD,SAAS,IAAI;GACpE,OAAO,MAAM,EAAE,MAAM,SAAS,KAAK,GAAG,gDAAgD;GACtF,OAAO;IACL,GAAG;IACH,UAAU,CAAC;IACX,QAAQ;GACV;EACF;QAEA,YAAY;EAAE,GAAG;EAAW,GAAG,WAAW;CAAK;CAGjD,MAAM,gBAAgB,UAAU;CAEhC,IAAI,UAAU,aAAa,SAAS;EAClC,MAAM,kBAAkB,WAAW,SAAS,QAAQ,MAAM,CAAC,oBAAoB,SAAS,CAAC,CAAC;EAC1F,KAAK,MAAM,WAAW,iBACpB,OAAO,SAAS,SAAS;EAG3B,IAAI,gBAAgB,SAAS,GAAG;GAC9B,MACE,iCACA,gBAAgB,QAChB,SAAS,MACT,eACF;GACA,OAAO,MACL;IACE,MAAM,SAAS;IACf,OAAO,gBAAgB;IACvB,UAAU,gBAAgB,KAAK,IAAI;GACrC,GACA,mDACF;GAEA,SAAS,UACN,SAAS,UAAU,MACpB,mBAAmB,gBAAgB,OAAO,qCAAqC,cAAc,KAC1F,UAAU,MAAM,GACnB;EACJ;EAEA,OAAO;CACT;CAIA,MAAM,qBAAqB,EAAE,GAAG,SAAS,SAAS;CAClD,MAAM,qBAAoD,CAAC;CAE3D,cAAc,SAAS,iBAAiB;EACtC,MAAM,cAAc,OAAO,KAAK,kBAAkB;EAElD,IAAI,wBAAuC;EAE3C,YAAY,SAAS,YAAY;GAC/B,IACE,CAAC,oBAAoB,SAAS,OAAO,KACrC,UAAU,SAAS,cAAc;IAC/B,mBAAmB;IACnB,OAAO;GACT,CAAC,GACD;IACA,OAAO,mBAAmB;IAC1B,mBAAmB,WAAW;GAChC,OACE,wBAAwB;EAE5B,CAAC;CACH,CAAC;CAED,MAAM,iCAAiC,SAAS,MAAM,kBAAkB;CAExE,MAAM,kBAAkB,OAAO,QAAQ,kBAAkB,EAAE,QACxD,CAAC,GAAG,aAAa,YAAY,IAChC;CACA,MAAM,mBAAmB,OAAO,QAAQ,kBAAkB,EAAE,QACzD,CAAC,GAAG,aAAa,YAAY,IAChC;CAEA,gBAAgB,SAAS,CAAC,aAAa;EACrC,MAAM,kCAAkC,SAAS,SAAS,IAAI;EAC9D,OAAO,MACL;GAAE,MAAM,SAAS;GAAM;EAAQ,GAC/B,kEACF;EACA,OAAO,SAAS,SAAS;CAC3B,CAAC;CAED,iBAAiB,SAAS,CAAC,SAAS,oBAAoB;EACtD,OAAO,MACL;GAAE,MAAM,SAAS;GAAM;GAAS;EAAe,GAC/C,+DACF;EACA,SAAS,SAAS,WAAW;GAC3B,GAAG,SAAS,SAAS;GACrB;EACF;CACF,CAAC;CAED,IAAI,gBAAgB,SAAS,GAC3B,SAAS,UACP,gFAAgF,gBAAgB,OAAO,KACnG,gBAAgB,KAAK,MAAM,EAAE,EAAE;CAGvC,IAAI,iBAAiB,SAAS,GAC5B,SAAS,UACP,oDAAoD,iBAAiB,OAAO,KACxE,iBAAiB,KAAK,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,IAAI;CAGxD,OAAO;AACT"}
1
+ {"version":3,"file":"packageVersion.mjs","names":[],"sources":["../../src/filtering/packageVersion.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range, satisfies } from 'semver';\n\nimport type { Logger, Manifest } from '@verdaccio/types';\n\nimport type { ParsedConfigRule, ParsedRule } from '../config/types';\nimport { matchRules, resolveAllowList } from './matcher';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all blocked package versions.\n * If package or scope is blocked, then block all versions.\n *\n * TODO: consider adding a `prerelease` filter option to block/allow\n * prerelease versions independently. Currently prereleases are matched by\n * semver ranges with `includePrerelease: true`, but there's no dedicated toggle.\n *\n * Example config (not yet implemented):\n * block:\n * - package: 'foo'\n * prerelease: true # block 1.0.0-beta.1, 2.0.0-rc.1, keep 1.0.0, 2.0.0\n * - package: 'bar'\n * prerelease: false # block 1.0.0, 2.0.0, keep 1.0.0-beta.1\n *\n * Today the only workaround is using awkward ranges like \">=1.0.0-0 <1.0.0\".\n */\nexport function filterBlockedVersions(\n manifest: Manifest,\n blockRules: Map<string, ParsedRule>,\n allowMatch: MatchResult | undefined,\n logger: Logger\n): Manifest {\n const { allowAll, whitelistedVersions } = resolveAllowList(allowMatch);\n if (allowAll) {\n // An entire scope or package is whitelisted\n logger.trace({ name: manifest.name }, 'package @{name} is allow-listed, skipping block rules');\n return manifest;\n }\n\n const blockMatch = matchRules(manifest, blockRules);\n if (!blockMatch) {\n // No rule is blocking this package\n return manifest;\n }\n\n logger.trace(\n { name: manifest.name, type: blockMatch.type },\n 'block rule matched for @{name} (type: @{type})'\n );\n\n let blockRule: ParsedConfigRule = {\n versions: [new Range('*')],\n strategy: 'block',\n };\n\n if (blockMatch.type === MatchType.SCOPE) {\n if (whitelistedVersions.length === 0) {\n debug('blocking all versions of %s (scope %s blocked)', manifest.name, blockMatch.scope);\n logger.trace(\n { name: manifest.name, scope: blockMatch.scope },\n 'all versions of @{name} blocked (scope @{scope})'\n );\n return {\n ...manifest,\n versions: {},\n readme: `All packages in scope ${blockMatch.scope} are blocked by rule`,\n };\n }\n } else if (blockMatch.type === MatchType.PACKAGE) {\n if (whitelistedVersions.length === 0) {\n debug('blocking all versions of %s (package blocked)', manifest.name);\n logger.trace({ name: manifest.name }, 'all versions of @{name} blocked (package rule)');\n return {\n ...manifest,\n versions: {},\n readme: `All package versions are blocked by rule`,\n };\n }\n } else {\n blockRule = { ...blockRule, ...blockMatch.rule };\n }\n\n const versionRanges = blockRule.versions;\n\n if (blockRule.strategy === 'block') {\n const blockedVersions = blockMatch.versions.filter((v) => !whitelistedVersions.includes(v));\n for (const version of blockedVersions) {\n delete manifest.versions[version];\n }\n\n if (blockedVersions.length > 0) {\n debug(\n 'blocked %d versions of %s: %o',\n blockedVersions.length,\n manifest.name,\n blockedVersions\n );\n logger.trace(\n {\n name: manifest.name,\n count: blockedVersions.length,\n versions: blockedVersions.join(', '),\n },\n '@{count} versions of @{name} blocked: @{versions}'\n );\n // Add debug info for devs\n manifest.readme =\n (manifest.readme || '') +\n `\\nSome versions(${blockedVersions.length}) of package are blocked by rules: ${versionRanges.map(\n (range) => range.raw\n )}`;\n }\n\n return manifest;\n }\n\n // Process block rule strategy 'replace'.\n // We assume that the order of versions is already sorted.\n const nonBlockedVersions = { ...manifest.versions };\n const newVersionsMapping: Record<string, string | null> = {};\n\n versionRanges.forEach((versionRange) => {\n const allVersions = Object.keys(nonBlockedVersions);\n\n let lastNonBlockedVersion: string | null = null;\n\n allVersions.forEach((version) => {\n if (\n !whitelistedVersions.includes(version) &&\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n delete nonBlockedVersions[version];\n newVersionsMapping[version] = lastNonBlockedVersion;\n } else {\n lastNonBlockedVersion = version;\n }\n });\n });\n\n debug('replacing versions for %s: %o', manifest.name, newVersionsMapping);\n\n const removedVersions = Object.entries(newVersionsMapping).filter(\n ([_, replace]) => replace === null\n ) as [string, null][];\n const replacedVersions = Object.entries(newVersionsMapping).filter(\n ([_, replace]) => replace !== null\n ) as [string, string][];\n\n removedVersions.forEach(([version]) => {\n debug('no version to replace %s in %s', version, manifest.name);\n logger.trace(\n { name: manifest.name, version },\n 'version @{version} of @{name} removed (no replacement available)'\n );\n delete manifest.versions[version];\n });\n\n replacedVersions.forEach(([version, replaceVersion]) => {\n logger.trace(\n { name: manifest.name, version, replaceVersion },\n 'version @{version} of @{name} replaced with @{replaceVersion}'\n );\n manifest.versions[version] = {\n ...manifest.versions[replaceVersion],\n version,\n };\n });\n\n if (removedVersions.length > 0) {\n manifest.readme +=\n `\\nSome versions of package could not be replaced and thus are fully blocked (${removedVersions.length}):` +\n ` ${removedVersions.map((a) => a[0])}`;\n }\n\n if (replacedVersions.length > 0) {\n manifest.readme +=\n `\\nSome versions of package are replaced by other(${replacedVersions.length}):` +\n ` ${replacedVersions.map((a) => `${a[0]} => ${a[1]}`)}`;\n }\n\n return manifest;\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { Manifest } from '@verdaccio/types';
2
- import type { ParsedRule } from '../config/types';
2
+ import type { MatchResult } from './types';
3
3
  /**
4
4
  * Filter out all package versions that were published after dateThreshold.
5
5
  */
6
- export declare function filterVersionsByPublishDate(manifest: Manifest, dateThreshold: Date, allowRules: Map<string, ParsedRule>): Manifest;
6
+ export declare function filterVersionsByPublishDate(manifest: Manifest, dateThreshold: Date, allowMatch: MatchResult | undefined): Manifest;
@@ -1,5 +1,4 @@
1
1
  const require_runtime = require("../_virtual/_rolldown/runtime.js");
2
- const require_types = require("./types.js");
3
2
  const require_matcher = require("./matcher.js");
4
3
  let debug = require("debug");
5
4
  debug = require_runtime.__toESM(debug);
@@ -8,12 +7,11 @@ var debug$1 = (0, debug.default)("verdaccio:plugin:package-filter:filter");
8
7
  /**
9
8
  * Filter out all package versions that were published after dateThreshold.
10
9
  */
11
- function filterVersionsByPublishDate(manifest, dateThreshold, allowRules) {
12
- const allowMatch = require_matcher.matchRules(manifest, allowRules);
13
- if (allowMatch && (allowMatch.type === require_types.MatchType.SCOPE || allowMatch.type === require_types.MatchType.PACKAGE)) return manifest;
10
+ function filterVersionsByPublishDate(manifest, dateThreshold, allowMatch) {
11
+ const { allowAll, whitelistedVersions } = require_matcher.resolveAllowList(allowMatch);
12
+ if (allowAll) return manifest;
14
13
  const { versions, time, name } = manifest;
15
14
  if (!time) throw new TypeError(`Time of publication was not provided for package ${name}`);
16
- const whitelistedVersions = allowMatch ? allowMatch.versions : [];
17
15
  const clearVersions = [];
18
16
  Object.keys(versions).forEach((version) => {
19
17
  if (whitelistedVersions.includes(version)) return;
@@ -1 +1 @@
1
- {"version":3,"file":"publishDate.js","names":[],"sources":["../../src/filtering/publishDate.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport { matchRules } from './matcher';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all package versions that were published after dateThreshold.\n */\nexport function filterVersionsByPublishDate(\n manifest: Manifest,\n dateThreshold: Date,\n allowRules: Map<string, ParsedRule>\n): Manifest {\n const allowMatch = matchRules(manifest, allowRules);\n if (\n allowMatch &&\n (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE)\n ) {\n // An entire scope or package is whitelisted\n return manifest;\n }\n\n const { versions, time, name } = manifest;\n\n if (!time) {\n throw new TypeError(`Time of publication was not provided for package ${name}`);\n }\n\n const whitelistedVersions: string[] = allowMatch ? allowMatch.versions : [];\n const clearVersions: string[] = [];\n\n Object.keys(versions).forEach((version) => {\n if (whitelistedVersions.includes(version)) {\n return;\n }\n\n const publishTime = time[version];\n\n if (!publishTime) {\n throw new TypeError(\n `Time of publication was not provided for package ${name}, version ${version}`\n );\n }\n\n if (new Date(publishTime) > dateThreshold) {\n // clear untrusted version\n clearVersions.push(version);\n }\n });\n\n // delete version from versions\n clearVersions.forEach((version) => {\n delete manifest.versions[version];\n });\n\n if (clearVersions.length > 0) {\n debug(\n 'date filter removed %d versions from %s: %o',\n clearVersions.length,\n manifest.name,\n clearVersions\n );\n }\n\n return manifest;\n}\n"],"mappings":";;;;;;AAQA,IAAM,WAAA,GAAA,MAAA,SAAmB,wCAAwC;;;;AAKjE,SAAgB,4BACd,UACA,eACA,YACU;CACV,MAAM,aAAa,gBAAA,WAAW,UAAU,UAAU;CAClD,IACE,eACC,WAAW,SAAS,cAAA,UAAU,SAAS,WAAW,SAAS,cAAA,UAAU,UAGtE,OAAO;CAGT,MAAM,EAAE,UAAU,MAAM,SAAS;CAEjC,IAAI,CAAC,MACH,MAAM,IAAI,UAAU,oDAAoD,MAAM;CAGhF,MAAM,sBAAgC,aAAa,WAAW,WAAW,CAAC;CAC1E,MAAM,gBAA0B,CAAC;CAEjC,OAAO,KAAK,QAAQ,EAAE,SAAS,YAAY;EACzC,IAAI,oBAAoB,SAAS,OAAO,GACtC;EAGF,MAAM,cAAc,KAAK;EAEzB,IAAI,CAAC,aACH,MAAM,IAAI,UACR,oDAAoD,KAAK,YAAY,SACvE;EAGF,IAAI,IAAI,KAAK,WAAW,IAAI,eAE1B,cAAc,KAAK,OAAO;CAE9B,CAAC;CAGD,cAAc,SAAS,YAAY;EACjC,OAAO,SAAS,SAAS;CAC3B,CAAC;CAED,IAAI,cAAc,SAAS,GACzB,QACE,+CACA,cAAc,QACd,SAAS,MACT,aACF;CAGF,OAAO;AACT"}
1
+ {"version":3,"file":"publishDate.js","names":[],"sources":["../../src/filtering/publishDate.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport { resolveAllowList } from './matcher';\nimport type { MatchResult } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all package versions that were published after dateThreshold.\n */\nexport function filterVersionsByPublishDate(\n manifest: Manifest,\n dateThreshold: Date,\n allowMatch: MatchResult | undefined\n): Manifest {\n const { allowAll, whitelistedVersions } = resolveAllowList(allowMatch);\n if (allowAll) {\n // An entire scope or package is whitelisted\n return manifest;\n }\n\n const { versions, time, name } = manifest;\n\n if (!time) {\n throw new TypeError(`Time of publication was not provided for package ${name}`);\n }\n\n const clearVersions: string[] = [];\n\n Object.keys(versions).forEach((version) => {\n if (whitelistedVersions.includes(version)) {\n return;\n }\n\n const publishTime = time[version];\n\n if (!publishTime) {\n throw new TypeError(\n `Time of publication was not provided for package ${name}, version ${version}`\n );\n }\n\n if (new Date(publishTime) > dateThreshold) {\n // clear untrusted version\n clearVersions.push(version);\n }\n });\n\n // delete version from versions\n clearVersions.forEach((version) => {\n delete manifest.versions[version];\n });\n\n if (clearVersions.length > 0) {\n debug(\n 'date filter removed %d versions from %s: %o',\n clearVersions.length,\n manifest.name,\n clearVersions\n );\n }\n\n return manifest;\n}\n"],"mappings":";;;;;AAOA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,wCAAwC;;;;AAKjE,SAAgB,4BACd,UACA,eACA,YACU;CACV,MAAM,EAAE,UAAU,wBAAwB,gBAAA,iBAAiB,UAAU;CACrE,IAAI,UAEF,OAAO;CAGT,MAAM,EAAE,UAAU,MAAM,SAAS;CAEjC,IAAI,CAAC,MACH,MAAM,IAAI,UAAU,oDAAoD,MAAM;CAGhF,MAAM,gBAA0B,CAAC;CAEjC,OAAO,KAAK,QAAQ,CAAC,CAAC,SAAS,YAAY;EACzC,IAAI,oBAAoB,SAAS,OAAO,GACtC;EAGF,MAAM,cAAc,KAAK;EAEzB,IAAI,CAAC,aACH,MAAM,IAAI,UACR,oDAAoD,KAAK,YAAY,SACvE;EAGF,IAAI,IAAI,KAAK,WAAW,IAAI,eAE1B,cAAc,KAAK,OAAO;CAE9B,CAAC;CAGD,cAAc,SAAS,YAAY;EACjC,OAAO,SAAS,SAAS;CAC3B,CAAC;CAED,IAAI,cAAc,SAAS,GACzB,QACE,+CACA,cAAc,QACd,SAAS,MACT,aACF;CAGF,OAAO;AACT"}
@@ -1,17 +1,15 @@
1
- import { MatchType } from "./types.mjs";
2
- import { matchRules } from "./matcher.mjs";
1
+ import { resolveAllowList } from "./matcher.mjs";
3
2
  import buildDebug from "debug";
4
3
  //#region src/filtering/publishDate.ts
5
4
  var debug = buildDebug("verdaccio:plugin:package-filter:filter");
6
5
  /**
7
6
  * Filter out all package versions that were published after dateThreshold.
8
7
  */
9
- function filterVersionsByPublishDate(manifest, dateThreshold, allowRules) {
10
- const allowMatch = matchRules(manifest, allowRules);
11
- if (allowMatch && (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE)) return manifest;
8
+ function filterVersionsByPublishDate(manifest, dateThreshold, allowMatch) {
9
+ const { allowAll, whitelistedVersions } = resolveAllowList(allowMatch);
10
+ if (allowAll) return manifest;
12
11
  const { versions, time, name } = manifest;
13
12
  if (!time) throw new TypeError(`Time of publication was not provided for package ${name}`);
14
- const whitelistedVersions = allowMatch ? allowMatch.versions : [];
15
13
  const clearVersions = [];
16
14
  Object.keys(versions).forEach((version) => {
17
15
  if (whitelistedVersions.includes(version)) return;
@@ -1 +1 @@
1
- {"version":3,"file":"publishDate.mjs","names":[],"sources":["../../src/filtering/publishDate.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport { matchRules } from './matcher';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all package versions that were published after dateThreshold.\n */\nexport function filterVersionsByPublishDate(\n manifest: Manifest,\n dateThreshold: Date,\n allowRules: Map<string, ParsedRule>\n): Manifest {\n const allowMatch = matchRules(manifest, allowRules);\n if (\n allowMatch &&\n (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE)\n ) {\n // An entire scope or package is whitelisted\n return manifest;\n }\n\n const { versions, time, name } = manifest;\n\n if (!time) {\n throw new TypeError(`Time of publication was not provided for package ${name}`);\n }\n\n const whitelistedVersions: string[] = allowMatch ? allowMatch.versions : [];\n const clearVersions: string[] = [];\n\n Object.keys(versions).forEach((version) => {\n if (whitelistedVersions.includes(version)) {\n return;\n }\n\n const publishTime = time[version];\n\n if (!publishTime) {\n throw new TypeError(\n `Time of publication was not provided for package ${name}, version ${version}`\n );\n }\n\n if (new Date(publishTime) > dateThreshold) {\n // clear untrusted version\n clearVersions.push(version);\n }\n });\n\n // delete version from versions\n clearVersions.forEach((version) => {\n delete manifest.versions[version];\n });\n\n if (clearVersions.length > 0) {\n debug(\n 'date filter removed %d versions from %s: %o',\n clearVersions.length,\n manifest.name,\n clearVersions\n );\n }\n\n return manifest;\n}\n"],"mappings":";;;;AAQA,IAAM,QAAQ,WAAW,wCAAwC;;;;AAKjE,SAAgB,4BACd,UACA,eACA,YACU;CACV,MAAM,aAAa,WAAW,UAAU,UAAU;CAClD,IACE,eACC,WAAW,SAAS,UAAU,SAAS,WAAW,SAAS,UAAU,UAGtE,OAAO;CAGT,MAAM,EAAE,UAAU,MAAM,SAAS;CAEjC,IAAI,CAAC,MACH,MAAM,IAAI,UAAU,oDAAoD,MAAM;CAGhF,MAAM,sBAAgC,aAAa,WAAW,WAAW,CAAC;CAC1E,MAAM,gBAA0B,CAAC;CAEjC,OAAO,KAAK,QAAQ,EAAE,SAAS,YAAY;EACzC,IAAI,oBAAoB,SAAS,OAAO,GACtC;EAGF,MAAM,cAAc,KAAK;EAEzB,IAAI,CAAC,aACH,MAAM,IAAI,UACR,oDAAoD,KAAK,YAAY,SACvE;EAGF,IAAI,IAAI,KAAK,WAAW,IAAI,eAE1B,cAAc,KAAK,OAAO;CAE9B,CAAC;CAGD,cAAc,SAAS,YAAY;EACjC,OAAO,SAAS,SAAS;CAC3B,CAAC;CAED,IAAI,cAAc,SAAS,GACzB,MACE,+CACA,cAAc,QACd,SAAS,MACT,aACF;CAGF,OAAO;AACT"}
1
+ {"version":3,"file":"publishDate.mjs","names":[],"sources":["../../src/filtering/publishDate.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport { resolveAllowList } from './matcher';\nimport type { MatchResult } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Filter out all package versions that were published after dateThreshold.\n */\nexport function filterVersionsByPublishDate(\n manifest: Manifest,\n dateThreshold: Date,\n allowMatch: MatchResult | undefined\n): Manifest {\n const { allowAll, whitelistedVersions } = resolveAllowList(allowMatch);\n if (allowAll) {\n // An entire scope or package is whitelisted\n return manifest;\n }\n\n const { versions, time, name } = manifest;\n\n if (!time) {\n throw new TypeError(`Time of publication was not provided for package ${name}`);\n }\n\n const clearVersions: string[] = [];\n\n Object.keys(versions).forEach((version) => {\n if (whitelistedVersions.includes(version)) {\n return;\n }\n\n const publishTime = time[version];\n\n if (!publishTime) {\n throw new TypeError(\n `Time of publication was not provided for package ${name}, version ${version}`\n );\n }\n\n if (new Date(publishTime) > dateThreshold) {\n // clear untrusted version\n clearVersions.push(version);\n }\n });\n\n // delete version from versions\n clearVersions.forEach((version) => {\n delete manifest.versions[version];\n });\n\n if (clearVersions.length > 0) {\n debug(\n 'date filter removed %d versions from %s: %o',\n clearVersions.length,\n manifest.name,\n clearVersions\n );\n }\n\n return manifest;\n}\n"],"mappings":";;;AAOA,IAAM,QAAQ,WAAW,wCAAwC;;;;AAKjE,SAAgB,4BACd,UACA,eACA,YACU;CACV,MAAM,EAAE,UAAU,wBAAwB,iBAAiB,UAAU;CACrE,IAAI,UAEF,OAAO;CAGT,MAAM,EAAE,UAAU,MAAM,SAAS;CAEjC,IAAI,CAAC,MACH,MAAM,IAAI,UAAU,oDAAoD,MAAM;CAGhF,MAAM,gBAA0B,CAAC;CAEjC,OAAO,KAAK,QAAQ,CAAC,CAAC,SAAS,YAAY;EACzC,IAAI,oBAAoB,SAAS,OAAO,GACtC;EAGF,MAAM,cAAc,KAAK;EAEzB,IAAI,CAAC,aACH,MAAM,IAAI,UACR,oDAAoD,KAAK,YAAY,SACvE;EAGF,IAAI,IAAI,KAAK,WAAW,IAAI,eAE1B,cAAc,KAAK,OAAO;CAE9B,CAAC;CAGD,cAAc,SAAS,YAAY;EACjC,OAAO,SAAS,SAAS;CAC3B,CAAC;CAED,IAAI,cAAc,SAAS,GACzB,MACE,+CACA,cAAc,QACd,SAAS,MACT,aACF;CAGF,OAAO;AACT"}
@@ -1,5 +1,7 @@
1
1
  const require_runtime = require("./_virtual/_rolldown/runtime.js");
2
2
  const require_parser = require("./config/parser.js");
3
+ const require_matcher = require("./filtering/matcher.js");
4
+ const require_deprecated = require("./filtering/deprecated.js");
3
5
  const require_packageVersion = require("./filtering/packageVersion.js");
4
6
  const require_publishDate = require("./filtering/publishDate.js");
5
7
  const require_jsonUtils = require("./utils/jsonUtils.js");
@@ -33,9 +35,13 @@ var PackageFilterPlugin = class extends _verdaccio_core.pluginUtils.Plugin {
33
35
  debug$1("min age: %d days", minAgeDays);
34
36
  this.logger.trace({ minAgeDays }, "package-filter min age: @{minAgeDays} days");
35
37
  }
38
+ if (this.parsedConfig.excludeDeprecated) {
39
+ debug$1("excludeDeprecated enabled");
40
+ this.logger.trace("package-filter excludeDeprecated is enabled");
41
+ }
36
42
  }
37
43
  async filter_metadata(manifest) {
38
- const { dateThreshold, minAgeMs, blockRules, allowRules } = this.parsedConfig;
44
+ const { dateThreshold, minAgeMs, excludeDeprecated, blockRules, allowRules } = this.parsedConfig;
39
45
  const versionCount = Object.keys(manifest.versions ?? {}).length;
40
46
  debug$1("filtering manifest for %s (%d versions)", manifest.name, versionCount);
41
47
  this.logger.trace({
@@ -45,19 +51,21 @@ var PackageFilterPlugin = class extends _verdaccio_core.pluginUtils.Plugin {
45
51
  let earliestDateThreshold = null;
46
52
  if (minAgeMs) earliestDateThreshold = new Date(Date.now() - minAgeMs);
47
53
  if (dateThreshold && (!earliestDateThreshold || dateThreshold < earliestDateThreshold)) earliestDateThreshold = dateThreshold;
48
- if (blockRules.size === 0 && !earliestDateThreshold) {
54
+ if (blockRules.size === 0 && !excludeDeprecated && !earliestDateThreshold) {
49
55
  debug$1("no filters configured, returning manifest untouched for %s", manifest.name);
50
56
  return manifest;
51
57
  }
52
58
  let newManifest = require_manifestUtils.getManifestClone(manifest);
53
- if (blockRules.size > 0) newManifest = require_packageVersion.filterBlockedVersions(newManifest, blockRules, allowRules, this.logger);
59
+ const allowMatch = require_matcher.matchRules(newManifest, allowRules);
60
+ if (blockRules.size > 0) newManifest = require_packageVersion.filterBlockedVersions(newManifest, blockRules, allowMatch, this.logger);
61
+ if (excludeDeprecated) newManifest = require_deprecated.filterDeprecatedVersions(newManifest, allowMatch);
54
62
  if (earliestDateThreshold) {
55
63
  debug$1("applying date filter for %s, threshold: %s", manifest.name, earliestDateThreshold.toISOString());
56
64
  this.logger.trace({
57
65
  name: manifest.name,
58
66
  threshold: earliestDateThreshold.toISOString()
59
67
  }, "applying date filter for @{name}, cutoff: @{threshold}");
60
- newManifest = require_publishDate.filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowRules);
68
+ newManifest = require_publishDate.filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowMatch);
61
69
  }
62
70
  const filteredCount = Object.keys(newManifest.versions).length;
63
71
  const removedCount = versionCount - filteredCount;
@@ -1 +1 @@
1
- {"version":3,"file":"packageFilter.js","names":[],"sources":["../src/packageFilter.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { pluginUtils } from '@verdaccio/core';\nimport type { Logger, Manifest } from '@verdaccio/types';\n\nimport { parseConfig } from './config/parser';\nimport type { ParsedConfig, PluginConfig } from './config/types';\nimport { filterBlockedVersions } from './filtering/packageVersion';\nimport { filterVersionsByPublishDate } from './filtering/publishDate';\nimport { jsonLogReplacer } from './utils/jsonUtils';\nimport {\n cleanupDistFiles,\n cleanupTags,\n cleanupTime,\n getManifestClone,\n setupCreatedAndModified,\n setupLatestTag,\n} from './utils/manifestUtils';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter');\n\nexport class PackageFilterPlugin\n extends pluginUtils.Plugin<PluginConfig>\n implements pluginUtils.ManifestFilter<PluginConfig>\n{\n public readonly config: PluginConfig;\n private readonly parsedConfig: ParsedConfig;\n protected readonly logger: Logger;\n\n public constructor(config: PluginConfig, options: pluginUtils.PluginOptions) {\n super(config, options);\n this.config = config ?? {};\n this.logger = options.logger;\n this.parsedConfig = parseConfig(this.config);\n\n debug(\n 'plugin loaded: block rules: %d, allow rules: %d',\n this.parsedConfig.blockRules.size,\n this.parsedConfig.allowRules.size\n );\n this.logger.debug(\n { config: JSON.stringify(this.parsedConfig, jsonLogReplacer) },\n 'package-filter loaded with config: @{config}'\n );\n this.logger.trace(\n {\n blockRules: this.parsedConfig.blockRules.size,\n allowRules: this.parsedConfig.allowRules.size,\n },\n 'package-filter plugin initialized: @{blockRules} block rules, @{allowRules} allow rules'\n );\n if (this.parsedConfig.dateThreshold) {\n debug('date threshold: %s', this.parsedConfig.dateThreshold.toISOString());\n this.logger.trace(\n { dateThreshold: this.parsedConfig.dateThreshold.toISOString() },\n 'package-filter date threshold: @{dateThreshold}'\n );\n }\n if (this.parsedConfig.minAgeMs) {\n const minAgeDays = this.parsedConfig.minAgeMs / (24 * 60 * 60 * 1000);\n debug('min age: %d days', minAgeDays);\n this.logger.trace({ minAgeDays }, 'package-filter min age: @{minAgeDays} days');\n }\n }\n\n public async filter_metadata(manifest: Readonly<Manifest>): Promise<Manifest> {\n const { dateThreshold, minAgeMs, blockRules, allowRules } = this.parsedConfig;\n const versionCount = Object.keys(manifest.versions ?? {}).length;\n debug('filtering manifest for %s (%d versions)', manifest.name, versionCount);\n this.logger.trace(\n { name: manifest.name, versionCount },\n 'package-filter processing @{name} (@{versionCount} versions)'\n );\n\n let earliestDateThreshold: Date | null = null;\n if (minAgeMs) {\n earliestDateThreshold = new Date(Date.now() - minAgeMs);\n }\n\n if (dateThreshold && (!earliestDateThreshold || dateThreshold < earliestDateThreshold)) {\n earliestDateThreshold = dateThreshold;\n }\n\n // Fast path: when neither block rules nor a date threshold are configured there\n // is nothing this filter can change. Returning the manifest untouched avoids the\n // clone and the cleanup passes below. This matters most for `npm search`, which\n // invokes filter_metadata once per matched package (see issue #5837).\n if (blockRules.size === 0 && !earliestDateThreshold) {\n debug('no filters configured, returning manifest untouched for %s', manifest.name);\n return manifest as Manifest;\n }\n\n let newManifest = getManifestClone(manifest);\n if (blockRules.size > 0) {\n newManifest = filterBlockedVersions(newManifest, blockRules, allowRules, this.logger);\n }\n\n if (earliestDateThreshold) {\n debug(\n 'applying date filter for %s, threshold: %s',\n manifest.name,\n earliestDateThreshold.toISOString()\n );\n this.logger.trace(\n { name: manifest.name, threshold: earliestDateThreshold.toISOString() },\n 'applying date filter for @{name}, cutoff: @{threshold}'\n );\n newManifest = filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowRules);\n }\n\n const filteredCount = Object.keys(newManifest.versions).length;\n const removedCount = versionCount - filteredCount;\n // The cleanup passes only repair inconsistencies introduced by filtering:\n // orphaned dist-tags/time/_distfiles entries and a `latest` tag pointing at a\n // removed version. When the filters left the manifest untouched (no version\n // removed or replaced) it is already consistent, so the passes are skipped.\n // `readme` changing is the signal that the (count-preserving) replace strategy\n // rewrote version content and the cleanup still needs to run.\n const wasModified = removedCount > 0 || newManifest.readme !== manifest.readme;\n if (wasModified) {\n cleanupTags(newManifest);\n setupLatestTag(newManifest);\n cleanupTime(newManifest);\n setupCreatedAndModified(newManifest);\n cleanupDistFiles(newManifest);\n }\n\n if (removedCount > 0) {\n debug(\n 'filtered %s: %d -> %d versions (%d removed)',\n manifest.name,\n versionCount,\n filteredCount,\n removedCount\n );\n this.logger.trace(\n { name: manifest.name, before: versionCount, after: filteredCount, removed: removedCount },\n 'package-filter @{name}: @{before} -> @{after} versions (@{removed} removed)'\n );\n } else {\n debug('no versions filtered for %s', manifest.name);\n }\n\n return newManifest;\n }\n}\n"],"mappings":";;;;;;;;;;AAmBA,IAAM,WAAA,GAAA,MAAA,SAAmB,iCAAiC;AAE1D,IAAa,sBAAb,cACU,gBAAA,YAAY,OAEtB;CACE;CACA;CACA;CAEA,YAAmB,QAAsB,SAAoC;EAC3E,MAAM,QAAQ,OAAO;EACrB,KAAK,SAAS,UAAU,CAAC;EACzB,KAAK,SAAS,QAAQ;EACtB,KAAK,eAAe,eAAA,YAAY,KAAK,MAAM;EAE3C,QACE,mDACA,KAAK,aAAa,WAAW,MAC7B,KAAK,aAAa,WAAW,IAC/B;EACA,KAAK,OAAO,MACV,EAAE,QAAQ,KAAK,UAAU,KAAK,cAAc,kBAAA,eAAe,EAAE,GAC7D,8CACF;EACA,KAAK,OAAO,MACV;GACE,YAAY,KAAK,aAAa,WAAW;GACzC,YAAY,KAAK,aAAa,WAAW;EAC3C,GACA,yFACF;EACA,IAAI,KAAK,aAAa,eAAe;GACnC,QAAM,sBAAsB,KAAK,aAAa,cAAc,YAAY,CAAC;GACzE,KAAK,OAAO,MACV,EAAE,eAAe,KAAK,aAAa,cAAc,YAAY,EAAE,GAC/D,iDACF;EACF;EACA,IAAI,KAAK,aAAa,UAAU;GAC9B,MAAM,aAAa,KAAK,aAAa,YAAY,OAAU,KAAK;GAChE,QAAM,oBAAoB,UAAU;GACpC,KAAK,OAAO,MAAM,EAAE,WAAW,GAAG,4CAA4C;EAChF;CACF;CAEA,MAAa,gBAAgB,UAAiD;EAC5E,MAAM,EAAE,eAAe,UAAU,YAAY,eAAe,KAAK;EACjE,MAAM,eAAe,OAAO,KAAK,SAAS,YAAY,CAAC,CAAC,EAAE;EAC1D,QAAM,2CAA2C,SAAS,MAAM,YAAY;EAC5E,KAAK,OAAO,MACV;GAAE,MAAM,SAAS;GAAM;EAAa,GACpC,8DACF;EAEA,IAAI,wBAAqC;EACzC,IAAI,UACF,wBAAwB,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ;EAGxD,IAAI,kBAAkB,CAAC,yBAAyB,gBAAgB,wBAC9D,wBAAwB;EAO1B,IAAI,WAAW,SAAS,KAAK,CAAC,uBAAuB;GACnD,QAAM,8DAA8D,SAAS,IAAI;GACjF,OAAO;EACT;EAEA,IAAI,cAAc,sBAAA,iBAAiB,QAAQ;EAC3C,IAAI,WAAW,OAAO,GACpB,cAAc,uBAAA,sBAAsB,aAAa,YAAY,YAAY,KAAK,MAAM;EAGtF,IAAI,uBAAuB;GACzB,QACE,8CACA,SAAS,MACT,sBAAsB,YAAY,CACpC;GACA,KAAK,OAAO,MACV;IAAE,MAAM,SAAS;IAAM,WAAW,sBAAsB,YAAY;GAAE,GACtE,wDACF;GACA,cAAc,oBAAA,4BAA4B,aAAa,uBAAuB,UAAU;EAC1F;EAEA,MAAM,gBAAgB,OAAO,KAAK,YAAY,QAAQ,EAAE;EACxD,MAAM,eAAe,eAAe;EAQpC,IADoB,eAAe,KAAK,YAAY,WAAW,SAAS,QACvD;GACf,sBAAA,YAAY,WAAW;GACvB,sBAAA,eAAe,WAAW;GAC1B,sBAAA,YAAY,WAAW;GACvB,sBAAA,wBAAwB,WAAW;GACnC,sBAAA,iBAAiB,WAAW;EAC9B;EAEA,IAAI,eAAe,GAAG;GACpB,QACE,+CACA,SAAS,MACT,cACA,eACA,YACF;GACA,KAAK,OAAO,MACV;IAAE,MAAM,SAAS;IAAM,QAAQ;IAAc,OAAO;IAAe,SAAS;GAAa,GACzF,6EACF;EACF,OACE,QAAM,+BAA+B,SAAS,IAAI;EAGpD,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"packageFilter.js","names":[],"sources":["../src/packageFilter.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { pluginUtils } from '@verdaccio/core';\nimport type { Logger, Manifest } from '@verdaccio/types';\n\nimport { parseConfig } from './config/parser';\nimport type { ParsedConfig, PluginConfig } from './config/types';\nimport { filterDeprecatedVersions } from './filtering/deprecated';\nimport { matchRules } from './filtering/matcher';\nimport { filterBlockedVersions } from './filtering/packageVersion';\nimport { filterVersionsByPublishDate } from './filtering/publishDate';\nimport { jsonLogReplacer } from './utils/jsonUtils';\nimport {\n cleanupDistFiles,\n cleanupTags,\n cleanupTime,\n getManifestClone,\n setupCreatedAndModified,\n setupLatestTag,\n} from './utils/manifestUtils';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter');\n\nexport class PackageFilterPlugin\n extends pluginUtils.Plugin<PluginConfig>\n implements pluginUtils.ManifestFilter<PluginConfig>\n{\n public readonly config: PluginConfig;\n private readonly parsedConfig: ParsedConfig;\n protected readonly logger: Logger;\n\n public constructor(config: PluginConfig, options: pluginUtils.PluginOptions) {\n super(config, options);\n this.config = config ?? {};\n this.logger = options.logger;\n this.parsedConfig = parseConfig(this.config);\n\n debug(\n 'plugin loaded: block rules: %d, allow rules: %d',\n this.parsedConfig.blockRules.size,\n this.parsedConfig.allowRules.size\n );\n this.logger.debug(\n { config: JSON.stringify(this.parsedConfig, jsonLogReplacer) },\n 'package-filter loaded with config: @{config}'\n );\n this.logger.trace(\n {\n blockRules: this.parsedConfig.blockRules.size,\n allowRules: this.parsedConfig.allowRules.size,\n },\n 'package-filter plugin initialized: @{blockRules} block rules, @{allowRules} allow rules'\n );\n if (this.parsedConfig.dateThreshold) {\n debug('date threshold: %s', this.parsedConfig.dateThreshold.toISOString());\n this.logger.trace(\n { dateThreshold: this.parsedConfig.dateThreshold.toISOString() },\n 'package-filter date threshold: @{dateThreshold}'\n );\n }\n if (this.parsedConfig.minAgeMs) {\n const minAgeDays = this.parsedConfig.minAgeMs / (24 * 60 * 60 * 1000);\n debug('min age: %d days', minAgeDays);\n this.logger.trace({ minAgeDays }, 'package-filter min age: @{minAgeDays} days');\n }\n if (this.parsedConfig.excludeDeprecated) {\n debug('excludeDeprecated enabled');\n this.logger.trace('package-filter excludeDeprecated is enabled');\n }\n }\n\n public async filter_metadata(manifest: Readonly<Manifest>): Promise<Manifest> {\n const { dateThreshold, minAgeMs, excludeDeprecated, blockRules, allowRules } =\n this.parsedConfig;\n const versionCount = Object.keys(manifest.versions ?? {}).length;\n debug('filtering manifest for %s (%d versions)', manifest.name, versionCount);\n this.logger.trace(\n { name: manifest.name, versionCount },\n 'package-filter processing @{name} (@{versionCount} versions)'\n );\n\n let earliestDateThreshold: Date | null = null;\n if (minAgeMs) {\n earliestDateThreshold = new Date(Date.now() - minAgeMs);\n }\n\n if (dateThreshold && (!earliestDateThreshold || dateThreshold < earliestDateThreshold)) {\n earliestDateThreshold = dateThreshold;\n }\n\n // Fast path: when neither block rules nor a date threshold are configured there\n // is nothing this filter can change. Returning the manifest untouched avoids the\n // clone and the cleanup passes below. This matters most for `npm search`, which\n // invokes filter_metadata once per matched package (see issue #5837).\n if (blockRules.size === 0 && !excludeDeprecated && !earliestDateThreshold) {\n debug('no filters configured, returning manifest untouched for %s', manifest.name);\n return manifest as Manifest;\n }\n\n let newManifest = getManifestClone(manifest);\n const allowMatch = matchRules(newManifest, allowRules);\n\n if (blockRules.size > 0) {\n newManifest = filterBlockedVersions(newManifest, blockRules, allowMatch, this.logger);\n }\n\n if (excludeDeprecated) {\n newManifest = filterDeprecatedVersions(newManifest, allowMatch);\n }\n\n if (earliestDateThreshold) {\n debug(\n 'applying date filter for %s, threshold: %s',\n manifest.name,\n earliestDateThreshold.toISOString()\n );\n this.logger.trace(\n { name: manifest.name, threshold: earliestDateThreshold.toISOString() },\n 'applying date filter for @{name}, cutoff: @{threshold}'\n );\n newManifest = filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowMatch);\n }\n\n const filteredCount = Object.keys(newManifest.versions).length;\n const removedCount = versionCount - filteredCount;\n // The cleanup passes only repair inconsistencies introduced by filtering:\n // orphaned dist-tags/time/_distfiles entries and a `latest` tag pointing at a\n // removed version. When the filters left the manifest untouched (no version\n // removed or replaced) it is already consistent, so the passes are skipped.\n // `readme` changing is the signal that the (count-preserving) replace strategy\n // rewrote version content and the cleanup still needs to run.\n const wasModified = removedCount > 0 || newManifest.readme !== manifest.readme;\n if (wasModified) {\n cleanupTags(newManifest);\n setupLatestTag(newManifest);\n cleanupTime(newManifest);\n setupCreatedAndModified(newManifest);\n cleanupDistFiles(newManifest);\n }\n\n if (removedCount > 0) {\n debug(\n 'filtered %s: %d -> %d versions (%d removed)',\n manifest.name,\n versionCount,\n filteredCount,\n removedCount\n );\n this.logger.trace(\n { name: manifest.name, before: versionCount, after: filteredCount, removed: removedCount },\n 'package-filter @{name}: @{before} -> @{after} versions (@{removed} removed)'\n );\n } else {\n debug('no versions filtered for %s', manifest.name);\n }\n\n return newManifest;\n }\n}\n"],"mappings":";;;;;;;;;;;;AAqBA,IAAM,WAAA,GAAA,MAAA,QAAA,CAAmB,iCAAiC;AAE1D,IAAa,sBAAb,cACU,gBAAA,YAAY,OAEtB;CACE;CACA;CACA;CAEA,YAAmB,QAAsB,SAAoC;EAC3E,MAAM,QAAQ,OAAO;EACrB,KAAK,SAAS,UAAU,CAAC;EACzB,KAAK,SAAS,QAAQ;EACtB,KAAK,eAAe,eAAA,YAAY,KAAK,MAAM;EAE3C,QACE,mDACA,KAAK,aAAa,WAAW,MAC7B,KAAK,aAAa,WAAW,IAC/B;EACA,KAAK,OAAO,MACV,EAAE,QAAQ,KAAK,UAAU,KAAK,cAAc,kBAAA,eAAe,EAAE,GAC7D,8CACF;EACA,KAAK,OAAO,MACV;GACE,YAAY,KAAK,aAAa,WAAW;GACzC,YAAY,KAAK,aAAa,WAAW;EAC3C,GACA,yFACF;EACA,IAAI,KAAK,aAAa,eAAe;GACnC,QAAM,sBAAsB,KAAK,aAAa,cAAc,YAAY,CAAC;GACzE,KAAK,OAAO,MACV,EAAE,eAAe,KAAK,aAAa,cAAc,YAAY,EAAE,GAC/D,iDACF;EACF;EACA,IAAI,KAAK,aAAa,UAAU;GAC9B,MAAM,aAAa,KAAK,aAAa,YAAY,OAAU,KAAK;GAChE,QAAM,oBAAoB,UAAU;GACpC,KAAK,OAAO,MAAM,EAAE,WAAW,GAAG,4CAA4C;EAChF;EACA,IAAI,KAAK,aAAa,mBAAmB;GACvC,QAAM,2BAA2B;GACjC,KAAK,OAAO,MAAM,6CAA6C;EACjE;CACF;CAEA,MAAa,gBAAgB,UAAiD;EAC5E,MAAM,EAAE,eAAe,UAAU,mBAAmB,YAAY,eAC9D,KAAK;EACP,MAAM,eAAe,OAAO,KAAK,SAAS,YAAY,CAAC,CAAC,CAAC,CAAC;EAC1D,QAAM,2CAA2C,SAAS,MAAM,YAAY;EAC5E,KAAK,OAAO,MACV;GAAE,MAAM,SAAS;GAAM;EAAa,GACpC,8DACF;EAEA,IAAI,wBAAqC;EACzC,IAAI,UACF,wBAAwB,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ;EAGxD,IAAI,kBAAkB,CAAC,yBAAyB,gBAAgB,wBAC9D,wBAAwB;EAO1B,IAAI,WAAW,SAAS,KAAK,CAAC,qBAAqB,CAAC,uBAAuB;GACzE,QAAM,8DAA8D,SAAS,IAAI;GACjF,OAAO;EACT;EAEA,IAAI,cAAc,sBAAA,iBAAiB,QAAQ;EAC3C,MAAM,aAAa,gBAAA,WAAW,aAAa,UAAU;EAErD,IAAI,WAAW,OAAO,GACpB,cAAc,uBAAA,sBAAsB,aAAa,YAAY,YAAY,KAAK,MAAM;EAGtF,IAAI,mBACF,cAAc,mBAAA,yBAAyB,aAAa,UAAU;EAGhE,IAAI,uBAAuB;GACzB,QACE,8CACA,SAAS,MACT,sBAAsB,YAAY,CACpC;GACA,KAAK,OAAO,MACV;IAAE,MAAM,SAAS;IAAM,WAAW,sBAAsB,YAAY;GAAE,GACtE,wDACF;GACA,cAAc,oBAAA,4BAA4B,aAAa,uBAAuB,UAAU;EAC1F;EAEA,MAAM,gBAAgB,OAAO,KAAK,YAAY,QAAQ,CAAC,CAAC;EACxD,MAAM,eAAe,eAAe;EAQpC,IADoB,eAAe,KAAK,YAAY,WAAW,SAAS,QACvD;GACf,sBAAA,YAAY,WAAW;GACvB,sBAAA,eAAe,WAAW;GAC1B,sBAAA,YAAY,WAAW;GACvB,sBAAA,wBAAwB,WAAW;GACnC,sBAAA,iBAAiB,WAAW;EAC9B;EAEA,IAAI,eAAe,GAAG;GACpB,QACE,+CACA,SAAS,MACT,cACA,eACA,YACF;GACA,KAAK,OAAO,MACV;IAAE,MAAM,SAAS;IAAM,QAAQ;IAAc,OAAO;IAAe,SAAS;GAAa,GACzF,6EACF;EACF,OACE,QAAM,+BAA+B,SAAS,IAAI;EAGpD,OAAO;CACT;AACF"}
@@ -1,4 +1,6 @@
1
1
  import { parseConfig } from "./config/parser.mjs";
2
+ import { matchRules } from "./filtering/matcher.mjs";
3
+ import { filterDeprecatedVersions } from "./filtering/deprecated.mjs";
2
4
  import { filterBlockedVersions } from "./filtering/packageVersion.mjs";
3
5
  import { filterVersionsByPublishDate } from "./filtering/publishDate.mjs";
4
6
  import { jsonLogReplacer } from "./utils/jsonUtils.mjs";
@@ -31,9 +33,13 @@ var PackageFilterPlugin = class extends pluginUtils.Plugin {
31
33
  debug("min age: %d days", minAgeDays);
32
34
  this.logger.trace({ minAgeDays }, "package-filter min age: @{minAgeDays} days");
33
35
  }
36
+ if (this.parsedConfig.excludeDeprecated) {
37
+ debug("excludeDeprecated enabled");
38
+ this.logger.trace("package-filter excludeDeprecated is enabled");
39
+ }
34
40
  }
35
41
  async filter_metadata(manifest) {
36
- const { dateThreshold, minAgeMs, blockRules, allowRules } = this.parsedConfig;
42
+ const { dateThreshold, minAgeMs, excludeDeprecated, blockRules, allowRules } = this.parsedConfig;
37
43
  const versionCount = Object.keys(manifest.versions ?? {}).length;
38
44
  debug("filtering manifest for %s (%d versions)", manifest.name, versionCount);
39
45
  this.logger.trace({
@@ -43,19 +49,21 @@ var PackageFilterPlugin = class extends pluginUtils.Plugin {
43
49
  let earliestDateThreshold = null;
44
50
  if (minAgeMs) earliestDateThreshold = new Date(Date.now() - minAgeMs);
45
51
  if (dateThreshold && (!earliestDateThreshold || dateThreshold < earliestDateThreshold)) earliestDateThreshold = dateThreshold;
46
- if (blockRules.size === 0 && !earliestDateThreshold) {
52
+ if (blockRules.size === 0 && !excludeDeprecated && !earliestDateThreshold) {
47
53
  debug("no filters configured, returning manifest untouched for %s", manifest.name);
48
54
  return manifest;
49
55
  }
50
56
  let newManifest = getManifestClone(manifest);
51
- if (blockRules.size > 0) newManifest = filterBlockedVersions(newManifest, blockRules, allowRules, this.logger);
57
+ const allowMatch = matchRules(newManifest, allowRules);
58
+ if (blockRules.size > 0) newManifest = filterBlockedVersions(newManifest, blockRules, allowMatch, this.logger);
59
+ if (excludeDeprecated) newManifest = filterDeprecatedVersions(newManifest, allowMatch);
52
60
  if (earliestDateThreshold) {
53
61
  debug("applying date filter for %s, threshold: %s", manifest.name, earliestDateThreshold.toISOString());
54
62
  this.logger.trace({
55
63
  name: manifest.name,
56
64
  threshold: earliestDateThreshold.toISOString()
57
65
  }, "applying date filter for @{name}, cutoff: @{threshold}");
58
- newManifest = filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowRules);
66
+ newManifest = filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowMatch);
59
67
  }
60
68
  const filteredCount = Object.keys(newManifest.versions).length;
61
69
  const removedCount = versionCount - filteredCount;
@@ -1 +1 @@
1
- {"version":3,"file":"packageFilter.mjs","names":[],"sources":["../src/packageFilter.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { pluginUtils } from '@verdaccio/core';\nimport type { Logger, Manifest } from '@verdaccio/types';\n\nimport { parseConfig } from './config/parser';\nimport type { ParsedConfig, PluginConfig } from './config/types';\nimport { filterBlockedVersions } from './filtering/packageVersion';\nimport { filterVersionsByPublishDate } from './filtering/publishDate';\nimport { jsonLogReplacer } from './utils/jsonUtils';\nimport {\n cleanupDistFiles,\n cleanupTags,\n cleanupTime,\n getManifestClone,\n setupCreatedAndModified,\n setupLatestTag,\n} from './utils/manifestUtils';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter');\n\nexport class PackageFilterPlugin\n extends pluginUtils.Plugin<PluginConfig>\n implements pluginUtils.ManifestFilter<PluginConfig>\n{\n public readonly config: PluginConfig;\n private readonly parsedConfig: ParsedConfig;\n protected readonly logger: Logger;\n\n public constructor(config: PluginConfig, options: pluginUtils.PluginOptions) {\n super(config, options);\n this.config = config ?? {};\n this.logger = options.logger;\n this.parsedConfig = parseConfig(this.config);\n\n debug(\n 'plugin loaded: block rules: %d, allow rules: %d',\n this.parsedConfig.blockRules.size,\n this.parsedConfig.allowRules.size\n );\n this.logger.debug(\n { config: JSON.stringify(this.parsedConfig, jsonLogReplacer) },\n 'package-filter loaded with config: @{config}'\n );\n this.logger.trace(\n {\n blockRules: this.parsedConfig.blockRules.size,\n allowRules: this.parsedConfig.allowRules.size,\n },\n 'package-filter plugin initialized: @{blockRules} block rules, @{allowRules} allow rules'\n );\n if (this.parsedConfig.dateThreshold) {\n debug('date threshold: %s', this.parsedConfig.dateThreshold.toISOString());\n this.logger.trace(\n { dateThreshold: this.parsedConfig.dateThreshold.toISOString() },\n 'package-filter date threshold: @{dateThreshold}'\n );\n }\n if (this.parsedConfig.minAgeMs) {\n const minAgeDays = this.parsedConfig.minAgeMs / (24 * 60 * 60 * 1000);\n debug('min age: %d days', minAgeDays);\n this.logger.trace({ minAgeDays }, 'package-filter min age: @{minAgeDays} days');\n }\n }\n\n public async filter_metadata(manifest: Readonly<Manifest>): Promise<Manifest> {\n const { dateThreshold, minAgeMs, blockRules, allowRules } = this.parsedConfig;\n const versionCount = Object.keys(manifest.versions ?? {}).length;\n debug('filtering manifest for %s (%d versions)', manifest.name, versionCount);\n this.logger.trace(\n { name: manifest.name, versionCount },\n 'package-filter processing @{name} (@{versionCount} versions)'\n );\n\n let earliestDateThreshold: Date | null = null;\n if (minAgeMs) {\n earliestDateThreshold = new Date(Date.now() - minAgeMs);\n }\n\n if (dateThreshold && (!earliestDateThreshold || dateThreshold < earliestDateThreshold)) {\n earliestDateThreshold = dateThreshold;\n }\n\n // Fast path: when neither block rules nor a date threshold are configured there\n // is nothing this filter can change. Returning the manifest untouched avoids the\n // clone and the cleanup passes below. This matters most for `npm search`, which\n // invokes filter_metadata once per matched package (see issue #5837).\n if (blockRules.size === 0 && !earliestDateThreshold) {\n debug('no filters configured, returning manifest untouched for %s', manifest.name);\n return manifest as Manifest;\n }\n\n let newManifest = getManifestClone(manifest);\n if (blockRules.size > 0) {\n newManifest = filterBlockedVersions(newManifest, blockRules, allowRules, this.logger);\n }\n\n if (earliestDateThreshold) {\n debug(\n 'applying date filter for %s, threshold: %s',\n manifest.name,\n earliestDateThreshold.toISOString()\n );\n this.logger.trace(\n { name: manifest.name, threshold: earliestDateThreshold.toISOString() },\n 'applying date filter for @{name}, cutoff: @{threshold}'\n );\n newManifest = filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowRules);\n }\n\n const filteredCount = Object.keys(newManifest.versions).length;\n const removedCount = versionCount - filteredCount;\n // The cleanup passes only repair inconsistencies introduced by filtering:\n // orphaned dist-tags/time/_distfiles entries and a `latest` tag pointing at a\n // removed version. When the filters left the manifest untouched (no version\n // removed or replaced) it is already consistent, so the passes are skipped.\n // `readme` changing is the signal that the (count-preserving) replace strategy\n // rewrote version content and the cleanup still needs to run.\n const wasModified = removedCount > 0 || newManifest.readme !== manifest.readme;\n if (wasModified) {\n cleanupTags(newManifest);\n setupLatestTag(newManifest);\n cleanupTime(newManifest);\n setupCreatedAndModified(newManifest);\n cleanupDistFiles(newManifest);\n }\n\n if (removedCount > 0) {\n debug(\n 'filtered %s: %d -> %d versions (%d removed)',\n manifest.name,\n versionCount,\n filteredCount,\n removedCount\n );\n this.logger.trace(\n { name: manifest.name, before: versionCount, after: filteredCount, removed: removedCount },\n 'package-filter @{name}: @{before} -> @{after} versions (@{removed} removed)'\n );\n } else {\n debug('no versions filtered for %s', manifest.name);\n }\n\n return newManifest;\n }\n}\n"],"mappings":";;;;;;;;AAmBA,IAAM,QAAQ,WAAW,iCAAiC;AAE1D,IAAa,sBAAb,cACU,YAAY,OAEtB;CACE;CACA;CACA;CAEA,YAAmB,QAAsB,SAAoC;EAC3E,MAAM,QAAQ,OAAO;EACrB,KAAK,SAAS,UAAU,CAAC;EACzB,KAAK,SAAS,QAAQ;EACtB,KAAK,eAAe,YAAY,KAAK,MAAM;EAE3C,MACE,mDACA,KAAK,aAAa,WAAW,MAC7B,KAAK,aAAa,WAAW,IAC/B;EACA,KAAK,OAAO,MACV,EAAE,QAAQ,KAAK,UAAU,KAAK,cAAc,eAAe,EAAE,GAC7D,8CACF;EACA,KAAK,OAAO,MACV;GACE,YAAY,KAAK,aAAa,WAAW;GACzC,YAAY,KAAK,aAAa,WAAW;EAC3C,GACA,yFACF;EACA,IAAI,KAAK,aAAa,eAAe;GACnC,MAAM,sBAAsB,KAAK,aAAa,cAAc,YAAY,CAAC;GACzE,KAAK,OAAO,MACV,EAAE,eAAe,KAAK,aAAa,cAAc,YAAY,EAAE,GAC/D,iDACF;EACF;EACA,IAAI,KAAK,aAAa,UAAU;GAC9B,MAAM,aAAa,KAAK,aAAa,YAAY,OAAU,KAAK;GAChE,MAAM,oBAAoB,UAAU;GACpC,KAAK,OAAO,MAAM,EAAE,WAAW,GAAG,4CAA4C;EAChF;CACF;CAEA,MAAa,gBAAgB,UAAiD;EAC5E,MAAM,EAAE,eAAe,UAAU,YAAY,eAAe,KAAK;EACjE,MAAM,eAAe,OAAO,KAAK,SAAS,YAAY,CAAC,CAAC,EAAE;EAC1D,MAAM,2CAA2C,SAAS,MAAM,YAAY;EAC5E,KAAK,OAAO,MACV;GAAE,MAAM,SAAS;GAAM;EAAa,GACpC,8DACF;EAEA,IAAI,wBAAqC;EACzC,IAAI,UACF,wBAAwB,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ;EAGxD,IAAI,kBAAkB,CAAC,yBAAyB,gBAAgB,wBAC9D,wBAAwB;EAO1B,IAAI,WAAW,SAAS,KAAK,CAAC,uBAAuB;GACnD,MAAM,8DAA8D,SAAS,IAAI;GACjF,OAAO;EACT;EAEA,IAAI,cAAc,iBAAiB,QAAQ;EAC3C,IAAI,WAAW,OAAO,GACpB,cAAc,sBAAsB,aAAa,YAAY,YAAY,KAAK,MAAM;EAGtF,IAAI,uBAAuB;GACzB,MACE,8CACA,SAAS,MACT,sBAAsB,YAAY,CACpC;GACA,KAAK,OAAO,MACV;IAAE,MAAM,SAAS;IAAM,WAAW,sBAAsB,YAAY;GAAE,GACtE,wDACF;GACA,cAAc,4BAA4B,aAAa,uBAAuB,UAAU;EAC1F;EAEA,MAAM,gBAAgB,OAAO,KAAK,YAAY,QAAQ,EAAE;EACxD,MAAM,eAAe,eAAe;EAQpC,IADoB,eAAe,KAAK,YAAY,WAAW,SAAS,QACvD;GACf,YAAY,WAAW;GACvB,eAAe,WAAW;GAC1B,YAAY,WAAW;GACvB,wBAAwB,WAAW;GACnC,iBAAiB,WAAW;EAC9B;EAEA,IAAI,eAAe,GAAG;GACpB,MACE,+CACA,SAAS,MACT,cACA,eACA,YACF;GACA,KAAK,OAAO,MACV;IAAE,MAAM,SAAS;IAAM,QAAQ;IAAc,OAAO;IAAe,SAAS;GAAa,GACzF,6EACF;EACF,OACE,MAAM,+BAA+B,SAAS,IAAI;EAGpD,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"packageFilter.mjs","names":[],"sources":["../src/packageFilter.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport { pluginUtils } from '@verdaccio/core';\nimport type { Logger, Manifest } from '@verdaccio/types';\n\nimport { parseConfig } from './config/parser';\nimport type { ParsedConfig, PluginConfig } from './config/types';\nimport { filterDeprecatedVersions } from './filtering/deprecated';\nimport { matchRules } from './filtering/matcher';\nimport { filterBlockedVersions } from './filtering/packageVersion';\nimport { filterVersionsByPublishDate } from './filtering/publishDate';\nimport { jsonLogReplacer } from './utils/jsonUtils';\nimport {\n cleanupDistFiles,\n cleanupTags,\n cleanupTime,\n getManifestClone,\n setupCreatedAndModified,\n setupLatestTag,\n} from './utils/manifestUtils';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter');\n\nexport class PackageFilterPlugin\n extends pluginUtils.Plugin<PluginConfig>\n implements pluginUtils.ManifestFilter<PluginConfig>\n{\n public readonly config: PluginConfig;\n private readonly parsedConfig: ParsedConfig;\n protected readonly logger: Logger;\n\n public constructor(config: PluginConfig, options: pluginUtils.PluginOptions) {\n super(config, options);\n this.config = config ?? {};\n this.logger = options.logger;\n this.parsedConfig = parseConfig(this.config);\n\n debug(\n 'plugin loaded: block rules: %d, allow rules: %d',\n this.parsedConfig.blockRules.size,\n this.parsedConfig.allowRules.size\n );\n this.logger.debug(\n { config: JSON.stringify(this.parsedConfig, jsonLogReplacer) },\n 'package-filter loaded with config: @{config}'\n );\n this.logger.trace(\n {\n blockRules: this.parsedConfig.blockRules.size,\n allowRules: this.parsedConfig.allowRules.size,\n },\n 'package-filter plugin initialized: @{blockRules} block rules, @{allowRules} allow rules'\n );\n if (this.parsedConfig.dateThreshold) {\n debug('date threshold: %s', this.parsedConfig.dateThreshold.toISOString());\n this.logger.trace(\n { dateThreshold: this.parsedConfig.dateThreshold.toISOString() },\n 'package-filter date threshold: @{dateThreshold}'\n );\n }\n if (this.parsedConfig.minAgeMs) {\n const minAgeDays = this.parsedConfig.minAgeMs / (24 * 60 * 60 * 1000);\n debug('min age: %d days', minAgeDays);\n this.logger.trace({ minAgeDays }, 'package-filter min age: @{minAgeDays} days');\n }\n if (this.parsedConfig.excludeDeprecated) {\n debug('excludeDeprecated enabled');\n this.logger.trace('package-filter excludeDeprecated is enabled');\n }\n }\n\n public async filter_metadata(manifest: Readonly<Manifest>): Promise<Manifest> {\n const { dateThreshold, minAgeMs, excludeDeprecated, blockRules, allowRules } =\n this.parsedConfig;\n const versionCount = Object.keys(manifest.versions ?? {}).length;\n debug('filtering manifest for %s (%d versions)', manifest.name, versionCount);\n this.logger.trace(\n { name: manifest.name, versionCount },\n 'package-filter processing @{name} (@{versionCount} versions)'\n );\n\n let earliestDateThreshold: Date | null = null;\n if (minAgeMs) {\n earliestDateThreshold = new Date(Date.now() - minAgeMs);\n }\n\n if (dateThreshold && (!earliestDateThreshold || dateThreshold < earliestDateThreshold)) {\n earliestDateThreshold = dateThreshold;\n }\n\n // Fast path: when neither block rules nor a date threshold are configured there\n // is nothing this filter can change. Returning the manifest untouched avoids the\n // clone and the cleanup passes below. This matters most for `npm search`, which\n // invokes filter_metadata once per matched package (see issue #5837).\n if (blockRules.size === 0 && !excludeDeprecated && !earliestDateThreshold) {\n debug('no filters configured, returning manifest untouched for %s', manifest.name);\n return manifest as Manifest;\n }\n\n let newManifest = getManifestClone(manifest);\n const allowMatch = matchRules(newManifest, allowRules);\n\n if (blockRules.size > 0) {\n newManifest = filterBlockedVersions(newManifest, blockRules, allowMatch, this.logger);\n }\n\n if (excludeDeprecated) {\n newManifest = filterDeprecatedVersions(newManifest, allowMatch);\n }\n\n if (earliestDateThreshold) {\n debug(\n 'applying date filter for %s, threshold: %s',\n manifest.name,\n earliestDateThreshold.toISOString()\n );\n this.logger.trace(\n { name: manifest.name, threshold: earliestDateThreshold.toISOString() },\n 'applying date filter for @{name}, cutoff: @{threshold}'\n );\n newManifest = filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowMatch);\n }\n\n const filteredCount = Object.keys(newManifest.versions).length;\n const removedCount = versionCount - filteredCount;\n // The cleanup passes only repair inconsistencies introduced by filtering:\n // orphaned dist-tags/time/_distfiles entries and a `latest` tag pointing at a\n // removed version. When the filters left the manifest untouched (no version\n // removed or replaced) it is already consistent, so the passes are skipped.\n // `readme` changing is the signal that the (count-preserving) replace strategy\n // rewrote version content and the cleanup still needs to run.\n const wasModified = removedCount > 0 || newManifest.readme !== manifest.readme;\n if (wasModified) {\n cleanupTags(newManifest);\n setupLatestTag(newManifest);\n cleanupTime(newManifest);\n setupCreatedAndModified(newManifest);\n cleanupDistFiles(newManifest);\n }\n\n if (removedCount > 0) {\n debug(\n 'filtered %s: %d -> %d versions (%d removed)',\n manifest.name,\n versionCount,\n filteredCount,\n removedCount\n );\n this.logger.trace(\n { name: manifest.name, before: versionCount, after: filteredCount, removed: removedCount },\n 'package-filter @{name}: @{before} -> @{after} versions (@{removed} removed)'\n );\n } else {\n debug('no versions filtered for %s', manifest.name);\n }\n\n return newManifest;\n }\n}\n"],"mappings":";;;;;;;;;;AAqBA,IAAM,QAAQ,WAAW,iCAAiC;AAE1D,IAAa,sBAAb,cACU,YAAY,OAEtB;CACE;CACA;CACA;CAEA,YAAmB,QAAsB,SAAoC;EAC3E,MAAM,QAAQ,OAAO;EACrB,KAAK,SAAS,UAAU,CAAC;EACzB,KAAK,SAAS,QAAQ;EACtB,KAAK,eAAe,YAAY,KAAK,MAAM;EAE3C,MACE,mDACA,KAAK,aAAa,WAAW,MAC7B,KAAK,aAAa,WAAW,IAC/B;EACA,KAAK,OAAO,MACV,EAAE,QAAQ,KAAK,UAAU,KAAK,cAAc,eAAe,EAAE,GAC7D,8CACF;EACA,KAAK,OAAO,MACV;GACE,YAAY,KAAK,aAAa,WAAW;GACzC,YAAY,KAAK,aAAa,WAAW;EAC3C,GACA,yFACF;EACA,IAAI,KAAK,aAAa,eAAe;GACnC,MAAM,sBAAsB,KAAK,aAAa,cAAc,YAAY,CAAC;GACzE,KAAK,OAAO,MACV,EAAE,eAAe,KAAK,aAAa,cAAc,YAAY,EAAE,GAC/D,iDACF;EACF;EACA,IAAI,KAAK,aAAa,UAAU;GAC9B,MAAM,aAAa,KAAK,aAAa,YAAY,OAAU,KAAK;GAChE,MAAM,oBAAoB,UAAU;GACpC,KAAK,OAAO,MAAM,EAAE,WAAW,GAAG,4CAA4C;EAChF;EACA,IAAI,KAAK,aAAa,mBAAmB;GACvC,MAAM,2BAA2B;GACjC,KAAK,OAAO,MAAM,6CAA6C;EACjE;CACF;CAEA,MAAa,gBAAgB,UAAiD;EAC5E,MAAM,EAAE,eAAe,UAAU,mBAAmB,YAAY,eAC9D,KAAK;EACP,MAAM,eAAe,OAAO,KAAK,SAAS,YAAY,CAAC,CAAC,CAAC,CAAC;EAC1D,MAAM,2CAA2C,SAAS,MAAM,YAAY;EAC5E,KAAK,OAAO,MACV;GAAE,MAAM,SAAS;GAAM;EAAa,GACpC,8DACF;EAEA,IAAI,wBAAqC;EACzC,IAAI,UACF,wBAAwB,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ;EAGxD,IAAI,kBAAkB,CAAC,yBAAyB,gBAAgB,wBAC9D,wBAAwB;EAO1B,IAAI,WAAW,SAAS,KAAK,CAAC,qBAAqB,CAAC,uBAAuB;GACzE,MAAM,8DAA8D,SAAS,IAAI;GACjF,OAAO;EACT;EAEA,IAAI,cAAc,iBAAiB,QAAQ;EAC3C,MAAM,aAAa,WAAW,aAAa,UAAU;EAErD,IAAI,WAAW,OAAO,GACpB,cAAc,sBAAsB,aAAa,YAAY,YAAY,KAAK,MAAM;EAGtF,IAAI,mBACF,cAAc,yBAAyB,aAAa,UAAU;EAGhE,IAAI,uBAAuB;GACzB,MACE,8CACA,SAAS,MACT,sBAAsB,YAAY,CACpC;GACA,KAAK,OAAO,MACV;IAAE,MAAM,SAAS;IAAM,WAAW,sBAAsB,YAAY;GAAE,GACtE,wDACF;GACA,cAAc,4BAA4B,aAAa,uBAAuB,UAAU;EAC1F;EAEA,MAAM,gBAAgB,OAAO,KAAK,YAAY,QAAQ,CAAC,CAAC;EACxD,MAAM,eAAe,eAAe;EAQpC,IADoB,eAAe,KAAK,YAAY,WAAW,SAAS,QACvD;GACf,YAAY,WAAW;GACvB,eAAe,WAAW;GAC1B,YAAY,WAAW;GACvB,wBAAwB,WAAW;GACnC,iBAAiB,WAAW;EAC9B;EAEA,IAAI,eAAe,GAAG;GACpB,MACE,+CACA,SAAS,MACT,cACA,eACA,YACF;GACA,KAAK,OAAO,MACV;IAAE,MAAM,SAAS;IAAM,QAAQ;IAAc,OAAO;IAAe,SAAS;GAAa,GACzF,6EACF;EACF,OACE,MAAM,+BAA+B,SAAS,IAAI;EAGpD,OAAO;CACT;AACF"}
@@ -122,6 +122,7 @@ function getManifestClone(manifest) {
122
122
  exports.cleanupDistFiles = cleanupDistFiles;
123
123
  exports.cleanupTags = cleanupTags;
124
124
  exports.cleanupTime = cleanupTime;
125
+ exports.getLatestVersion = getLatestVersion;
125
126
  exports.getManifestClone = getManifestClone;
126
127
  exports.setupCreatedAndModified = setupCreatedAndModified;
127
128
  exports.setupLatestTag = setupLatestTag;
@@ -1 +1 @@
1
- {"version":3,"file":"manifestUtils.js","names":[],"sources":["../../src/utils/manifestUtils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport semver from 'semver';\n\nimport { DIST_TAGS } from '@verdaccio/core';\nimport type { Manifest } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:manifest');\n\n/**\n * Delete `dist-tags` entries corresponding to missing versions.\n */\nexport function cleanupTags(manifest: Manifest): void {\n const distTags = manifest[DIST_TAGS];\n Object.entries(distTags).forEach(([tag, tagVersion]) => {\n if (!manifest.versions[tagVersion]) {\n debug('removing orphaned dist-tag %s -> %s from %s', tag, tagVersion, manifest.name);\n delete distTags[tag];\n }\n });\n}\n\n/**\n * Delete `time` entries corresponding to missing versions.\n */\nexport function cleanupTime(manifest: Manifest): void {\n const time = manifest.time;\n if (!time) {\n return;\n }\n\n Object.keys(time).forEach((version) => {\n if (!manifest.versions[version]) {\n delete time[version];\n }\n });\n}\n\n/**\n * Get the latest version from a list of versions,\n * ordered by time of their publication stored in the manifest.\n */\nexport function getLatestVersion(manifest: Manifest, versions: string[]): string | undefined {\n const time = manifest.time;\n if (!time) {\n // No time information, it's the best we can do\n const sortedVersions = versions.sort(semver.rcompare);\n return sortedVersions[0];\n }\n\n const timedVersions = versions\n .map((v) => ({\n version: v,\n time: time[v],\n }))\n .filter((v) => v.time);\n\n if (timedVersions.length === 0) {\n return undefined;\n }\n\n const timeOrderedVersions = timedVersions.sort(\n (a, b) => new Date(b.time).getTime() - new Date(a.time).getTime()\n );\n return timeOrderedVersions[0].version;\n}\n\n/**\n * Set the latest tag if dist-tags/latest is missing.\n * The last stable version available is used when possible.\n * Otherwise, it uses the latest version not found in dist-tags.\n */\nexport function setupLatestTag(manifest: Manifest): void {\n const distTags = manifest[DIST_TAGS];\n if (distTags.latest) {\n // Tag 'latest' must only be fixed when latest version was blocked\n return;\n }\n\n const versions = Object.keys(manifest.versions);\n if (versions.length === 0) {\n return;\n }\n\n const distTagsVersions = Object.values(distTags);\n const untaggedVersions = versions.filter((v) => semver.valid(v) && !distTagsVersions.includes(v));\n if (untaggedVersions.length === 0) {\n return;\n }\n\n // Try stable versions first (no \"-next\" or \"-beta\", etc.)\n const stableVersions = untaggedVersions.filter((v) => !semver.prerelease(v));\n const latestStableVersion = getLatestVersion(manifest, stableVersions);\n if (latestStableVersion) {\n debug('reassigned latest tag to stable version %s for %s', latestStableVersion, manifest.name);\n distTags.latest = latestStableVersion;\n return;\n }\n\n // Fallback to all untagged versions\n const latestVersion = getLatestVersion(manifest, untaggedVersions);\n if (!latestVersion) {\n return;\n }\n\n debug('reassigned latest tag to pre-release version %s for %s', latestVersion, manifest.name);\n distTags.latest = latestVersion;\n}\n\n/**\n * Set the created and modified times.\n */\nexport function setupCreatedAndModified(manifest: Manifest): void {\n const time = manifest.time;\n if (!time) {\n return;\n }\n\n const times = Object.values(time);\n if (times.length === 0) {\n return;\n }\n\n // Single O(n) pass for the earliest/latest publication time instead of an\n // O(n log n) sort — the result is identical but cheaper on large manifests.\n let earliest = times[0];\n let latest = times[0];\n let earliestMs = new Date(earliest).getTime();\n let latestMs = earliestMs;\n for (let i = 1; i < times.length; i++) {\n const currentMs = new Date(times[i]).getTime();\n if (currentMs < earliestMs) {\n earliestMs = currentMs;\n earliest = times[i];\n }\n if (currentMs > latestMs) {\n latestMs = currentMs;\n latest = times[i];\n }\n }\n time.created = earliest;\n time.modified = latest;\n}\n\n/**\n * Remove `_distfiles` entries which are not used by any version.\n */\nexport function cleanupDistFiles(manifest: Manifest): void {\n const distFiles = manifest._distfiles;\n // Build a Set of active tarball URLs in one pass — O(n) instead of O(n²)\n const activeTarballs = new Set(\n Object.values(manifest.versions)\n .map((v) => v.dist?.tarball)\n .filter((tarball): tarball is string => typeof tarball === 'string')\n );\n Object.keys(distFiles).forEach((key) => {\n if (!activeTarballs.has(distFiles[key].url)) {\n delete distFiles[key];\n }\n });\n}\n\n/**\n * Creates a copy of a manifest suitable for safe, localized mutation.\n *\n * The returned object is shallow-cloned, except for `versions`, `dist-tags`,\n * `time`, and `_distfiles`, which are cloned as independent maps so they can be\n * filtered or modified without affecting the original manifest.\n */\nexport function getManifestClone(manifest: Readonly<Manifest>): Manifest {\n return {\n ...manifest,\n versions: {\n ...manifest.versions,\n },\n [DIST_TAGS]: {\n ...manifest[DIST_TAGS],\n },\n time: {\n ...manifest.time,\n },\n _distfiles: {\n ...manifest._distfiles,\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"manifestUtils.js","names":[],"sources":["../../src/utils/manifestUtils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport semver from 'semver';\n\nimport { DIST_TAGS } from '@verdaccio/core';\nimport type { Manifest } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:manifest');\n\n/**\n * Delete `dist-tags` entries corresponding to missing versions.\n */\nexport function cleanupTags(manifest: Manifest): void {\n const distTags = manifest[DIST_TAGS];\n Object.entries(distTags).forEach(([tag, tagVersion]) => {\n if (!manifest.versions[tagVersion]) {\n debug('removing orphaned dist-tag %s -> %s from %s', tag, tagVersion, manifest.name);\n delete distTags[tag];\n }\n });\n}\n\n/**\n * Delete `time` entries corresponding to missing versions.\n */\nexport function cleanupTime(manifest: Manifest): void {\n const time = manifest.time;\n if (!time) {\n return;\n }\n\n Object.keys(time).forEach((version) => {\n if (!manifest.versions[version]) {\n delete time[version];\n }\n });\n}\n\n/**\n * Get the latest version from a list of versions,\n * ordered by time of their publication stored in the manifest.\n */\nexport function getLatestVersion(manifest: Manifest, versions: string[]): string | undefined {\n const time = manifest.time;\n if (!time) {\n // No time information, it's the best we can do\n const sortedVersions = versions.sort(semver.rcompare);\n return sortedVersions[0];\n }\n\n const timedVersions = versions\n .map((v) => ({\n version: v,\n time: time[v],\n }))\n .filter((v) => v.time);\n\n if (timedVersions.length === 0) {\n return undefined;\n }\n\n const timeOrderedVersions = timedVersions.sort(\n (a, b) => new Date(b.time).getTime() - new Date(a.time).getTime()\n );\n return timeOrderedVersions[0].version;\n}\n\n/**\n * Set the latest tag if dist-tags/latest is missing.\n * The last stable version available is used when possible.\n * Otherwise, it uses the latest version not found in dist-tags.\n */\nexport function setupLatestTag(manifest: Manifest): void {\n const distTags = manifest[DIST_TAGS];\n if (distTags.latest) {\n // Tag 'latest' must only be fixed when latest version was blocked\n return;\n }\n\n const versions = Object.keys(manifest.versions);\n if (versions.length === 0) {\n return;\n }\n\n const distTagsVersions = Object.values(distTags);\n const untaggedVersions = versions.filter((v) => semver.valid(v) && !distTagsVersions.includes(v));\n if (untaggedVersions.length === 0) {\n return;\n }\n\n // Try stable versions first (no \"-next\" or \"-beta\", etc.)\n const stableVersions = untaggedVersions.filter((v) => !semver.prerelease(v));\n const latestStableVersion = getLatestVersion(manifest, stableVersions);\n if (latestStableVersion) {\n debug('reassigned latest tag to stable version %s for %s', latestStableVersion, manifest.name);\n distTags.latest = latestStableVersion;\n return;\n }\n\n // Fallback to all untagged versions\n const latestVersion = getLatestVersion(manifest, untaggedVersions);\n if (!latestVersion) {\n return;\n }\n\n debug('reassigned latest tag to pre-release version %s for %s', latestVersion, manifest.name);\n distTags.latest = latestVersion;\n}\n\n/**\n * Set the created and modified times.\n */\nexport function setupCreatedAndModified(manifest: Manifest): void {\n const time = manifest.time;\n if (!time) {\n return;\n }\n\n const times = Object.values(time);\n if (times.length === 0) {\n return;\n }\n\n // Single O(n) pass for the earliest/latest publication time instead of an\n // O(n log n) sort — the result is identical but cheaper on large manifests.\n let earliest = times[0];\n let latest = times[0];\n let earliestMs = new Date(earliest).getTime();\n let latestMs = earliestMs;\n for (let i = 1; i < times.length; i++) {\n const currentMs = new Date(times[i]).getTime();\n if (currentMs < earliestMs) {\n earliestMs = currentMs;\n earliest = times[i];\n }\n if (currentMs > latestMs) {\n latestMs = currentMs;\n latest = times[i];\n }\n }\n time.created = earliest;\n time.modified = latest;\n}\n\n/**\n * Remove `_distfiles` entries which are not used by any version.\n */\nexport function cleanupDistFiles(manifest: Manifest): void {\n const distFiles = manifest._distfiles;\n // Build a Set of active tarball URLs in one pass — O(n) instead of O(n²)\n const activeTarballs = new Set(\n Object.values(manifest.versions)\n .map((v) => v.dist?.tarball)\n .filter((tarball): tarball is string => typeof tarball === 'string')\n );\n Object.keys(distFiles).forEach((key) => {\n if (!activeTarballs.has(distFiles[key].url)) {\n delete distFiles[key];\n }\n });\n}\n\n/**\n * Creates a copy of a manifest suitable for safe, localized mutation.\n *\n * The returned object is shallow-cloned, except for `versions`, `dist-tags`,\n * `time`, and `_distfiles`, which are cloned as independent maps so they can be\n * filtered or modified without affecting the original manifest.\n */\nexport function getManifestClone(manifest: Readonly<Manifest>): Manifest {\n return {\n ...manifest,\n versions: {\n ...manifest.versions,\n },\n [DIST_TAGS]: {\n ...manifest[DIST_TAGS],\n },\n time: {\n ...manifest.time,\n },\n _distfiles: {\n ...manifest._distfiles,\n },\n };\n}\n"],"mappings":"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"}
@@ -116,6 +116,6 @@ function getManifestClone(manifest) {
116
116
  };
117
117
  }
118
118
  //#endregion
119
- export { cleanupDistFiles, cleanupTags, cleanupTime, getManifestClone, setupCreatedAndModified, setupLatestTag };
119
+ export { cleanupDistFiles, cleanupTags, cleanupTime, getLatestVersion, getManifestClone, setupCreatedAndModified, setupLatestTag };
120
120
 
121
121
  //# sourceMappingURL=manifestUtils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifestUtils.mjs","names":[],"sources":["../../src/utils/manifestUtils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport semver from 'semver';\n\nimport { DIST_TAGS } from '@verdaccio/core';\nimport type { Manifest } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:manifest');\n\n/**\n * Delete `dist-tags` entries corresponding to missing versions.\n */\nexport function cleanupTags(manifest: Manifest): void {\n const distTags = manifest[DIST_TAGS];\n Object.entries(distTags).forEach(([tag, tagVersion]) => {\n if (!manifest.versions[tagVersion]) {\n debug('removing orphaned dist-tag %s -> %s from %s', tag, tagVersion, manifest.name);\n delete distTags[tag];\n }\n });\n}\n\n/**\n * Delete `time` entries corresponding to missing versions.\n */\nexport function cleanupTime(manifest: Manifest): void {\n const time = manifest.time;\n if (!time) {\n return;\n }\n\n Object.keys(time).forEach((version) => {\n if (!manifest.versions[version]) {\n delete time[version];\n }\n });\n}\n\n/**\n * Get the latest version from a list of versions,\n * ordered by time of their publication stored in the manifest.\n */\nexport function getLatestVersion(manifest: Manifest, versions: string[]): string | undefined {\n const time = manifest.time;\n if (!time) {\n // No time information, it's the best we can do\n const sortedVersions = versions.sort(semver.rcompare);\n return sortedVersions[0];\n }\n\n const timedVersions = versions\n .map((v) => ({\n version: v,\n time: time[v],\n }))\n .filter((v) => v.time);\n\n if (timedVersions.length === 0) {\n return undefined;\n }\n\n const timeOrderedVersions = timedVersions.sort(\n (a, b) => new Date(b.time).getTime() - new Date(a.time).getTime()\n );\n return timeOrderedVersions[0].version;\n}\n\n/**\n * Set the latest tag if dist-tags/latest is missing.\n * The last stable version available is used when possible.\n * Otherwise, it uses the latest version not found in dist-tags.\n */\nexport function setupLatestTag(manifest: Manifest): void {\n const distTags = manifest[DIST_TAGS];\n if (distTags.latest) {\n // Tag 'latest' must only be fixed when latest version was blocked\n return;\n }\n\n const versions = Object.keys(manifest.versions);\n if (versions.length === 0) {\n return;\n }\n\n const distTagsVersions = Object.values(distTags);\n const untaggedVersions = versions.filter((v) => semver.valid(v) && !distTagsVersions.includes(v));\n if (untaggedVersions.length === 0) {\n return;\n }\n\n // Try stable versions first (no \"-next\" or \"-beta\", etc.)\n const stableVersions = untaggedVersions.filter((v) => !semver.prerelease(v));\n const latestStableVersion = getLatestVersion(manifest, stableVersions);\n if (latestStableVersion) {\n debug('reassigned latest tag to stable version %s for %s', latestStableVersion, manifest.name);\n distTags.latest = latestStableVersion;\n return;\n }\n\n // Fallback to all untagged versions\n const latestVersion = getLatestVersion(manifest, untaggedVersions);\n if (!latestVersion) {\n return;\n }\n\n debug('reassigned latest tag to pre-release version %s for %s', latestVersion, manifest.name);\n distTags.latest = latestVersion;\n}\n\n/**\n * Set the created and modified times.\n */\nexport function setupCreatedAndModified(manifest: Manifest): void {\n const time = manifest.time;\n if (!time) {\n return;\n }\n\n const times = Object.values(time);\n if (times.length === 0) {\n return;\n }\n\n // Single O(n) pass for the earliest/latest publication time instead of an\n // O(n log n) sort — the result is identical but cheaper on large manifests.\n let earliest = times[0];\n let latest = times[0];\n let earliestMs = new Date(earliest).getTime();\n let latestMs = earliestMs;\n for (let i = 1; i < times.length; i++) {\n const currentMs = new Date(times[i]).getTime();\n if (currentMs < earliestMs) {\n earliestMs = currentMs;\n earliest = times[i];\n }\n if (currentMs > latestMs) {\n latestMs = currentMs;\n latest = times[i];\n }\n }\n time.created = earliest;\n time.modified = latest;\n}\n\n/**\n * Remove `_distfiles` entries which are not used by any version.\n */\nexport function cleanupDistFiles(manifest: Manifest): void {\n const distFiles = manifest._distfiles;\n // Build a Set of active tarball URLs in one pass — O(n) instead of O(n²)\n const activeTarballs = new Set(\n Object.values(manifest.versions)\n .map((v) => v.dist?.tarball)\n .filter((tarball): tarball is string => typeof tarball === 'string')\n );\n Object.keys(distFiles).forEach((key) => {\n if (!activeTarballs.has(distFiles[key].url)) {\n delete distFiles[key];\n }\n });\n}\n\n/**\n * Creates a copy of a manifest suitable for safe, localized mutation.\n *\n * The returned object is shallow-cloned, except for `versions`, `dist-tags`,\n * `time`, and `_distfiles`, which are cloned as independent maps so they can be\n * filtered or modified without affecting the original manifest.\n */\nexport function getManifestClone(manifest: Readonly<Manifest>): Manifest {\n return {\n ...manifest,\n versions: {\n ...manifest.versions,\n },\n [DIST_TAGS]: {\n ...manifest[DIST_TAGS],\n },\n time: {\n ...manifest.time,\n },\n _distfiles: {\n ...manifest._distfiles,\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"manifestUtils.mjs","names":[],"sources":["../../src/utils/manifestUtils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport semver from 'semver';\n\nimport { DIST_TAGS } from '@verdaccio/core';\nimport type { Manifest } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:manifest');\n\n/**\n * Delete `dist-tags` entries corresponding to missing versions.\n */\nexport function cleanupTags(manifest: Manifest): void {\n const distTags = manifest[DIST_TAGS];\n Object.entries(distTags).forEach(([tag, tagVersion]) => {\n if (!manifest.versions[tagVersion]) {\n debug('removing orphaned dist-tag %s -> %s from %s', tag, tagVersion, manifest.name);\n delete distTags[tag];\n }\n });\n}\n\n/**\n * Delete `time` entries corresponding to missing versions.\n */\nexport function cleanupTime(manifest: Manifest): void {\n const time = manifest.time;\n if (!time) {\n return;\n }\n\n Object.keys(time).forEach((version) => {\n if (!manifest.versions[version]) {\n delete time[version];\n }\n });\n}\n\n/**\n * Get the latest version from a list of versions,\n * ordered by time of their publication stored in the manifest.\n */\nexport function getLatestVersion(manifest: Manifest, versions: string[]): string | undefined {\n const time = manifest.time;\n if (!time) {\n // No time information, it's the best we can do\n const sortedVersions = versions.sort(semver.rcompare);\n return sortedVersions[0];\n }\n\n const timedVersions = versions\n .map((v) => ({\n version: v,\n time: time[v],\n }))\n .filter((v) => v.time);\n\n if (timedVersions.length === 0) {\n return undefined;\n }\n\n const timeOrderedVersions = timedVersions.sort(\n (a, b) => new Date(b.time).getTime() - new Date(a.time).getTime()\n );\n return timeOrderedVersions[0].version;\n}\n\n/**\n * Set the latest tag if dist-tags/latest is missing.\n * The last stable version available is used when possible.\n * Otherwise, it uses the latest version not found in dist-tags.\n */\nexport function setupLatestTag(manifest: Manifest): void {\n const distTags = manifest[DIST_TAGS];\n if (distTags.latest) {\n // Tag 'latest' must only be fixed when latest version was blocked\n return;\n }\n\n const versions = Object.keys(manifest.versions);\n if (versions.length === 0) {\n return;\n }\n\n const distTagsVersions = Object.values(distTags);\n const untaggedVersions = versions.filter((v) => semver.valid(v) && !distTagsVersions.includes(v));\n if (untaggedVersions.length === 0) {\n return;\n }\n\n // Try stable versions first (no \"-next\" or \"-beta\", etc.)\n const stableVersions = untaggedVersions.filter((v) => !semver.prerelease(v));\n const latestStableVersion = getLatestVersion(manifest, stableVersions);\n if (latestStableVersion) {\n debug('reassigned latest tag to stable version %s for %s', latestStableVersion, manifest.name);\n distTags.latest = latestStableVersion;\n return;\n }\n\n // Fallback to all untagged versions\n const latestVersion = getLatestVersion(manifest, untaggedVersions);\n if (!latestVersion) {\n return;\n }\n\n debug('reassigned latest tag to pre-release version %s for %s', latestVersion, manifest.name);\n distTags.latest = latestVersion;\n}\n\n/**\n * Set the created and modified times.\n */\nexport function setupCreatedAndModified(manifest: Manifest): void {\n const time = manifest.time;\n if (!time) {\n return;\n }\n\n const times = Object.values(time);\n if (times.length === 0) {\n return;\n }\n\n // Single O(n) pass for the earliest/latest publication time instead of an\n // O(n log n) sort — the result is identical but cheaper on large manifests.\n let earliest = times[0];\n let latest = times[0];\n let earliestMs = new Date(earliest).getTime();\n let latestMs = earliestMs;\n for (let i = 1; i < times.length; i++) {\n const currentMs = new Date(times[i]).getTime();\n if (currentMs < earliestMs) {\n earliestMs = currentMs;\n earliest = times[i];\n }\n if (currentMs > latestMs) {\n latestMs = currentMs;\n latest = times[i];\n }\n }\n time.created = earliest;\n time.modified = latest;\n}\n\n/**\n * Remove `_distfiles` entries which are not used by any version.\n */\nexport function cleanupDistFiles(manifest: Manifest): void {\n const distFiles = manifest._distfiles;\n // Build a Set of active tarball URLs in one pass — O(n) instead of O(n²)\n const activeTarballs = new Set(\n Object.values(manifest.versions)\n .map((v) => v.dist?.tarball)\n .filter((tarball): tarball is string => typeof tarball === 'string')\n );\n Object.keys(distFiles).forEach((key) => {\n if (!activeTarballs.has(distFiles[key].url)) {\n delete distFiles[key];\n }\n });\n}\n\n/**\n * Creates a copy of a manifest suitable for safe, localized mutation.\n *\n * The returned object is shallow-cloned, except for `versions`, `dist-tags`,\n * `time`, and `_distfiles`, which are cloned as independent maps so they can be\n * filtered or modified without affecting the original manifest.\n */\nexport function getManifestClone(manifest: Readonly<Manifest>): Manifest {\n return {\n ...manifest,\n versions: {\n ...manifest.versions,\n },\n [DIST_TAGS]: {\n ...manifest[DIST_TAGS],\n },\n time: {\n ...manifest.time,\n },\n _distfiles: {\n ...manifest._distfiles,\n },\n };\n}\n"],"mappings":";;;;AAMA,IAAM,QAAQ,WAAW,0CAA0C;;;;AAKnE,SAAgB,YAAY,UAA0B;CACpD,MAAM,WAAW,SAAS;CAC1B,OAAO,QAAQ,QAAQ,CAAC,CAAC,SAAS,CAAC,KAAK,gBAAgB;EACtD,IAAI,CAAC,SAAS,SAAS,aAAa;GAClC,MAAM,+CAA+C,KAAK,YAAY,SAAS,IAAI;GACnF,OAAO,SAAS;EAClB;CACF,CAAC;AACH;;;;AAKA,SAAgB,YAAY,UAA0B;CACpD,MAAM,OAAO,SAAS;CACtB,IAAI,CAAC,MACH;CAGF,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,YAAY;EACrC,IAAI,CAAC,SAAS,SAAS,UACrB,OAAO,KAAK;CAEhB,CAAC;AACH;;;;;AAMA,SAAgB,iBAAiB,UAAoB,UAAwC;CAC3F,MAAM,OAAO,SAAS;CACtB,IAAI,CAAC,MAGH,OADuB,SAAS,KAAK,OAAO,QACrC,CAAA,CAAe;CAGxB,MAAM,gBAAgB,SACnB,KAAK,OAAO;EACX,SAAS;EACT,MAAM,KAAK;CACb,EAAE,CAAC,CACF,QAAQ,MAAM,EAAE,IAAI;CAEvB,IAAI,cAAc,WAAW,GAC3B;CAMF,OAH4B,cAAc,MACvC,GAAG,MAAM,IAAI,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,IAAI,IAAI,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAE3D,CAAA,CAAoB,EAAE,CAAC;AAChC;;;;;;AAOA,SAAgB,eAAe,UAA0B;CACvD,MAAM,WAAW,SAAS;CAC1B,IAAI,SAAS,QAEX;CAGF,MAAM,WAAW,OAAO,KAAK,SAAS,QAAQ;CAC9C,IAAI,SAAS,WAAW,GACtB;CAGF,MAAM,mBAAmB,OAAO,OAAO,QAAQ;CAC/C,MAAM,mBAAmB,SAAS,QAAQ,MAAM,OAAO,MAAM,CAAC,KAAK,CAAC,iBAAiB,SAAS,CAAC,CAAC;CAChG,IAAI,iBAAiB,WAAW,GAC9B;CAKF,MAAM,sBAAsB,iBAAiB,UADtB,iBAAiB,QAAQ,MAAM,CAAC,OAAO,WAAW,CAAC,CACnB,CAAc;CACrE,IAAI,qBAAqB;EACvB,MAAM,qDAAqD,qBAAqB,SAAS,IAAI;EAC7F,SAAS,SAAS;EAClB;CACF;CAGA,MAAM,gBAAgB,iBAAiB,UAAU,gBAAgB;CACjE,IAAI,CAAC,eACH;CAGF,MAAM,0DAA0D,eAAe,SAAS,IAAI;CAC5F,SAAS,SAAS;AACpB;;;;AAKA,SAAgB,wBAAwB,UAA0B;CAChE,MAAM,OAAO,SAAS;CACtB,IAAI,CAAC,MACH;CAGF,MAAM,QAAQ,OAAO,OAAO,IAAI;CAChC,IAAI,MAAM,WAAW,GACnB;CAKF,IAAI,WAAW,MAAM;CACrB,IAAI,SAAS,MAAM;CACnB,IAAI,aAAa,IAAI,KAAK,QAAQ,CAAC,CAAC,QAAQ;CAC5C,IAAI,WAAW;CACf,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,YAAY,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,QAAQ;EAC7C,IAAI,YAAY,YAAY;GAC1B,aAAa;GACb,WAAW,MAAM;EACnB;EACA,IAAI,YAAY,UAAU;GACxB,WAAW;GACX,SAAS,MAAM;EACjB;CACF;CACA,KAAK,UAAU;CACf,KAAK,WAAW;AAClB;;;;AAKA,SAAgB,iBAAiB,UAA0B;CACzD,MAAM,YAAY,SAAS;CAE3B,MAAM,iBAAiB,IAAI,IACzB,OAAO,OAAO,SAAS,QAAQ,CAAC,CAC7B,KAAK,MAAM,EAAE,MAAM,OAAO,CAAC,CAC3B,QAAQ,YAA+B,OAAO,YAAY,QAAQ,CACvE;CACA,OAAO,KAAK,SAAS,CAAC,CAAC,SAAS,QAAQ;EACtC,IAAI,CAAC,eAAe,IAAI,UAAU,IAAI,CAAC,GAAG,GACxC,OAAO,UAAU;CAErB,CAAC;AACH;;;;;;;;AASA,SAAgB,iBAAiB,UAAwC;CACvE,OAAO;EACL,GAAG;EACH,UAAU,EACR,GAAG,SAAS,SACd;GACC,YAAY,EACX,GAAG,SAAS,WACd;EACA,MAAM,EACJ,GAAG,SAAS,KACd;EACA,YAAY,EACV,GAAG,SAAS,WACd;CACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/package-filter",
3
- "version": "13.1.0",
3
+ "version": "13.2.0",
4
4
  "description": "Package filter plugin for Verdaccio that allows blocking packages by name, scope, version or date",
5
5
  "keywords": [
6
6
  "enterprise",
@@ -50,17 +50,17 @@
50
50
  "./build/*": "./build/*"
51
51
  },
52
52
  "dependencies": {
53
- "@verdaccio/core": "8.2.0",
53
+ "@verdaccio/core": "8.2.2",
54
54
  "debug": "4.4.3",
55
- "semver": "7.7.4"
55
+ "semver": "7.8.5"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/debug": "4.1.12",
59
- "@verdaccio/config": "8.2.0",
60
- "@verdaccio/logger": "8.1.0",
61
- "@verdaccio/types": "13.0.5",
62
- "vite": "8.0.16",
63
- "vitest": "4.1.2"
59
+ "@verdaccio/config": "8.2.2",
60
+ "@verdaccio/logger": "8.1.2",
61
+ "@verdaccio/types": "13.0.6",
62
+ "vite": "8.1.5",
63
+ "vitest": "4.1.10"
64
64
  },
65
65
  "engines": {
66
66
  "node": ">=22"