@verdaccio/package-filter 14.0.0-next-9.30
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.
- package/LICENSE +21 -0
- package/README.md +277 -0
- package/build/_virtual/_rolldown/runtime.js +23 -0
- package/build/config/parser.d.ts +2 -0
- package/build/config/parser.js +56 -0
- package/build/config/parser.js.map +1 -0
- package/build/config/parser.mjs +54 -0
- package/build/config/parser.mjs.map +1 -0
- package/build/config/types.d.ts +39 -0
- package/build/filtering/matcher.d.ts +8 -0
- package/build/filtering/matcher.js +71 -0
- package/build/filtering/matcher.js.map +1 -0
- package/build/filtering/matcher.mjs +69 -0
- package/build/filtering/matcher.mjs.map +1 -0
- package/build/filtering/packageVersion.d.ts +20 -0
- package/build/filtering/packageVersion.js +129 -0
- package/build/filtering/packageVersion.js.map +1 -0
- package/build/filtering/packageVersion.mjs +127 -0
- package/build/filtering/packageVersion.mjs.map +1 -0
- package/build/filtering/publishDate.d.ts +6 -0
- package/build/filtering/publishDate.js +33 -0
- package/build/filtering/publishDate.js.map +1 -0
- package/build/filtering/publishDate.mjs +31 -0
- package/build/filtering/publishDate.mjs.map +1 -0
- package/build/filtering/types.d.ts +24 -0
- package/build/filtering/types.js +11 -0
- package/build/filtering/types.js.map +1 -0
- package/build/filtering/types.mjs +11 -0
- package/build/filtering/types.mjs.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.js +12 -0
- package/build/index.js.map +1 -0
- package/build/index.mjs +7 -0
- package/build/index.mjs.map +1 -0
- package/build/packageFilter.d.ts +10 -0
- package/build/packageFilter.js +80 -0
- package/build/packageFilter.js.map +1 -0
- package/build/packageFilter.mjs +78 -0
- package/build/packageFilter.mjs.map +1 -0
- package/build/utils/jsonUtils.d.ts +1 -0
- package/build/utils/jsonUtils.js +12 -0
- package/build/utils/jsonUtils.js.map +1 -0
- package/build/utils/jsonUtils.mjs +11 -0
- package/build/utils/jsonUtils.mjs.map +1 -0
- package/build/utils/manifestUtils.d.ts +36 -0
- package/build/utils/manifestUtils.js +115 -0
- package/build/utils/manifestUtils.js.map +1 -0
- package/build/utils/manifestUtils.mjs +107 -0
- package/build/utils/manifestUtils.mjs.map +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Verdaccio contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# @verdaccio/package-filter
|
|
2
|
+
|
|
3
|
+
[](https://verdaccio.org)
|
|
4
|
+
[](https://github.com/verdaccio/verdaccio/blob/master/LICENSE)
|
|
5
|
+
[](https://github.com/verdaccio/verdaccio)
|
|
6
|
+
|
|
7
|
+
[](https://verdaccio.org/docs)
|
|
8
|
+
[](https://discord.com/channels/388674437219745793)
|
|
9
|
+
|
|
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.
|
|
11
|
+
|
|
12
|
+
## Use Cases
|
|
13
|
+
|
|
14
|
+
- **Supply-chain security** - block known-malicious packages, scopes, or version ranges.
|
|
15
|
+
- **Version quarantine** - hide versions younger than N days so newly published code has time to be reviewed before adoption.
|
|
16
|
+
- **Date freeze** - pin the registry to a point-in-time snapshot (e.g., only serve versions published before a specific date).
|
|
17
|
+
- **Emergency response** - immediately block a compromised version while keeping older safe versions available.
|
|
18
|
+
|
|
19
|
+
## How It Works
|
|
20
|
+
|
|
21
|
+
The plugin implements Verdaccio's `ManifestFilter` interface. Every time Verdaccio serves a package manifest (via `npm install`, `npm view`, search, or the web UI), the manifest passes through `filter_metadata()` before reaching the client.
|
|
22
|
+
|
|
23
|
+
The processing pipeline:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Incoming manifest
|
|
27
|
+
1. Clone manifest (avoids mutating cached data)
|
|
28
|
+
2. Apply block/replace rules by package name, scope, or version range
|
|
29
|
+
3. Apply date-based filtering (minAgeDays / dateThreshold)
|
|
30
|
+
4. Cleanup: remove orphaned dist-tags, time entries, and dist files
|
|
31
|
+
5. Recalculate "latest" tag from remaining versions
|
|
32
|
+
Output filtered manifest
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Filtered versions are removed from the manifest metadata only. Tarballs already downloaded or cached are not affected.
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
The plugin is enabled by default in Verdaccio's `config.yaml`. With no rules configured, it acts as a no-op passthrough.
|
|
40
|
+
|
|
41
|
+
### Minimal Configuration (no-op)
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
filters:
|
|
45
|
+
'@verdaccio/package-filter':
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Block Versions by Age
|
|
49
|
+
|
|
50
|
+
Hide versions published less than N days ago. This is a global rule applied to all packages.
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
filters:
|
|
54
|
+
'@verdaccio/package-filter':
|
|
55
|
+
minAgeDays: 30
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Block Versions by Date
|
|
59
|
+
|
|
60
|
+
Only serve versions published before a specific date.
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
filters:
|
|
64
|
+
'@verdaccio/package-filter':
|
|
65
|
+
dateThreshold: '2024-01-01'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
When both `minAgeDays` and `dateThreshold` are set, the **earlier** cutoff wins (more versions are filtered).
|
|
69
|
+
|
|
70
|
+
### Block by Scope
|
|
71
|
+
|
|
72
|
+
Block all packages under a scope.
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
filters:
|
|
76
|
+
'@verdaccio/package-filter':
|
|
77
|
+
block:
|
|
78
|
+
- scope: '@evilscope'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Block by Package Name
|
|
82
|
+
|
|
83
|
+
Block all versions of a specific package.
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
filters:
|
|
87
|
+
'@verdaccio/package-filter':
|
|
88
|
+
block:
|
|
89
|
+
- package: 'malicious-pkg'
|
|
90
|
+
- package: '@coolauthor/stolen'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Block by Version Range
|
|
94
|
+
|
|
95
|
+
Block specific semver ranges of a package. Uses [semver](https://www.npmjs.com/package/semver) syntax.
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
filters:
|
|
99
|
+
'@verdaccio/package-filter':
|
|
100
|
+
block:
|
|
101
|
+
- package: '@coolauthor/stolen'
|
|
102
|
+
versions: '>2.0.1'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Multiple version ranges for the same package are merged:
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
filters:
|
|
109
|
+
'@verdaccio/package-filter':
|
|
110
|
+
block:
|
|
111
|
+
- package: 'some-pkg'
|
|
112
|
+
versions: '>2.0.0'
|
|
113
|
+
- package: 'some-pkg'
|
|
114
|
+
versions: '<1.3.0'
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This leaves only versions in `[1.3.0, 2.0.0]` visible.
|
|
118
|
+
|
|
119
|
+
### Replace Strategy
|
|
120
|
+
|
|
121
|
+
Instead of removing blocked versions, substitute them with the nearest older safe version. Useful when a blocked version is a transitive dependency and removing it would break installs.
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
filters:
|
|
125
|
+
'@verdaccio/package-filter':
|
|
126
|
+
block:
|
|
127
|
+
- package: '@coolauthor/stolen'
|
|
128
|
+
versions: '>2.0.1'
|
|
129
|
+
strategy: replace
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
With `replace`, `npm install @coolauthor/stolen@3.0.0` still resolves, but the client receives the content of `2.0.1`.
|
|
133
|
+
|
|
134
|
+
### Whitelisting Blocked Packages
|
|
135
|
+
|
|
136
|
+
In some cases, you may need to bypass your own rules and whitelist certain scopes, packages, or package versions even though they fall within a blocked area. For example, this might happen when you own some private registry or you really need the latest version of some package and you ensured that its code is safe. You can configure whitelist rules with the `allow` clause, which follows the same rules as `block`. Rules specified in `allow` take precedence over all blocking rules (even `minAgeDays` and `dateThreshold`).
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
filters:
|
|
140
|
+
'@verdaccio/package-filter':
|
|
141
|
+
minAgeDays: 30 # Block versions younger than 30 days
|
|
142
|
+
allow:
|
|
143
|
+
- scope: '@my-company-scope' # Don't block the scope that belongs to you
|
|
144
|
+
- package: '@coolauthor/not-stolen' # Don't block package you really trust
|
|
145
|
+
- package: semver
|
|
146
|
+
versions: '7.7.3' # Don't block specific package version that you know is not malicious
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
You can also combine `allow` with `block` rules to create fine-grained exceptions:
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
filters:
|
|
153
|
+
'@verdaccio/package-filter':
|
|
154
|
+
block:
|
|
155
|
+
- scope: '@untrusted'
|
|
156
|
+
allow:
|
|
157
|
+
- package: '@untrusted/but-verified'
|
|
158
|
+
- package: 'some-pkg'
|
|
159
|
+
versions: '2.1.0'
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Allow rules are checked before block rules. The granularity levels:
|
|
163
|
+
|
|
164
|
+
| Allow rule | Effect |
|
|
165
|
+
| ------------------------------------ | ----------------------------------- |
|
|
166
|
+
| `scope: '@x'` | Entire scope bypasses all rules |
|
|
167
|
+
| `package: 'x'` | Entire package bypasses all rules |
|
|
168
|
+
| `package: 'x'` + `versions: '1.0.0'` | Only matching versions are exempted |
|
|
169
|
+
|
|
170
|
+
### Full Example
|
|
171
|
+
|
|
172
|
+
```yaml
|
|
173
|
+
filters:
|
|
174
|
+
'@verdaccio/package-filter':
|
|
175
|
+
minAgeDays: 7
|
|
176
|
+
dateThreshold: '2025-01-01'
|
|
177
|
+
block:
|
|
178
|
+
- scope: '@malicious'
|
|
179
|
+
- package: 'typosquat-pkg'
|
|
180
|
+
- package: 'compromised-lib'
|
|
181
|
+
versions: '>=3.0.0'
|
|
182
|
+
- package: 'legacy-lib'
|
|
183
|
+
versions: '>=2.0.0'
|
|
184
|
+
strategy: replace
|
|
185
|
+
allow:
|
|
186
|
+
- scope: '@my-org'
|
|
187
|
+
- package: 'compromised-lib'
|
|
188
|
+
versions: '3.0.1'
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Disabling the Plugin
|
|
192
|
+
|
|
193
|
+
Remove or comment out the `filters` section in `config.yaml`:
|
|
194
|
+
|
|
195
|
+
```yaml
|
|
196
|
+
# filters:
|
|
197
|
+
# '@verdaccio/package-filter':
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Manifest Cleanup
|
|
201
|
+
|
|
202
|
+
After filtering, the plugin automatically cleans up the manifest:
|
|
203
|
+
|
|
204
|
+
- **Dist-tags**: tags pointing to removed versions are deleted.
|
|
205
|
+
- **Latest tag**: if `latest` was removed, the most recent remaining stable version becomes `latest`. If no stable version exists, the most recent pre-release is used.
|
|
206
|
+
- **Time entries**: publish timestamps for removed versions are deleted.
|
|
207
|
+
- **Created/modified**: recalculated from remaining time entries.
|
|
208
|
+
- **Dist files**: `_distfiles` entries not referenced by any remaining version are removed.
|
|
209
|
+
|
|
210
|
+
## Debugging
|
|
211
|
+
|
|
212
|
+
The plugin uses the [`debug`](https://www.npmjs.com/package/debug) library under the `verdaccio:plugin:package-filter` namespace.
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# See all plugin debug output
|
|
216
|
+
DEBUG=verdaccio:plugin:package-filter* verdaccio
|
|
217
|
+
|
|
218
|
+
# See only config parsing
|
|
219
|
+
DEBUG=verdaccio:plugin:package-filter:config verdaccio
|
|
220
|
+
|
|
221
|
+
# See only filtering decisions
|
|
222
|
+
DEBUG=verdaccio:plugin:package-filter:filter verdaccio
|
|
223
|
+
|
|
224
|
+
# See manifest cleanup details
|
|
225
|
+
DEBUG=verdaccio:plugin:package-filter:manifest verdaccio
|
|
226
|
+
|
|
227
|
+
# Combine with other verdaccio debug namespaces
|
|
228
|
+
DEBUG=verdaccio:plugin:package-filter*,verdaccio:storage verdaccio
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Plugin History
|
|
232
|
+
|
|
233
|
+
Originally authored by Ansile as [verdaccio-plugin-secfilter](https://github.com/Ansile/verdaccio-plugin-secfilter) (MIT license). Forked by Vitalii Sugrobov as [verdaccio-plugin-delay-filter](https://github.com/vsugrob/verdaccio-plugin-delay-filter). Now maintained as a built-in plugin in the Verdaccio monorepo.
|
|
234
|
+
|
|
235
|
+
## Donations
|
|
236
|
+
|
|
237
|
+
Verdaccio is run by **volunteers**; nobody is working full-time on it. If you find this project to be useful and would like to support its development, consider making a donation - **your logo might end up in this readme.**
|
|
238
|
+
|
|
239
|
+
**[Donate](https://opencollective.com/verdaccio)** starting from _\$1/month_ or just one single contribution.
|
|
240
|
+
|
|
241
|
+
## Report a vulnerability
|
|
242
|
+
|
|
243
|
+
If you want to report a security vulnerability, please follow the steps which we have defined for you in our [security policy](https://github.com/verdaccio/verdaccio/security/policy).
|
|
244
|
+
|
|
245
|
+
## Open Collective Sponsors
|
|
246
|
+
|
|
247
|
+
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/verdaccio/contribute)]
|
|
248
|
+
|
|
249
|
+
[](https://opencollective.com/verdaccio/sponsor/0/website)
|
|
250
|
+
[](https://opencollective.com/verdaccio/sponsor/1/website)
|
|
251
|
+
[](https://opencollective.com/verdaccio/sponsor/2/website)
|
|
252
|
+
[](https://opencollective.com/verdaccio/sponsor/3/website)
|
|
253
|
+
[](https://opencollective.com/verdaccio/sponsor/4/website)
|
|
254
|
+
[](https://opencollective.com/verdaccio/sponsor/5/website)
|
|
255
|
+
[](https://opencollective.com/verdaccio/sponsor/6/website)
|
|
256
|
+
[](https://opencollective.com/verdaccio/sponsor/7/website)
|
|
257
|
+
[](https://opencollective.com/verdaccio/sponsor/8/website)
|
|
258
|
+
[](https://opencollective.com/verdaccio/sponsor/9/website)
|
|
259
|
+
|
|
260
|
+
## Open Collective Backers
|
|
261
|
+
|
|
262
|
+
Thank you to all our backers! [[Become a backer](https://opencollective.com/verdaccio/contribute)]
|
|
263
|
+
|
|
264
|
+
[](https://opencollective.com/verdaccio/contributes)
|
|
265
|
+
|
|
266
|
+
## Contributors
|
|
267
|
+
|
|
268
|
+
This project exists thanks to all the people who contribute. [[Contribute](https://github.com/verdaccio/verdaccio/blob/master/CONTRIBUTING.md)].
|
|
269
|
+
|
|
270
|
+
[](https://github.com/verdaccio/verdaccio/graphs/contributors)
|
|
271
|
+
|
|
272
|
+
## License
|
|
273
|
+
|
|
274
|
+
Verdaccio is [MIT licensed](https://github.com/verdaccio/verdaccio/blob/master/LICENSE).
|
|
275
|
+
|
|
276
|
+
The Verdaccio documentation and logos (excluding /thanks, e.g., .md, .png, .sketch files within the /assets folder) are
|
|
277
|
+
[Creative Commons licensed](https://creativecommons.org/licenses/by/4.0/).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
exports.__toESM = __toESM;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.js");
|
|
2
|
+
let debug = require("debug");
|
|
3
|
+
debug = require_runtime.__toESM(debug);
|
|
4
|
+
let semver = require("semver");
|
|
5
|
+
//#region src/config/parser.ts
|
|
6
|
+
var debug$1 = (0, debug.default)("verdaccio:plugin:package-filter:config");
|
|
7
|
+
function parseConfigRules(configRules) {
|
|
8
|
+
const ruleMap = /* @__PURE__ */ new Map();
|
|
9
|
+
for (const rule of configRules) {
|
|
10
|
+
if ("scope" in rule && typeof rule.scope === "string") {
|
|
11
|
+
if (!rule.scope.startsWith("@")) throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);
|
|
12
|
+
ruleMap.set(rule.scope, "scope");
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if ("package" in rule && !("versions" in rule)) {
|
|
16
|
+
ruleMap.set(rule.package, "package");
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if ("package" in rule && "versions" in rule) {
|
|
20
|
+
const previousConfig = ruleMap.get(rule.package) || { versions: [] };
|
|
21
|
+
if (typeof previousConfig === "string") throw new Error(`Package ${rule.package} is already specified by another strict rule ${previousConfig}`);
|
|
22
|
+
const range = new semver.Range(rule.versions);
|
|
23
|
+
ruleMap.set(rule.package, {
|
|
24
|
+
versions: [...previousConfig.versions, range],
|
|
25
|
+
strategy: rule.strategy ?? "block"
|
|
26
|
+
});
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);
|
|
30
|
+
}
|
|
31
|
+
return ruleMap;
|
|
32
|
+
}
|
|
33
|
+
function parseConfig(config) {
|
|
34
|
+
debug$1("parsing config: %o", config);
|
|
35
|
+
const blockMap = parseConfigRules(config.block ?? []);
|
|
36
|
+
const allowMap = parseConfigRules(config.allow ?? []);
|
|
37
|
+
debug$1("parsed %d block rules, %d allow rules", blockMap.size, allowMap.size);
|
|
38
|
+
const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;
|
|
39
|
+
if (dateThreshold && isNaN(dateThreshold.getTime())) throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);
|
|
40
|
+
const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;
|
|
41
|
+
let minAgeMs = null;
|
|
42
|
+
if (minAgeDays !== null) {
|
|
43
|
+
if (isNaN(minAgeDays) || minAgeDays < 0) throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);
|
|
44
|
+
minAgeMs = minAgeDays * 24 * 60 * 60 * 1e3;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
dateThreshold,
|
|
48
|
+
minAgeMs,
|
|
49
|
+
blockRules: blockMap,
|
|
50
|
+
allowRules: allowMap
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
exports.parseConfig = parseConfig;
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +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,yCAAyC;AAElE,SAAS,iBAAiB,aAAoD;CAC5E,MAAM,0BAAU,IAAI,KAAyB;AAC7C,MAAK,MAAM,QAAQ,aAAa;AAC9B,MAAI,WAAW,QAAQ,OAAO,KAAK,UAAU,UAAU;AACrD,OAAI,CAAC,KAAK,MAAM,WAAW,IAAI,CAC7B,OAAM,IAAI,UAAU,yCAAyC,KAAK,QAAQ;AAG5E,WAAQ,IAAI,KAAK,OAAO,QAAQ;AAChC;;AAGF,MAAI,aAAa,QAAQ,EAAE,cAAc,OAAO;AAC9C,WAAQ,IAAI,KAAK,SAAS,UAAU;AACpC;;AAGF,MAAI,aAAa,QAAQ,cAAc,MAAM;GAC3C,MAAM,iBAAiB,QAAQ,IAAI,KAAK,QAAQ,IAAI,EAAE,UAAU,EAAE,EAAE;AAEpE,OAAI,OAAO,mBAAmB,SAC5B,OAAM,IAAI,MACR,WAAW,KAAK,QAAQ,+CAA+C,iBACxE;GAIH,MAAM,QAAQ,IAAI,OAAA,MAAM,KAAK,SAAS;AACtC,WAAQ,IAAI,KAAK,SAAS;IACxB,UAAU,CAAC,GAAG,eAAe,UAAU,MAAM;IAC7C,UAAU,KAAK,YAAY;IAC5B,CAAC;AAEF;;AAGF,QAAM,IAAI,UAAU,wBAAwB,KAAK,UAAU,MAAM,MAAM,EAAE,GAAG;;AAG9E,QAAO;;AAGT,SAAgB,YAAY,QAAoC;AAC9D,SAAM,sBAAsB,OAAO;CACnC,MAAM,WAAW,iBAAiB,OAAO,SAAS,EAAE,CAAC;CACrD,MAAM,WAAW,iBAAiB,OAAO,SAAS,EAAE,CAAC;AACrD,SAAM,yCAAyC,SAAS,MAAM,SAAS,KAAK;CAC5E,MAAM,gBAAgB,OAAO,gBAAgB,IAAI,KAAK,OAAO,cAAc,GAAG;AAC9E,KAAI,iBAAiB,MAAM,cAAc,SAAS,CAAC,CACjD,OAAM,IAAI,UAAU,gBAAgB,OAAO,cAAc,iCAAiC;CAG5F,MAAM,aAAa,OAAO,aAAa,OAAO,OAAO,WAAW,GAAG;CACnE,IAAI,WAA0B;AAC9B,KAAI,eAAe,MAAM;AACvB,MAAI,MAAM,WAAW,IAAI,aAAa,EACpC,OAAM,IAAI,UAAU,kBAAkB,OAAO,WAAW,8BAA8B;AAGxF,aAAW,aAAa,KAAK,KAAK,KAAK;;AAGzC,QAAO;EACL;EACA;EACA,YAAY;EACZ,YAAY;EACb"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import buildDebug from "debug";
|
|
2
|
+
import { Range } from "semver";
|
|
3
|
+
//#region src/config/parser.ts
|
|
4
|
+
var debug = buildDebug("verdaccio:plugin:package-filter:config");
|
|
5
|
+
function parseConfigRules(configRules) {
|
|
6
|
+
const ruleMap = /* @__PURE__ */ new Map();
|
|
7
|
+
for (const rule of configRules) {
|
|
8
|
+
if ("scope" in rule && typeof rule.scope === "string") {
|
|
9
|
+
if (!rule.scope.startsWith("@")) throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);
|
|
10
|
+
ruleMap.set(rule.scope, "scope");
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if ("package" in rule && !("versions" in rule)) {
|
|
14
|
+
ruleMap.set(rule.package, "package");
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if ("package" in rule && "versions" in rule) {
|
|
18
|
+
const previousConfig = ruleMap.get(rule.package) || { versions: [] };
|
|
19
|
+
if (typeof previousConfig === "string") throw new Error(`Package ${rule.package} is already specified by another strict rule ${previousConfig}`);
|
|
20
|
+
const range = new Range(rule.versions);
|
|
21
|
+
ruleMap.set(rule.package, {
|
|
22
|
+
versions: [...previousConfig.versions, range],
|
|
23
|
+
strategy: rule.strategy ?? "block"
|
|
24
|
+
});
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);
|
|
28
|
+
}
|
|
29
|
+
return ruleMap;
|
|
30
|
+
}
|
|
31
|
+
function parseConfig(config) {
|
|
32
|
+
debug("parsing config: %o", config);
|
|
33
|
+
const blockMap = parseConfigRules(config.block ?? []);
|
|
34
|
+
const allowMap = parseConfigRules(config.allow ?? []);
|
|
35
|
+
debug("parsed %d block rules, %d allow rules", blockMap.size, allowMap.size);
|
|
36
|
+
const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;
|
|
37
|
+
if (dateThreshold && isNaN(dateThreshold.getTime())) throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);
|
|
38
|
+
const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;
|
|
39
|
+
let minAgeMs = null;
|
|
40
|
+
if (minAgeDays !== null) {
|
|
41
|
+
if (isNaN(minAgeDays) || minAgeDays < 0) throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);
|
|
42
|
+
minAgeMs = minAgeDays * 24 * 60 * 60 * 1e3;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
dateThreshold,
|
|
46
|
+
minAgeMs,
|
|
47
|
+
blockRules: blockMap,
|
|
48
|
+
allowRules: allowMap
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { parseConfig };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=parser.mjs.map
|
|
@@ -0,0 +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,yCAAyC;AAElE,SAAS,iBAAiB,aAAoD;CAC5E,MAAM,0BAAU,IAAI,KAAyB;AAC7C,MAAK,MAAM,QAAQ,aAAa;AAC9B,MAAI,WAAW,QAAQ,OAAO,KAAK,UAAU,UAAU;AACrD,OAAI,CAAC,KAAK,MAAM,WAAW,IAAI,CAC7B,OAAM,IAAI,UAAU,yCAAyC,KAAK,QAAQ;AAG5E,WAAQ,IAAI,KAAK,OAAO,QAAQ;AAChC;;AAGF,MAAI,aAAa,QAAQ,EAAE,cAAc,OAAO;AAC9C,WAAQ,IAAI,KAAK,SAAS,UAAU;AACpC;;AAGF,MAAI,aAAa,QAAQ,cAAc,MAAM;GAC3C,MAAM,iBAAiB,QAAQ,IAAI,KAAK,QAAQ,IAAI,EAAE,UAAU,EAAE,EAAE;AAEpE,OAAI,OAAO,mBAAmB,SAC5B,OAAM,IAAI,MACR,WAAW,KAAK,QAAQ,+CAA+C,iBACxE;GAIH,MAAM,QAAQ,IAAI,MAAM,KAAK,SAAS;AACtC,WAAQ,IAAI,KAAK,SAAS;IACxB,UAAU,CAAC,GAAG,eAAe,UAAU,MAAM;IAC7C,UAAU,KAAK,YAAY;IAC5B,CAAC;AAEF;;AAGF,QAAM,IAAI,UAAU,wBAAwB,KAAK,UAAU,MAAM,MAAM,EAAE,GAAG;;AAG9E,QAAO;;AAGT,SAAgB,YAAY,QAAoC;AAC9D,OAAM,sBAAsB,OAAO;CACnC,MAAM,WAAW,iBAAiB,OAAO,SAAS,EAAE,CAAC;CACrD,MAAM,WAAW,iBAAiB,OAAO,SAAS,EAAE,CAAC;AACrD,OAAM,yCAAyC,SAAS,MAAM,SAAS,KAAK;CAC5E,MAAM,gBAAgB,OAAO,gBAAgB,IAAI,KAAK,OAAO,cAAc,GAAG;AAC9E,KAAI,iBAAiB,MAAM,cAAc,SAAS,CAAC,CACjD,OAAM,IAAI,UAAU,gBAAgB,OAAO,cAAc,iCAAiC;CAG5F,MAAM,aAAa,OAAO,aAAa,OAAO,OAAO,WAAW,GAAG;CACnE,IAAI,WAA0B;AAC9B,KAAI,eAAe,MAAM;AACvB,MAAI,MAAM,WAAW,IAAI,aAAa,EACpC,OAAM,IAAI,UAAU,kBAAkB,OAAO,WAAW,8BAA8B;AAGxF,aAAW,aAAa,KAAK,KAAK,KAAK;;AAGzC,QAAO;EACL;EACA;EACA,YAAY;EACZ,YAAY;EACb"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Range } from 'semver';
|
|
2
|
+
export type BlockStrategy = 'block' | 'replace';
|
|
3
|
+
export type ConfigRule = {
|
|
4
|
+
scope: string;
|
|
5
|
+
} | {
|
|
6
|
+
package: string;
|
|
7
|
+
} | {
|
|
8
|
+
package: string;
|
|
9
|
+
versions: string;
|
|
10
|
+
strategy?: BlockStrategy;
|
|
11
|
+
};
|
|
12
|
+
export interface PluginConfig {
|
|
13
|
+
/**
|
|
14
|
+
* An absolute date cutoff (e.g. '2023-01-01'). Versions published after this
|
|
15
|
+
* date will be blocked. When both `dateThreshold` and `minAgeDays` are set,
|
|
16
|
+
* the earlier (more restrictive) date wins.
|
|
17
|
+
*/
|
|
18
|
+
dateThreshold?: string | number;
|
|
19
|
+
/**
|
|
20
|
+
* A relative age cutoff in days. Versions published less than this many days
|
|
21
|
+
* ago will be blocked. When both `minAgeDays` and `dateThreshold` are set,
|
|
22
|
+
* the earlier (more restrictive) date wins.
|
|
23
|
+
*/
|
|
24
|
+
minAgeDays?: number;
|
|
25
|
+
block?: ConfigRule[];
|
|
26
|
+
allow?: ConfigRule[];
|
|
27
|
+
}
|
|
28
|
+
export interface ParsedConfigRule {
|
|
29
|
+
versions: Range[];
|
|
30
|
+
strategy?: BlockStrategy;
|
|
31
|
+
}
|
|
32
|
+
export type PackageScopeLevel = 'scope' | 'package' | undefined;
|
|
33
|
+
export type ParsedRule = ParsedConfigRule | PackageScopeLevel;
|
|
34
|
+
export interface ParsedConfig {
|
|
35
|
+
dateThreshold: Date | null;
|
|
36
|
+
minAgeMs: number | null;
|
|
37
|
+
blockRules: Map<string, ParsedRule>;
|
|
38
|
+
allowRules: Map<string, ParsedRule>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Manifest } from '@verdaccio/types';
|
|
2
|
+
import { ParsedRule } from '../config/types';
|
|
3
|
+
import { MatchResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Try to find a rule that matches the package.
|
|
6
|
+
* If found, returns the rule and the matched package versions from the manifest.
|
|
7
|
+
*/
|
|
8
|
+
export declare function matchRules(manifest: Manifest, rules: Map<string, ParsedRule>): MatchResult | undefined;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.js");
|
|
2
|
+
const require_types = require("./types.js");
|
|
3
|
+
let debug = require("debug");
|
|
4
|
+
debug = require_runtime.__toESM(debug);
|
|
5
|
+
let semver = require("semver");
|
|
6
|
+
//#region src/filtering/matcher.ts
|
|
7
|
+
var debug$1 = (0, debug.default)("verdaccio:plugin:package-filter:filter");
|
|
8
|
+
/**
|
|
9
|
+
* Split a package name into name itself and scope.
|
|
10
|
+
*/
|
|
11
|
+
function splitName(name) {
|
|
12
|
+
if (!name) return { name: "" };
|
|
13
|
+
const parts = name.split("/");
|
|
14
|
+
if (parts.length > 1) return {
|
|
15
|
+
scope: parts[0],
|
|
16
|
+
name: parts[1]
|
|
17
|
+
};
|
|
18
|
+
else return { name: parts[0] };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Try to find a rule that matches the package.
|
|
22
|
+
* If found, returns the rule and the matched package versions from the manifest.
|
|
23
|
+
*/
|
|
24
|
+
function matchRules(manifest, rules) {
|
|
25
|
+
const { scope } = splitName(manifest.name);
|
|
26
|
+
if (scope) {
|
|
27
|
+
const rule = rules.get(scope);
|
|
28
|
+
if (rule === "scope") {
|
|
29
|
+
debug$1("scope match: %s matched rule for %s", manifest.name, scope);
|
|
30
|
+
return {
|
|
31
|
+
type: require_types.MatchType.SCOPE,
|
|
32
|
+
rule,
|
|
33
|
+
scope,
|
|
34
|
+
versions: Object.keys(manifest.versions)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const rule = rules.get(manifest.name);
|
|
39
|
+
if (!rule) return;
|
|
40
|
+
if (rule === "package") {
|
|
41
|
+
debug$1("package match: %s", manifest.name);
|
|
42
|
+
return {
|
|
43
|
+
type: require_types.MatchType.PACKAGE,
|
|
44
|
+
rule,
|
|
45
|
+
package: manifest.name,
|
|
46
|
+
versions: Object.keys(manifest.versions)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (rule === "scope") throw new Error("Unexpected case - rule for package should never be \"scope\"");
|
|
50
|
+
const versionRanges = rule.versions;
|
|
51
|
+
if (versionRanges.length === 0) return;
|
|
52
|
+
const matchedVersions = [];
|
|
53
|
+
Object.keys(manifest.versions).forEach((version) => {
|
|
54
|
+
versionRanges.forEach((versionRange) => {
|
|
55
|
+
if ((0, semver.satisfies)(version, versionRange, {
|
|
56
|
+
includePrerelease: true,
|
|
57
|
+
loose: true
|
|
58
|
+
})) matchedVersions.push(version);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
if (matchedVersions.length > 0) debug$1("version match: %s matched %d versions: %o", manifest.name, matchedVersions.length, matchedVersions);
|
|
62
|
+
return {
|
|
63
|
+
type: require_types.MatchType.VERSIONS,
|
|
64
|
+
rule,
|
|
65
|
+
versions: matchedVersions
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
exports.matchRules = matchRules;
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=matcher.js.map
|
|
@@ -0,0 +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,yCAAyC;;;;AAKlE,SAAS,UAAU,MAAgD;AACjE,KAAI,CAAC,KACH,QAAO,EAAE,MAAM,IAAI;CAGrB,MAAM,QAAQ,KAAK,MAAM,IAAI;AAE7B,KAAI,MAAM,SAAS,EACjB,QAAO;EACL,OAAO,MAAM;EACb,MAAM,MAAM;EACb;KAED,QAAO,EACL,MAAM,MAAM,IACb;;;;;;AAQL,SAAgB,WACd,UACA,OACyB;CACzB,MAAM,EAAE,UAAU,UAAU,SAAS,KAAK;AAC1C,KAAI,OAAO;EACT,MAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,MAAI,SAAS,SAAS;AACpB,WAAM,uCAAuC,SAAS,MAAM,MAAM;AAClE,UAAO;IACL,MAAM,cAAA,UAAU;IAChB;IACA;IACA,UAAU,OAAO,KAAK,SAAS,SAAS;IACzC;;;CAIL,MAAM,OAAO,MAAM,IAAI,SAAS,KAAK;AACrC,KAAI,CAAC,KAEH;AAGF,KAAI,SAAS,WAAW;AACtB,UAAM,qBAAqB,SAAS,KAAK;AACzC,SAAO;GACL,MAAM,cAAA,UAAU;GAChB;GACA,SAAS,SAAS;GAClB,UAAU,OAAO,KAAK,SAAS,SAAS;GACzC;;AAGH,KAAI,SAAS,QACX,OAAM,IAAI,MAAM,+DAA6D;CAG/E,MAAM,gBAAgB,KAAK;AAC3B,KAAI,cAAc,WAAW,EAE3B;CAGF,MAAM,kBAA4B,EAAE;AACpC,QAAO,KAAK,SAAS,SAAS,CAAC,SAAS,YAAY;AAClD,gBAAc,SAAS,iBAAiB;AACtC,QAAA,GAAA,OAAA,WACY,SAAS,cAAc;IAC/B,mBAAmB;IACnB,OAAO;IACR,CAAC,CAEF,iBAAgB,KAAK,QAAQ;IAE/B;GACF;AAEF,KAAI,gBAAgB,SAAS,EAC3B,SACE,6CACA,SAAS,MACT,gBAAgB,QAChB,gBACD;AAGH,QAAO;EACL,MAAM,cAAA,UAAU;EAChB;EACA,UAAU;EACX"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { MatchType } from "./types.mjs";
|
|
2
|
+
import buildDebug from "debug";
|
|
3
|
+
import { satisfies } from "semver";
|
|
4
|
+
//#region src/filtering/matcher.ts
|
|
5
|
+
var debug = buildDebug("verdaccio:plugin:package-filter:filter");
|
|
6
|
+
/**
|
|
7
|
+
* Split a package name into name itself and scope.
|
|
8
|
+
*/
|
|
9
|
+
function splitName(name) {
|
|
10
|
+
if (!name) return { name: "" };
|
|
11
|
+
const parts = name.split("/");
|
|
12
|
+
if (parts.length > 1) return {
|
|
13
|
+
scope: parts[0],
|
|
14
|
+
name: parts[1]
|
|
15
|
+
};
|
|
16
|
+
else return { name: parts[0] };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Try to find a rule that matches the package.
|
|
20
|
+
* If found, returns the rule and the matched package versions from the manifest.
|
|
21
|
+
*/
|
|
22
|
+
function matchRules(manifest, rules) {
|
|
23
|
+
const { scope } = splitName(manifest.name);
|
|
24
|
+
if (scope) {
|
|
25
|
+
const rule = rules.get(scope);
|
|
26
|
+
if (rule === "scope") {
|
|
27
|
+
debug("scope match: %s matched rule for %s", manifest.name, scope);
|
|
28
|
+
return {
|
|
29
|
+
type: MatchType.SCOPE,
|
|
30
|
+
rule,
|
|
31
|
+
scope,
|
|
32
|
+
versions: Object.keys(manifest.versions)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const rule = rules.get(manifest.name);
|
|
37
|
+
if (!rule) return;
|
|
38
|
+
if (rule === "package") {
|
|
39
|
+
debug("package match: %s", manifest.name);
|
|
40
|
+
return {
|
|
41
|
+
type: MatchType.PACKAGE,
|
|
42
|
+
rule,
|
|
43
|
+
package: manifest.name,
|
|
44
|
+
versions: Object.keys(manifest.versions)
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (rule === "scope") throw new Error("Unexpected case - rule for package should never be \"scope\"");
|
|
48
|
+
const versionRanges = rule.versions;
|
|
49
|
+
if (versionRanges.length === 0) return;
|
|
50
|
+
const matchedVersions = [];
|
|
51
|
+
Object.keys(manifest.versions).forEach((version) => {
|
|
52
|
+
versionRanges.forEach((versionRange) => {
|
|
53
|
+
if (satisfies(version, versionRange, {
|
|
54
|
+
includePrerelease: true,
|
|
55
|
+
loose: true
|
|
56
|
+
})) matchedVersions.push(version);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
if (matchedVersions.length > 0) debug("version match: %s matched %d versions: %o", manifest.name, matchedVersions.length, matchedVersions);
|
|
60
|
+
return {
|
|
61
|
+
type: MatchType.VERSIONS,
|
|
62
|
+
rule,
|
|
63
|
+
versions: matchedVersions
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { matchRules };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=matcher.mjs.map
|