@verdaccio/package-filter 13.0.0 → 13.0.1
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/build/index.js +450 -495
- package/build/index.js.map +1 -1
- package/package.json +6 -6
package/build/index.js
CHANGED
|
@@ -1,524 +1,479 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
Object.defineProperties(exports, {
|
|
2
|
+
__esModule: { value: true },
|
|
3
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
+
});
|
|
5
|
+
//#region \0rolldown/runtime.js
|
|
6
|
+
var __create = Object.create;
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
14
|
+
key = keys[i];
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
16
|
+
get: ((k) => from[k]).bind(null, key),
|
|
17
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
//#endregion
|
|
27
|
+
let debug = require("debug");
|
|
28
|
+
debug = __toESM(debug);
|
|
29
|
+
let _verdaccio_core = require("@verdaccio/core");
|
|
30
|
+
let semver = require("semver");
|
|
31
|
+
semver = __toESM(semver);
|
|
32
|
+
//#region src/config/parser.ts
|
|
33
|
+
var debug$6 = (0, debug.default)("verdaccio:plugin:package-filter:config");
|
|
7
34
|
function parseConfigRules(configRules) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
});
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);
|
|
36
|
-
}
|
|
37
|
-
return ruleMap;
|
|
35
|
+
const ruleMap = /* @__PURE__ */ new Map();
|
|
36
|
+
for (const rule of configRules) {
|
|
37
|
+
if ("scope" in rule && typeof rule.scope === "string") {
|
|
38
|
+
if (!rule.scope.startsWith("@")) throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);
|
|
39
|
+
ruleMap.set(rule.scope, "scope");
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if ("package" in rule && !("versions" in rule)) {
|
|
43
|
+
ruleMap.set(rule.package, "package");
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if ("package" in rule && "versions" in rule) {
|
|
47
|
+
const previousConfig = ruleMap.get(rule.package) || { versions: [] };
|
|
48
|
+
if (typeof previousConfig === "string") throw new Error(`Package ${rule.package} is already specified by another strict rule ${previousConfig}`);
|
|
49
|
+
const range = new semver.Range(rule.versions);
|
|
50
|
+
ruleMap.set(rule.package, {
|
|
51
|
+
versions: [...previousConfig.versions, range],
|
|
52
|
+
strategy: rule.strategy ?? "block"
|
|
53
|
+
});
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);
|
|
57
|
+
}
|
|
58
|
+
return ruleMap;
|
|
38
59
|
}
|
|
39
60
|
function parseConfig(config) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
minAgeMs,
|
|
59
|
-
blockRules: blockMap,
|
|
60
|
-
allowRules: allowMap
|
|
61
|
-
};
|
|
61
|
+
debug$6("parsing config: %o", config);
|
|
62
|
+
const blockMap = parseConfigRules(config.block ?? []);
|
|
63
|
+
const allowMap = parseConfigRules(config.allow ?? []);
|
|
64
|
+
debug$6("parsed %d block rules, %d allow rules", blockMap.size, allowMap.size);
|
|
65
|
+
const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;
|
|
66
|
+
if (dateThreshold && isNaN(dateThreshold.getTime())) throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);
|
|
67
|
+
const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;
|
|
68
|
+
let minAgeMs = null;
|
|
69
|
+
if (minAgeDays !== null) {
|
|
70
|
+
if (isNaN(minAgeDays) || minAgeDays < 0) throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);
|
|
71
|
+
minAgeMs = minAgeDays * 24 * 60 * 60 * 1e3;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
dateThreshold,
|
|
75
|
+
minAgeMs,
|
|
76
|
+
blockRules: blockMap,
|
|
77
|
+
allowRules: allowMap
|
|
78
|
+
};
|
|
62
79
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/filtering/types.ts
|
|
82
|
+
var MatchType = /* @__PURE__ */ function(MatchType) {
|
|
83
|
+
MatchType["SCOPE"] = "scope";
|
|
84
|
+
MatchType["PACKAGE"] = "package";
|
|
85
|
+
MatchType["VERSIONS"] = "versions";
|
|
86
|
+
return MatchType;
|
|
87
|
+
}({});
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/filtering/matcher.ts
|
|
90
|
+
var debug$5 = (0, debug.default)("verdaccio:plugin:package-filter:filter");
|
|
91
|
+
/**
|
|
92
|
+
* Split a package name into name itself and scope.
|
|
93
|
+
*/
|
|
70
94
|
function splitName(name) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
name: parts[1]
|
|
79
|
-
};
|
|
80
|
-
} else {
|
|
81
|
-
return {
|
|
82
|
-
name: parts[0]
|
|
83
|
-
};
|
|
84
|
-
}
|
|
95
|
+
if (!name) return { name: "" };
|
|
96
|
+
const parts = name.split("/");
|
|
97
|
+
if (parts.length > 1) return {
|
|
98
|
+
scope: parts[0],
|
|
99
|
+
name: parts[1]
|
|
100
|
+
};
|
|
101
|
+
else return { name: parts[0] };
|
|
85
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Try to find a rule that matches the package.
|
|
105
|
+
* If found, returns the rule and the matched package versions from the manifest.
|
|
106
|
+
*/
|
|
86
107
|
function matchRules(manifest, rules) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
if (matchedVersions.length > 0) {
|
|
132
|
-
debug$4(
|
|
133
|
-
"version match: %s matched %d versions: %o",
|
|
134
|
-
manifest.name,
|
|
135
|
-
matchedVersions.length,
|
|
136
|
-
matchedVersions
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
type: MatchType.VERSIONS,
|
|
141
|
-
rule,
|
|
142
|
-
versions: matchedVersions
|
|
143
|
-
};
|
|
108
|
+
const { scope } = splitName(manifest.name);
|
|
109
|
+
if (scope) {
|
|
110
|
+
const rule = rules.get(scope);
|
|
111
|
+
if (rule === "scope") {
|
|
112
|
+
debug$5("scope match: %s matched rule for %s", manifest.name, scope);
|
|
113
|
+
return {
|
|
114
|
+
type: MatchType.SCOPE,
|
|
115
|
+
rule,
|
|
116
|
+
scope,
|
|
117
|
+
versions: Object.keys(manifest.versions)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const rule = rules.get(manifest.name);
|
|
122
|
+
if (!rule) return;
|
|
123
|
+
if (rule === "package") {
|
|
124
|
+
debug$5("package match: %s", manifest.name);
|
|
125
|
+
return {
|
|
126
|
+
type: MatchType.PACKAGE,
|
|
127
|
+
rule,
|
|
128
|
+
package: manifest.name,
|
|
129
|
+
versions: Object.keys(manifest.versions)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (rule === "scope") throw new Error("Unexpected case - rule for package should never be \"scope\"");
|
|
133
|
+
const versionRanges = rule.versions;
|
|
134
|
+
if (versionRanges.length === 0) return;
|
|
135
|
+
const matchedVersions = [];
|
|
136
|
+
Object.keys(manifest.versions).forEach((version) => {
|
|
137
|
+
versionRanges.forEach((versionRange) => {
|
|
138
|
+
if ((0, semver.satisfies)(version, versionRange, {
|
|
139
|
+
includePrerelease: true,
|
|
140
|
+
loose: true
|
|
141
|
+
})) matchedVersions.push(version);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
if (matchedVersions.length > 0) debug$5("version match: %s matched %d versions: %o", manifest.name, matchedVersions.length, matchedVersions);
|
|
145
|
+
return {
|
|
146
|
+
type: MatchType.VERSIONS,
|
|
147
|
+
rule,
|
|
148
|
+
versions: matchedVersions
|
|
149
|
+
};
|
|
144
150
|
}
|
|
145
|
-
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/filtering/packageVersion.ts
|
|
153
|
+
var debug$4 = (0, debug.default)("verdaccio:plugin:package-filter:filter");
|
|
154
|
+
/**
|
|
155
|
+
* Filter out all blocked package versions.
|
|
156
|
+
* If package or scope is blocked, then block all versions.
|
|
157
|
+
*
|
|
158
|
+
* TODO: consider adding a `prerelease` filter option to block/allow
|
|
159
|
+
* prerelease versions independently. Currently prereleases are matched by
|
|
160
|
+
* semver ranges with `includePrerelease: true`, but there's no dedicated toggle.
|
|
161
|
+
*
|
|
162
|
+
* Example config (not yet implemented):
|
|
163
|
+
* block:
|
|
164
|
+
* - package: 'foo'
|
|
165
|
+
* prerelease: true # block 1.0.0-beta.1, 2.0.0-rc.1, keep 1.0.0, 2.0.0
|
|
166
|
+
* - package: 'bar'
|
|
167
|
+
* prerelease: false # block 1.0.0, 2.0.0, keep 1.0.0-beta.1
|
|
168
|
+
*
|
|
169
|
+
* Today the only workaround is using awkward ranges like ">=1.0.0-0 <1.0.0".
|
|
170
|
+
*/
|
|
146
171
|
function filterBlockedVersions(manifest, blockRules, allowRules, logger) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
logger.trace(
|
|
246
|
-
{ name: manifest.name, version },
|
|
247
|
-
"version @{version} of @{name} removed (no replacement available)"
|
|
248
|
-
);
|
|
249
|
-
delete manifest.versions[version];
|
|
250
|
-
});
|
|
251
|
-
replacedVersions.forEach(([version, replaceVersion]) => {
|
|
252
|
-
logger.trace(
|
|
253
|
-
{ name: manifest.name, version, replaceVersion },
|
|
254
|
-
"version @{version} of @{name} replaced with @{replaceVersion}"
|
|
255
|
-
);
|
|
256
|
-
manifest.versions[version] = {
|
|
257
|
-
...manifest.versions[replaceVersion],
|
|
258
|
-
version
|
|
259
|
-
};
|
|
260
|
-
});
|
|
261
|
-
if (removedVersions.length > 0) {
|
|
262
|
-
manifest.readme += `
|
|
263
|
-
Some versions of package could not be replaced and thus are fully blocked (${removedVersions.length}): ${removedVersions.map((a) => a[0])}`;
|
|
264
|
-
}
|
|
265
|
-
if (replacedVersions.length > 0) {
|
|
266
|
-
manifest.readme += `
|
|
267
|
-
Some versions of package are replaced by other(${replacedVersions.length}): ${replacedVersions.map((a) => `${a[0]} => ${a[1]}`)}`;
|
|
268
|
-
}
|
|
269
|
-
return manifest;
|
|
172
|
+
const allowMatch = matchRules(manifest, allowRules);
|
|
173
|
+
if (allowMatch && (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE)) {
|
|
174
|
+
logger.trace({ name: manifest.name }, "package @{name} is allow-listed, skipping block rules");
|
|
175
|
+
return manifest;
|
|
176
|
+
}
|
|
177
|
+
const blockMatch = matchRules(manifest, blockRules);
|
|
178
|
+
if (!blockMatch) return manifest;
|
|
179
|
+
logger.trace({
|
|
180
|
+
name: manifest.name,
|
|
181
|
+
type: blockMatch.type
|
|
182
|
+
}, "block rule matched for @{name} (type: @{type})");
|
|
183
|
+
const whitelistedVersions = allowMatch ? allowMatch.versions : [];
|
|
184
|
+
let blockRule = {
|
|
185
|
+
versions: [new semver.Range("*")],
|
|
186
|
+
strategy: "block"
|
|
187
|
+
};
|
|
188
|
+
if (blockMatch.type === MatchType.SCOPE) {
|
|
189
|
+
if (whitelistedVersions.length === 0) {
|
|
190
|
+
debug$4("blocking all versions of %s (scope %s blocked)", manifest.name, blockMatch.scope);
|
|
191
|
+
logger.trace({
|
|
192
|
+
name: manifest.name,
|
|
193
|
+
scope: blockMatch.scope
|
|
194
|
+
}, "all versions of @{name} blocked (scope @{scope})");
|
|
195
|
+
return {
|
|
196
|
+
...manifest,
|
|
197
|
+
versions: {},
|
|
198
|
+
readme: `All packages in scope ${blockMatch.scope} are blocked by rule`
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
} else if (blockMatch.type === MatchType.PACKAGE) {
|
|
202
|
+
if (whitelistedVersions.length === 0) {
|
|
203
|
+
debug$4("blocking all versions of %s (package blocked)", manifest.name);
|
|
204
|
+
logger.trace({ name: manifest.name }, "all versions of @{name} blocked (package rule)");
|
|
205
|
+
return {
|
|
206
|
+
...manifest,
|
|
207
|
+
versions: {},
|
|
208
|
+
readme: `All package versions are blocked by rule`
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
} else blockRule = {
|
|
212
|
+
...blockRule,
|
|
213
|
+
...blockMatch.rule
|
|
214
|
+
};
|
|
215
|
+
const versionRanges = blockRule.versions;
|
|
216
|
+
if (blockRule.strategy === "block") {
|
|
217
|
+
const blockedVersions = blockMatch.versions.filter((v) => !whitelistedVersions.includes(v));
|
|
218
|
+
for (const version of blockedVersions) delete manifest.versions[version];
|
|
219
|
+
if (blockedVersions.length > 0) {
|
|
220
|
+
debug$4("blocked %d versions of %s: %o", blockedVersions.length, manifest.name, blockedVersions);
|
|
221
|
+
logger.trace({
|
|
222
|
+
name: manifest.name,
|
|
223
|
+
count: blockedVersions.length,
|
|
224
|
+
versions: blockedVersions.join(", ")
|
|
225
|
+
}, "@{count} versions of @{name} blocked: @{versions}");
|
|
226
|
+
manifest.readme = (manifest.readme || "") + `\nSome versions(${blockedVersions.length}) of package are blocked by rules: ${versionRanges.map((range) => range.raw)}`;
|
|
227
|
+
}
|
|
228
|
+
return manifest;
|
|
229
|
+
}
|
|
230
|
+
const nonBlockedVersions = { ...manifest.versions };
|
|
231
|
+
const newVersionsMapping = {};
|
|
232
|
+
versionRanges.forEach((versionRange) => {
|
|
233
|
+
const allVersions = Object.keys(nonBlockedVersions);
|
|
234
|
+
let lastNonBlockedVersion = null;
|
|
235
|
+
allVersions.forEach((version) => {
|
|
236
|
+
if (!whitelistedVersions.includes(version) && (0, semver.satisfies)(version, versionRange, {
|
|
237
|
+
includePrerelease: true,
|
|
238
|
+
loose: true
|
|
239
|
+
})) {
|
|
240
|
+
delete nonBlockedVersions[version];
|
|
241
|
+
newVersionsMapping[version] = lastNonBlockedVersion;
|
|
242
|
+
} else lastNonBlockedVersion = version;
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
debug$4("replacing versions for %s: %o", manifest.name, newVersionsMapping);
|
|
246
|
+
const removedVersions = Object.entries(newVersionsMapping).filter(([_, replace]) => replace === null);
|
|
247
|
+
const replacedVersions = Object.entries(newVersionsMapping).filter(([_, replace]) => replace !== null);
|
|
248
|
+
removedVersions.forEach(([version]) => {
|
|
249
|
+
debug$4("no version to replace %s in %s", version, manifest.name);
|
|
250
|
+
logger.trace({
|
|
251
|
+
name: manifest.name,
|
|
252
|
+
version
|
|
253
|
+
}, "version @{version} of @{name} removed (no replacement available)");
|
|
254
|
+
delete manifest.versions[version];
|
|
255
|
+
});
|
|
256
|
+
replacedVersions.forEach(([version, replaceVersion]) => {
|
|
257
|
+
logger.trace({
|
|
258
|
+
name: manifest.name,
|
|
259
|
+
version,
|
|
260
|
+
replaceVersion
|
|
261
|
+
}, "version @{version} of @{name} replaced with @{replaceVersion}");
|
|
262
|
+
manifest.versions[version] = {
|
|
263
|
+
...manifest.versions[replaceVersion],
|
|
264
|
+
version
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
if (removedVersions.length > 0) manifest.readme += `\nSome versions of package could not be replaced and thus are fully blocked (${removedVersions.length}): ${removedVersions.map((a) => a[0])}`;
|
|
268
|
+
if (replacedVersions.length > 0) manifest.readme += `\nSome versions of package are replaced by other(${replacedVersions.length}): ${replacedVersions.map((a) => `${a[0]} => ${a[1]}`)}`;
|
|
269
|
+
return manifest;
|
|
270
270
|
}
|
|
271
|
-
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region src/filtering/publishDate.ts
|
|
273
|
+
var debug$3 = (0, debug.default)("verdaccio:plugin:package-filter:filter");
|
|
274
|
+
/**
|
|
275
|
+
* Filter out all package versions that were published after dateThreshold.
|
|
276
|
+
*/
|
|
272
277
|
function filterVersionsByPublishDate(manifest, dateThreshold, allowRules) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
`Time of publication was not provided for package ${name}, version ${version}`
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
if (new Date(publishTime) > dateThreshold) {
|
|
294
|
-
clearVersions.push(version);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
clearVersions.forEach((version) => {
|
|
298
|
-
delete manifest.versions[version];
|
|
299
|
-
});
|
|
300
|
-
if (clearVersions.length > 0) {
|
|
301
|
-
debug$2(
|
|
302
|
-
"date filter removed %d versions from %s: %o",
|
|
303
|
-
clearVersions.length,
|
|
304
|
-
manifest.name,
|
|
305
|
-
clearVersions
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
return manifest;
|
|
278
|
+
const allowMatch = matchRules(manifest, allowRules);
|
|
279
|
+
if (allowMatch && (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE)) return manifest;
|
|
280
|
+
const { versions, time, name } = manifest;
|
|
281
|
+
if (!time) throw new TypeError(`Time of publication was not provided for package ${name}`);
|
|
282
|
+
const whitelistedVersions = allowMatch ? allowMatch.versions : [];
|
|
283
|
+
const clearVersions = [];
|
|
284
|
+
Object.keys(versions).forEach((version) => {
|
|
285
|
+
if (whitelistedVersions.includes(version)) return;
|
|
286
|
+
const publishTime = time[version];
|
|
287
|
+
if (!publishTime) throw new TypeError(`Time of publication was not provided for package ${name}, version ${version}`);
|
|
288
|
+
if (new Date(publishTime) > dateThreshold) clearVersions.push(version);
|
|
289
|
+
});
|
|
290
|
+
clearVersions.forEach((version) => {
|
|
291
|
+
delete manifest.versions[version];
|
|
292
|
+
});
|
|
293
|
+
if (clearVersions.length > 0) debug$3("date filter removed %d versions from %s: %o", clearVersions.length, manifest.name, clearVersions);
|
|
294
|
+
return manifest;
|
|
309
295
|
}
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/utils/jsonUtils.ts
|
|
310
298
|
function jsonLogReplacer(_key, value) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (value instanceof semver.Range) {
|
|
315
|
-
return value.range;
|
|
316
|
-
}
|
|
317
|
-
return value;
|
|
299
|
+
if (value instanceof Map) return Object.fromEntries(value);
|
|
300
|
+
if (value instanceof semver.Range) return value.range;
|
|
301
|
+
return value;
|
|
318
302
|
}
|
|
319
|
-
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/utils/manifestUtils.ts
|
|
305
|
+
var debug$2 = (0, debug.default)("verdaccio:plugin:package-filter:manifest");
|
|
306
|
+
/**
|
|
307
|
+
* Delete `dist-tags` entries corresponding to missing versions.
|
|
308
|
+
*/
|
|
320
309
|
function cleanupTags(manifest) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
310
|
+
const distTags = manifest[_verdaccio_core.DIST_TAGS];
|
|
311
|
+
Object.entries(distTags).forEach(([tag, tagVersion]) => {
|
|
312
|
+
if (!manifest.versions[tagVersion]) {
|
|
313
|
+
debug$2("removing orphaned dist-tag %s -> %s from %s", tag, tagVersion, manifest.name);
|
|
314
|
+
delete distTags[tag];
|
|
315
|
+
}
|
|
316
|
+
});
|
|
328
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Delete `time` entries corresponding to missing versions.
|
|
320
|
+
*/
|
|
329
321
|
function cleanupTime(manifest) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
if (!manifest.versions[version]) {
|
|
336
|
-
delete time[version];
|
|
337
|
-
}
|
|
338
|
-
});
|
|
322
|
+
const time = manifest.time;
|
|
323
|
+
if (!time) return;
|
|
324
|
+
Object.keys(time).forEach((version) => {
|
|
325
|
+
if (!manifest.versions[version]) delete time[version];
|
|
326
|
+
});
|
|
339
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* Get the latest version from a list of versions,
|
|
330
|
+
* ordered by time of their publication stored in the manifest.
|
|
331
|
+
*/
|
|
340
332
|
function getLatestVersion(manifest, versions) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
})).filter((v) => v.time);
|
|
350
|
-
if (timedVersions.length === 0) {
|
|
351
|
-
return void 0;
|
|
352
|
-
}
|
|
353
|
-
const timeOrderedVersions = timedVersions.sort(
|
|
354
|
-
(a, b) => new Date(b.time).getTime() - new Date(a.time).getTime()
|
|
355
|
-
);
|
|
356
|
-
return timeOrderedVersions[0].version;
|
|
333
|
+
const time = manifest.time;
|
|
334
|
+
if (!time) return versions.sort(semver.default.rcompare)[0];
|
|
335
|
+
const timedVersions = versions.map((v) => ({
|
|
336
|
+
version: v,
|
|
337
|
+
time: time[v]
|
|
338
|
+
})).filter((v) => v.time);
|
|
339
|
+
if (timedVersions.length === 0) return;
|
|
340
|
+
return timedVersions.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime())[0].version;
|
|
357
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* Set the latest tag if dist-tags/latest is missing.
|
|
344
|
+
* The last stable version available is used when possible.
|
|
345
|
+
* Otherwise, it uses the latest version not found in dist-tags.
|
|
346
|
+
*/
|
|
358
347
|
function setupLatestTag(manifest) {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
distTags.latest = latestStableVersion;
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
const latestVersion = getLatestVersion(manifest, untaggedVersions);
|
|
380
|
-
if (!latestVersion) {
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
debug$1("reassigned latest tag to pre-release version %s for %s", latestVersion, manifest.name);
|
|
384
|
-
distTags.latest = latestVersion;
|
|
348
|
+
const distTags = manifest[_verdaccio_core.DIST_TAGS];
|
|
349
|
+
if (distTags.latest) return;
|
|
350
|
+
const versions = Object.keys(manifest.versions);
|
|
351
|
+
if (versions.length === 0) return;
|
|
352
|
+
const distTagsVersions = Object.values(distTags);
|
|
353
|
+
const untaggedVersions = versions.filter((v) => semver.default.valid(v) && !distTagsVersions.includes(v));
|
|
354
|
+
if (untaggedVersions.length === 0) return;
|
|
355
|
+
const latestStableVersion = getLatestVersion(manifest, untaggedVersions.filter((v) => !semver.default.prerelease(v)));
|
|
356
|
+
if (latestStableVersion) {
|
|
357
|
+
debug$2("reassigned latest tag to stable version %s for %s", latestStableVersion, manifest.name);
|
|
358
|
+
distTags.latest = latestStableVersion;
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const latestVersion = getLatestVersion(manifest, untaggedVersions);
|
|
362
|
+
if (!latestVersion) return;
|
|
363
|
+
debug$2("reassigned latest tag to pre-release version %s for %s", latestVersion, manifest.name);
|
|
364
|
+
distTags.latest = latestVersion;
|
|
385
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* Set the created and modified times.
|
|
368
|
+
*/
|
|
386
369
|
function setupCreatedAndModified(manifest) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
const sortedTimes = times.sort((a, b) => new Date(a).getTime() - new Date(b).getTime());
|
|
396
|
-
time.created = sortedTimes[0];
|
|
397
|
-
time.modified = sortedTimes[sortedTimes.length - 1];
|
|
370
|
+
const time = manifest.time;
|
|
371
|
+
if (!time) return;
|
|
372
|
+
const times = Object.values(time);
|
|
373
|
+
if (times.length === 0) return;
|
|
374
|
+
const sortedTimes = times.sort((a, b) => new Date(a).getTime() - new Date(b).getTime());
|
|
375
|
+
time.created = sortedTimes[0];
|
|
376
|
+
time.modified = sortedTimes[sortedTimes.length - 1];
|
|
398
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Remove `_distfiles` entries which are not used by any version.
|
|
380
|
+
*/
|
|
399
381
|
function cleanupDistFiles(manifest) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
if (!activeTarballs.has(distFiles[key].url)) {
|
|
406
|
-
delete distFiles[key];
|
|
407
|
-
}
|
|
408
|
-
});
|
|
382
|
+
const distFiles = manifest._distfiles;
|
|
383
|
+
const activeTarballs = new Set(Object.values(manifest.versions).map((v) => v.dist?.tarball).filter((tarball) => typeof tarball === "string"));
|
|
384
|
+
Object.keys(distFiles).forEach((key) => {
|
|
385
|
+
if (!activeTarballs.has(distFiles[key].url)) delete distFiles[key];
|
|
386
|
+
});
|
|
409
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Creates a copy of a manifest suitable for safe, localized mutation.
|
|
390
|
+
*
|
|
391
|
+
* The returned object is shallow-cloned, except for `versions`, `dist-tags`,
|
|
392
|
+
* `time`, and `_distfiles`, which are cloned as independent maps so they can be
|
|
393
|
+
* filtered or modified without affecting the original manifest.
|
|
394
|
+
*/
|
|
410
395
|
function getManifestClone(manifest) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
},
|
|
419
|
-
time: {
|
|
420
|
-
...manifest.time
|
|
421
|
-
},
|
|
422
|
-
_distfiles: {
|
|
423
|
-
...manifest._distfiles
|
|
424
|
-
}
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
const debug = buildDebug("verdaccio:plugin:package-filter");
|
|
428
|
-
class PackageFilterPlugin extends core.pluginUtils.Plugin {
|
|
429
|
-
config;
|
|
430
|
-
parsedConfig;
|
|
431
|
-
logger;
|
|
432
|
-
constructor(config, options) {
|
|
433
|
-
super(config, options);
|
|
434
|
-
this.config = config ?? {};
|
|
435
|
-
this.logger = options.logger;
|
|
436
|
-
this.parsedConfig = parseConfig(this.config);
|
|
437
|
-
debug(
|
|
438
|
-
"plugin loaded: block rules: %d, allow rules: %d",
|
|
439
|
-
this.parsedConfig.blockRules.size,
|
|
440
|
-
this.parsedConfig.allowRules.size
|
|
441
|
-
);
|
|
442
|
-
this.logger.debug(
|
|
443
|
-
{ config: JSON.stringify(this.parsedConfig, jsonLogReplacer) },
|
|
444
|
-
"package-filter loaded with config: @{config}"
|
|
445
|
-
);
|
|
446
|
-
this.logger.trace(
|
|
447
|
-
{
|
|
448
|
-
blockRules: this.parsedConfig.blockRules.size,
|
|
449
|
-
allowRules: this.parsedConfig.allowRules.size
|
|
450
|
-
},
|
|
451
|
-
"package-filter plugin initialized: @{blockRules} block rules, @{allowRules} allow rules"
|
|
452
|
-
);
|
|
453
|
-
if (this.parsedConfig.dateThreshold) {
|
|
454
|
-
debug("date threshold: %s", this.parsedConfig.dateThreshold.toISOString());
|
|
455
|
-
this.logger.trace(
|
|
456
|
-
{ dateThreshold: this.parsedConfig.dateThreshold.toISOString() },
|
|
457
|
-
"package-filter date threshold: @{dateThreshold}"
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
if (this.parsedConfig.minAgeMs) {
|
|
461
|
-
const minAgeDays = this.parsedConfig.minAgeMs / (24 * 60 * 60 * 1e3);
|
|
462
|
-
debug("min age: %d days", minAgeDays);
|
|
463
|
-
this.logger.trace({ minAgeDays }, "package-filter min age: @{minAgeDays} days");
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
async filter_metadata(manifest) {
|
|
467
|
-
const { dateThreshold, minAgeMs, blockRules, allowRules } = this.parsedConfig;
|
|
468
|
-
const versionCount = Object.keys(manifest.versions ?? {}).length;
|
|
469
|
-
debug("filtering manifest for %s (%d versions)", manifest.name, versionCount);
|
|
470
|
-
this.logger.trace(
|
|
471
|
-
{ name: manifest.name, versionCount },
|
|
472
|
-
"package-filter processing @{name} (@{versionCount} versions)"
|
|
473
|
-
);
|
|
474
|
-
let newManifest = getManifestClone(manifest);
|
|
475
|
-
if (blockRules.size > 0) {
|
|
476
|
-
newManifest = filterBlockedVersions(newManifest, blockRules, allowRules, this.logger);
|
|
477
|
-
}
|
|
478
|
-
let earliestDateThreshold = null;
|
|
479
|
-
if (minAgeMs) {
|
|
480
|
-
earliestDateThreshold = new Date(Date.now() - minAgeMs);
|
|
481
|
-
}
|
|
482
|
-
if (dateThreshold && (!earliestDateThreshold || dateThreshold < earliestDateThreshold)) {
|
|
483
|
-
earliestDateThreshold = dateThreshold;
|
|
484
|
-
}
|
|
485
|
-
if (earliestDateThreshold) {
|
|
486
|
-
debug(
|
|
487
|
-
"applying date filter for %s, threshold: %s",
|
|
488
|
-
manifest.name,
|
|
489
|
-
earliestDateThreshold.toISOString()
|
|
490
|
-
);
|
|
491
|
-
this.logger.trace(
|
|
492
|
-
{ name: manifest.name, threshold: earliestDateThreshold.toISOString() },
|
|
493
|
-
"applying date filter for @{name}, cutoff: @{threshold}"
|
|
494
|
-
);
|
|
495
|
-
newManifest = filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowRules);
|
|
496
|
-
}
|
|
497
|
-
cleanupTags(newManifest);
|
|
498
|
-
setupLatestTag(newManifest);
|
|
499
|
-
cleanupTime(newManifest);
|
|
500
|
-
setupCreatedAndModified(newManifest);
|
|
501
|
-
cleanupDistFiles(newManifest);
|
|
502
|
-
const filteredCount = Object.keys(newManifest.versions).length;
|
|
503
|
-
const removedCount = versionCount - filteredCount;
|
|
504
|
-
if (filteredCount !== versionCount) {
|
|
505
|
-
debug(
|
|
506
|
-
"filtered %s: %d -> %d versions (%d removed)",
|
|
507
|
-
manifest.name,
|
|
508
|
-
versionCount,
|
|
509
|
-
filteredCount,
|
|
510
|
-
removedCount
|
|
511
|
-
);
|
|
512
|
-
this.logger.trace(
|
|
513
|
-
{ name: manifest.name, before: versionCount, after: filteredCount, removed: removedCount },
|
|
514
|
-
"package-filter @{name}: @{before} -> @{after} versions (@{removed} removed)"
|
|
515
|
-
);
|
|
516
|
-
} else {
|
|
517
|
-
debug("no versions filtered for %s", manifest.name);
|
|
518
|
-
}
|
|
519
|
-
return newManifest;
|
|
520
|
-
}
|
|
396
|
+
return {
|
|
397
|
+
...manifest,
|
|
398
|
+
versions: { ...manifest.versions },
|
|
399
|
+
[_verdaccio_core.DIST_TAGS]: { ...manifest[_verdaccio_core.DIST_TAGS] },
|
|
400
|
+
time: { ...manifest.time },
|
|
401
|
+
_distfiles: { ...manifest._distfiles }
|
|
402
|
+
};
|
|
521
403
|
}
|
|
404
|
+
//#endregion
|
|
405
|
+
//#region src/packageFilter.ts
|
|
406
|
+
var debug$1 = (0, debug.default)("verdaccio:plugin:package-filter");
|
|
407
|
+
var PackageFilterPlugin = class extends _verdaccio_core.pluginUtils.Plugin {
|
|
408
|
+
config;
|
|
409
|
+
parsedConfig;
|
|
410
|
+
logger;
|
|
411
|
+
constructor(config, options) {
|
|
412
|
+
super(config, options);
|
|
413
|
+
this.config = config ?? {};
|
|
414
|
+
this.logger = options.logger;
|
|
415
|
+
this.parsedConfig = parseConfig(this.config);
|
|
416
|
+
debug$1("plugin loaded: block rules: %d, allow rules: %d", this.parsedConfig.blockRules.size, this.parsedConfig.allowRules.size);
|
|
417
|
+
this.logger.debug({ config: JSON.stringify(this.parsedConfig, jsonLogReplacer) }, "package-filter loaded with config: @{config}");
|
|
418
|
+
this.logger.trace({
|
|
419
|
+
blockRules: this.parsedConfig.blockRules.size,
|
|
420
|
+
allowRules: this.parsedConfig.allowRules.size
|
|
421
|
+
}, "package-filter plugin initialized: @{blockRules} block rules, @{allowRules} allow rules");
|
|
422
|
+
if (this.parsedConfig.dateThreshold) {
|
|
423
|
+
debug$1("date threshold: %s", this.parsedConfig.dateThreshold.toISOString());
|
|
424
|
+
this.logger.trace({ dateThreshold: this.parsedConfig.dateThreshold.toISOString() }, "package-filter date threshold: @{dateThreshold}");
|
|
425
|
+
}
|
|
426
|
+
if (this.parsedConfig.minAgeMs) {
|
|
427
|
+
const minAgeDays = this.parsedConfig.minAgeMs / (1440 * 60 * 1e3);
|
|
428
|
+
debug$1("min age: %d days", minAgeDays);
|
|
429
|
+
this.logger.trace({ minAgeDays }, "package-filter min age: @{minAgeDays} days");
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async filter_metadata(manifest) {
|
|
433
|
+
const { dateThreshold, minAgeMs, blockRules, allowRules } = this.parsedConfig;
|
|
434
|
+
const versionCount = Object.keys(manifest.versions ?? {}).length;
|
|
435
|
+
debug$1("filtering manifest for %s (%d versions)", manifest.name, versionCount);
|
|
436
|
+
this.logger.trace({
|
|
437
|
+
name: manifest.name,
|
|
438
|
+
versionCount
|
|
439
|
+
}, "package-filter processing @{name} (@{versionCount} versions)");
|
|
440
|
+
let newManifest = getManifestClone(manifest);
|
|
441
|
+
if (blockRules.size > 0) newManifest = filterBlockedVersions(newManifest, blockRules, allowRules, this.logger);
|
|
442
|
+
let earliestDateThreshold = null;
|
|
443
|
+
if (minAgeMs) earliestDateThreshold = new Date(Date.now() - minAgeMs);
|
|
444
|
+
if (dateThreshold && (!earliestDateThreshold || dateThreshold < earliestDateThreshold)) earliestDateThreshold = dateThreshold;
|
|
445
|
+
if (earliestDateThreshold) {
|
|
446
|
+
debug$1("applying date filter for %s, threshold: %s", manifest.name, earliestDateThreshold.toISOString());
|
|
447
|
+
this.logger.trace({
|
|
448
|
+
name: manifest.name,
|
|
449
|
+
threshold: earliestDateThreshold.toISOString()
|
|
450
|
+
}, "applying date filter for @{name}, cutoff: @{threshold}");
|
|
451
|
+
newManifest = filterVersionsByPublishDate(newManifest, earliestDateThreshold, allowRules);
|
|
452
|
+
}
|
|
453
|
+
cleanupTags(newManifest);
|
|
454
|
+
setupLatestTag(newManifest);
|
|
455
|
+
cleanupTime(newManifest);
|
|
456
|
+
setupCreatedAndModified(newManifest);
|
|
457
|
+
cleanupDistFiles(newManifest);
|
|
458
|
+
const filteredCount = Object.keys(newManifest.versions).length;
|
|
459
|
+
const removedCount = versionCount - filteredCount;
|
|
460
|
+
if (filteredCount !== versionCount) {
|
|
461
|
+
debug$1("filtered %s: %d -> %d versions (%d removed)", manifest.name, versionCount, filteredCount, removedCount);
|
|
462
|
+
this.logger.trace({
|
|
463
|
+
name: manifest.name,
|
|
464
|
+
before: versionCount,
|
|
465
|
+
after: filteredCount,
|
|
466
|
+
removed: removedCount
|
|
467
|
+
}, "package-filter @{name}: @{before} -> @{after} versions (@{removed} removed)");
|
|
468
|
+
} else debug$1("no versions filtered for %s", manifest.name);
|
|
469
|
+
return newManifest;
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/index.ts
|
|
474
|
+
var src_default = PackageFilterPlugin;
|
|
475
|
+
//#endregion
|
|
522
476
|
exports.PackageFilterPlugin = PackageFilterPlugin;
|
|
523
|
-
exports.default =
|
|
524
|
-
|
|
477
|
+
exports.default = src_default;
|
|
478
|
+
|
|
479
|
+
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/config/parser.ts","../src/filtering/types.ts","../src/filtering/matcher.ts","../src/filtering/packageVersion.ts","../src/filtering/publishDate.ts","../src/utils/jsonUtils.ts","../src/utils/manifestUtils.ts","../src/packageFilter.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","import type { PackageScopeLevel, ParsedConfigRule } from '../config/types';\n\nexport enum MatchType {\n SCOPE = 'scope',\n PACKAGE = 'package',\n VERSIONS = 'versions',\n}\n\nexport interface MatchResultVersions {\n versions: string[];\n}\n\nexport interface MatchScopeResult extends MatchResultVersions {\n type: MatchType.SCOPE;\n rule: PackageScopeLevel;\n scope: string;\n}\n\nexport interface MatchPackageResult extends MatchResultVersions {\n type: MatchType.PACKAGE;\n rule: PackageScopeLevel;\n package: string;\n}\n\nexport interface MatchVersionsResult extends MatchResultVersions {\n type: MatchType.VERSIONS;\n rule: ParsedConfigRule;\n}\n\nexport type MatchResult = MatchScopeResult | MatchPackageResult | MatchVersionsResult;\n","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","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","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","import { Range } from 'semver';\n\nexport function jsonLogReplacer(_key: string, value: unknown) {\n if (value instanceof Map) {\n return Object.fromEntries(value);\n }\n\n if (value instanceof Range) {\n return value.range;\n }\n\n return value;\n}\n","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 const sortedTimes = times.sort((a, b) => new Date(a).getTime() - new Date(b).getTime());\n time.created = sortedTimes[0];\n time.modified = sortedTimes[sortedTimes.length - 1];\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","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 newManifest = getManifestClone(manifest);\n if (blockRules.size > 0) {\n newManifest = filterBlockedVersions(newManifest, blockRules, allowRules, this.logger);\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 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 cleanupTags(newManifest);\n setupLatestTag(newManifest);\n cleanupTime(newManifest);\n setupCreatedAndModified(newManifest);\n cleanupDistFiles(newManifest);\n\n const filteredCount = Object.keys(newManifest.versions).length;\n const removedCount = versionCount - filteredCount;\n if (filteredCount !== versionCount) {\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"],"names":["debug","Range","MatchType","rule","satisfies","DIST_TAGS","pluginUtils"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/config/parser.ts","../src/filtering/types.ts","../src/filtering/matcher.ts","../src/filtering/packageVersion.ts","../src/filtering/publishDate.ts","../src/utils/jsonUtils.ts","../src/utils/manifestUtils.ts","../src/packageFilter.ts","../src/index.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","import type { PackageScopeLevel, ParsedConfigRule } from '../config/types';\n\nexport enum MatchType {\n SCOPE = 'scope',\n PACKAGE = 'package',\n VERSIONS = 'versions',\n}\n\nexport interface MatchResultVersions {\n versions: string[];\n}\n\nexport interface MatchScopeResult extends MatchResultVersions {\n type: MatchType.SCOPE;\n rule: PackageScopeLevel;\n scope: string;\n}\n\nexport interface MatchPackageResult extends MatchResultVersions {\n type: MatchType.PACKAGE;\n rule: PackageScopeLevel;\n package: string;\n}\n\nexport interface MatchVersionsResult extends MatchResultVersions {\n type: MatchType.VERSIONS;\n rule: ParsedConfigRule;\n}\n\nexport type MatchResult = MatchScopeResult | MatchPackageResult | MatchVersionsResult;\n","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","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","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","import { Range } from 'semver';\n\nexport function jsonLogReplacer(_key: string, value: unknown) {\n if (value instanceof Map) {\n return Object.fromEntries(value);\n }\n\n if (value instanceof Range) {\n return value.range;\n }\n\n return value;\n}\n","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 const sortedTimes = times.sort((a, b) => new Date(a).getTime() - new Date(b).getTime());\n time.created = sortedTimes[0];\n time.modified = sortedTimes[sortedTimes.length - 1];\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","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 newManifest = getManifestClone(manifest);\n if (blockRules.size > 0) {\n newManifest = filterBlockedVersions(newManifest, blockRules, allowRules, this.logger);\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 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 cleanupTags(newManifest);\n setupLatestTag(newManifest);\n cleanupTime(newManifest);\n setupCreatedAndModified(newManifest);\n cleanupDistFiles(newManifest);\n\n const filteredCount = Object.keys(newManifest.versions).length;\n const removedCount = versionCount - filteredCount;\n if (filteredCount !== versionCount) {\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","import { PackageFilterPlugin } from './packageFilter';\n\nexport { PackageFilterPlugin };\nexport default PackageFilterPlugin;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdaccio/package-filter",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.1",
|
|
4
4
|
"description": "Package filter plugin for Verdaccio that allows blocking packages by name, scope, version or date",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"private",
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
"node": ">=18"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@verdaccio/core": "8.
|
|
38
|
+
"@verdaccio/core": "8.1.0",
|
|
39
39
|
"debug": "4.4.3",
|
|
40
40
|
"semver": "7.7.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/debug": "4.1.12",
|
|
44
|
-
"@verdaccio/config": "8.
|
|
45
|
-
"@verdaccio/logger": "8.0.
|
|
44
|
+
"@verdaccio/config": "8.1.0",
|
|
45
|
+
"@verdaccio/logger": "8.0.1",
|
|
46
46
|
"@verdaccio/types": "13.0.0",
|
|
47
|
-
"vite": "
|
|
48
|
-
"vitest": "
|
|
47
|
+
"vite": "8.0.5",
|
|
48
|
+
"vitest": "4.1.2"
|
|
49
49
|
},
|
|
50
50
|
"funding": {
|
|
51
51
|
"type": "opencollective",
|