@verdaccio/store 9.0.0-next-9.31 → 9.0.0-next-9.33
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/lib/versions-utils.d.ts +5 -5
- package/build/lib/versions-utils.js +13 -8
- package/build/lib/versions-utils.js.map +1 -1
- package/build/lib/versions-utils.mjs +14 -9
- package/build/lib/versions-utils.mjs.map +1 -1
- package/build/storage.d.ts +12 -0
- package/build/storage.js +115 -17
- package/build/storage.js.map +1 -1
- package/build/storage.mjs +118 -20
- package/build/storage.mjs.map +1 -1
- package/package.json +13 -13
|
@@ -28,12 +28,12 @@ export declare function tagVersion(data: Manifest, version: string, tag: StringV
|
|
|
28
28
|
*/
|
|
29
29
|
export declare function tagVersionNext(manifest: Manifest, version: string, tag: StringValue): Manifest;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
31
|
+
* Whether `newVersion` is strictly newer than `oldVersion` under loose semver.
|
|
32
|
+
* Equal versions in any spelling (`1.2.3`, `v1.2.3`, `01.2.3`, `1.2.3+build`) are
|
|
33
|
+
* not newer, so search merges keep the entry they saw first, which is the local one.
|
|
34
|
+
* Both arguments must already pass `pkgUtils.isValidVersion`.
|
|
35
35
|
*/
|
|
36
|
-
export declare function isNewerVersion(newVersion:
|
|
36
|
+
export declare function isNewerVersion(newVersion: string, oldVersion: string): boolean;
|
|
37
37
|
/**
|
|
38
38
|
* Remove duplicates from search results.
|
|
39
39
|
* @param {Array} objects
|
|
@@ -58,14 +58,13 @@ function tagVersionNext(manifest, version, tag) {
|
|
|
58
58
|
return data;
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
61
|
+
* Whether `newVersion` is strictly newer than `oldVersion` under loose semver.
|
|
62
|
+
* Equal versions in any spelling (`1.2.3`, `v1.2.3`, `01.2.3`, `1.2.3+build`) are
|
|
63
|
+
* not newer, so search merges keep the entry they saw first, which is the local one.
|
|
64
|
+
* Both arguments must already pass `pkgUtils.isValidVersion`.
|
|
65
65
|
*/
|
|
66
66
|
function isNewerVersion(newVersion, oldVersion) {
|
|
67
|
-
|
|
68
|
-
return comparisonResult === 1 || comparisonResult === 0;
|
|
67
|
+
return semver.default.compareLoose(newVersion, oldVersion) === 1;
|
|
69
68
|
}
|
|
70
69
|
/**
|
|
71
70
|
* Remove duplicates from search results.
|
|
@@ -74,7 +73,13 @@ function isNewerVersion(newVersion, oldVersion) {
|
|
|
74
73
|
*/
|
|
75
74
|
function removeLowerVersions(objects) {
|
|
76
75
|
const versionMap = /* @__PURE__ */ new Map();
|
|
77
|
-
objects.
|
|
76
|
+
const validObjects = objects.filter((item) => {
|
|
77
|
+
const version = item?.package?.version;
|
|
78
|
+
const valid = _verdaccio_core.pkgUtils.isValidVersion(version);
|
|
79
|
+
if (!valid) debug$1("ignoring invalid search version %o", version);
|
|
80
|
+
return valid;
|
|
81
|
+
});
|
|
82
|
+
validObjects.forEach((item) => {
|
|
78
83
|
const { name, version } = item.package;
|
|
79
84
|
const key = name;
|
|
80
85
|
if (versionMap.has(name) === false || isNewerVersion(version, versionMap.get(name))) {
|
|
@@ -82,7 +87,7 @@ function removeLowerVersions(objects) {
|
|
|
82
87
|
versionMap.set(key, version);
|
|
83
88
|
}
|
|
84
89
|
});
|
|
85
|
-
return
|
|
90
|
+
return validObjects.reduce((acc, item) => {
|
|
86
91
|
const { name, version } = item.package;
|
|
87
92
|
if (versionMap.has(name) && versionMap.get(name) === version && acc.find((i) => i.package.name === name) === void 0) {
|
|
88
93
|
debug$1("adding %o@%o", name, version);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions-utils.js","names":[],"sources":["../../src/lib/versions-utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { isNil } from 'lodash-es';\nimport type { SemVer } from 'semver';\nimport semver from 'semver';\n\nimport type { searchUtils } from '@verdaccio/core';\nimport { DIST_TAGS } from '@verdaccio/core';\nimport type { Manifest, StringValue, Version, Versions } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:storage:utils');\n\n/**\n * Gets version from a package object taking into account semver weirdness.\n * @return {String} return the semantic version of a package\n */\nexport function getVersion(versions: Versions, version: string): Version | undefined {\n if (!versions) {\n return;\n }\n\n // this condition must allow cast\n if (isNil(versions[version]) === false) {\n return versions[version];\n }\n\n const versionSemver: SemVer | null = semver.parse(version, true);\n if (versionSemver === null) {\n return;\n }\n\n for (const versionItem in versions) {\n if (Object.prototype.hasOwnProperty.call(versions, versionItem)) {\n // @ts-ignore\n if (versionSemver.compare(semver.parse(versionItem, true)) === 0) {\n return versions[versionItem];\n }\n }\n }\n}\n\n/**\n * Function filters out bad semver versions and sorts the array.\n * @return {Array} sorted Array\n */\nexport function sortVersionsAndFilterInvalid(listVersions: string[] /* logger */): string[] {\n return listVersions\n .filter(function (version): boolean {\n if (!semver.parse(version, true)) {\n return false;\n }\n return true;\n })\n .sort(semver.compareLoose)\n .map(String);\n}\n\n/**\n * Create a tag for a package\n * @param {*} data\n * @param {*} version\n * @param {*} tag\n * @return {Boolean} whether a package has been tagged\n * @deprecated\n */\nexport function tagVersion(data: Manifest, version: string, tag: StringValue): boolean {\n if (tag && data[DIST_TAGS][tag] !== version && semver.parse(version, true)) {\n // valid version - store\n data[DIST_TAGS][tag] = version;\n return true;\n }\n return false;\n}\n\n/**\n *\n * @param manifest\n * @param version\n * @param tag\n * @returns\n */\nexport function tagVersionNext(manifest: Manifest, version: string, tag: StringValue): Manifest {\n const data = { ...manifest };\n if (tag && data[DIST_TAGS][tag] !== version && semver.parse(version, true)) {\n // valid version - store\n data[DIST_TAGS][tag] = version;\n }\n return data;\n}\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"versions-utils.js","names":[],"sources":["../../src/lib/versions-utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { isNil } from 'lodash-es';\nimport type { SemVer } from 'semver';\nimport semver from 'semver';\n\nimport type { searchUtils } from '@verdaccio/core';\nimport { DIST_TAGS, pkgUtils } from '@verdaccio/core';\nimport type { Manifest, StringValue, Version, Versions } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:storage:utils');\n\n/**\n * Gets version from a package object taking into account semver weirdness.\n * @return {String} return the semantic version of a package\n */\nexport function getVersion(versions: Versions, version: string): Version | undefined {\n if (!versions) {\n return;\n }\n\n // this condition must allow cast\n if (isNil(versions[version]) === false) {\n return versions[version];\n }\n\n const versionSemver: SemVer | null = semver.parse(version, true);\n if (versionSemver === null) {\n return;\n }\n\n for (const versionItem in versions) {\n if (Object.prototype.hasOwnProperty.call(versions, versionItem)) {\n // @ts-ignore\n if (versionSemver.compare(semver.parse(versionItem, true)) === 0) {\n return versions[versionItem];\n }\n }\n }\n}\n\n/**\n * Function filters out bad semver versions and sorts the array.\n * @return {Array} sorted Array\n */\nexport function sortVersionsAndFilterInvalid(listVersions: string[] /* logger */): string[] {\n return listVersions\n .filter(function (version): boolean {\n if (!semver.parse(version, true)) {\n return false;\n }\n return true;\n })\n .sort(semver.compareLoose)\n .map(String);\n}\n\n/**\n * Create a tag for a package\n * @param {*} data\n * @param {*} version\n * @param {*} tag\n * @return {Boolean} whether a package has been tagged\n * @deprecated\n */\nexport function tagVersion(data: Manifest, version: string, tag: StringValue): boolean {\n if (tag && data[DIST_TAGS][tag] !== version && semver.parse(version, true)) {\n // valid version - store\n data[DIST_TAGS][tag] = version;\n return true;\n }\n return false;\n}\n\n/**\n *\n * @param manifest\n * @param version\n * @param tag\n * @returns\n */\nexport function tagVersionNext(manifest: Manifest, version: string, tag: StringValue): Manifest {\n const data = { ...manifest };\n if (tag && data[DIST_TAGS][tag] !== version && semver.parse(version, true)) {\n // valid version - store\n data[DIST_TAGS][tag] = version;\n }\n return data;\n}\n\n/**\n * Whether `newVersion` is strictly newer than `oldVersion` under loose semver.\n * Equal versions in any spelling (`1.2.3`, `v1.2.3`, `01.2.3`, `1.2.3+build`) are\n * not newer, so search merges keep the entry they saw first, which is the local one.\n * Both arguments must already pass `pkgUtils.isValidVersion`.\n */\nexport function isNewerVersion(newVersion: string, oldVersion: string): boolean {\n return semver.compareLoose(newVersion, oldVersion) === 1;\n}\n\n/**\n * Remove duplicates from search results.\n * @param {Array} objects\n * @return {Array} filtered array\n */\nexport function removeLowerVersions(objects: searchUtils.SearchPackageItem[]) {\n const versionMap = new Map();\n const validObjects = objects.filter((item) => {\n const version = item?.package?.version;\n const valid = pkgUtils.isValidVersion(version);\n if (!valid) debug('ignoring invalid search version %o', version);\n return valid;\n });\n\n // Iterate through the array and keep the highest version for each name\n validObjects.forEach((item) => {\n const { name, version } = item.package;\n const key = name;\n\n if (versionMap.has(name) === false || isNewerVersion(version, versionMap.get(name))) {\n debug('keeping %o@%o', name, version);\n versionMap.set(key, version);\n }\n });\n\n // Filter objects based on the version map\n return validObjects.reduce((acc, item) => {\n const { name, version } = item.package;\n if (\n versionMap.has(name) &&\n versionMap.get(name) === version &&\n acc.find((i) => i.package.name === name) === undefined\n ) {\n debug('adding %o@%o', name, version);\n acc.push(item);\n }\n return acc;\n }, [] as searchUtils.SearchPackageItem[]);\n}\n"],"mappings":";;;;;;;;AASA,IAAM,WAAA,GAAQ,MAAA,QAAA,CAAW,yBAAyB;;;;;AAMlD,SAAgB,WAAW,UAAoB,SAAsC;CACnF,IAAI,CAAC,UACH;CAIF,KAAA,GAAI,UAAA,MAAA,CAAM,SAAS,QAAQ,MAAM,OAC/B,OAAO,SAAS;CAGlB,MAAM,gBAA+B,OAAA,QAAO,MAAM,SAAS,IAAI;CAC/D,IAAI,kBAAkB,MACpB;CAGF,KAAK,MAAM,eAAe,UACxB,IAAI,OAAO,UAAU,eAAe,KAAK,UAAU,WAAW,GAExD;MAAA,cAAc,QAAQ,OAAA,QAAO,MAAM,aAAa,IAAI,CAAC,MAAM,GAC7D,OAAO,SAAS;CAAA;AAIxB;;;;;AAMA,SAAgB,6BAA6B,cAA+C;CAC1F,OAAO,aACJ,OAAO,SAAU,SAAkB;EAClC,IAAI,CAAC,OAAA,QAAO,MAAM,SAAS,IAAI,GAC7B,OAAO;EAET,OAAO;CACT,CAAC,CAAC,CACD,KAAK,OAAA,QAAO,YAAY,CAAC,CACzB,IAAI,MAAM;AACf;;;;;;;;;AAUA,SAAgB,WAAW,MAAgB,SAAiB,KAA2B;CACrF,IAAI,OAAO,KAAK,gBAAA,UAAU,CAAC,SAAS,WAAW,OAAA,QAAO,MAAM,SAAS,IAAI,GAAG;EAE1E,KAAK,gBAAA,UAAU,CAAC,OAAO;EACvB,OAAO;CACT;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,eAAe,UAAoB,SAAiB,KAA4B;CAC9F,MAAM,OAAO,EAAE,GAAG,SAAS;CAC3B,IAAI,OAAO,KAAK,gBAAA,UAAU,CAAC,SAAS,WAAW,OAAA,QAAO,MAAM,SAAS,IAAI,GAEvE,KAAK,gBAAA,UAAU,CAAC,OAAO;CAEzB,OAAO;AACT;;;;;;;AAQA,SAAgB,eAAe,YAAoB,YAA6B;CAC9E,OAAO,OAAA,QAAO,aAAa,YAAY,UAAU,MAAM;AACzD;;;;;;AAOA,SAAgB,oBAAoB,SAA0C;CAC5E,MAAM,6BAAa,IAAI,IAAI;CAC3B,MAAM,eAAe,QAAQ,QAAQ,SAAS;EAC5C,MAAM,UAAU,MAAM,SAAS;EAC/B,MAAM,QAAQ,gBAAA,SAAS,eAAe,OAAO;EAC7C,IAAI,CAAC,OAAO,QAAM,sCAAsC,OAAO;EAC/D,OAAO;CACT,CAAC;CAGD,aAAa,SAAS,SAAS;EAC7B,MAAM,EAAE,MAAM,YAAY,KAAK;EAC/B,MAAM,MAAM;EAEZ,IAAI,WAAW,IAAI,IAAI,MAAM,SAAS,eAAe,SAAS,WAAW,IAAI,IAAI,CAAC,GAAG;GACnF,QAAM,iBAAiB,MAAM,OAAO;GACpC,WAAW,IAAI,KAAK,OAAO;EAC7B;CACF,CAAC;CAGD,OAAO,aAAa,QAAQ,KAAK,SAAS;EACxC,MAAM,EAAE,MAAM,YAAY,KAAK;EAC/B,IACE,WAAW,IAAI,IAAI,KACnB,WAAW,IAAI,IAAI,MAAM,WACzB,IAAI,MAAM,MAAM,EAAE,QAAQ,SAAS,IAAI,MAAM,KAAA,GAC7C;GACA,QAAM,gBAAgB,MAAM,OAAO;GACnC,IAAI,KAAK,IAAI;EACf;EACA,OAAO;CACT,GAAG,CAAC,CAAoC;AAC1C"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import buildDebug from "debug";
|
|
2
2
|
import { isNil } from "lodash-es";
|
|
3
|
-
import { DIST_TAGS } from "@verdaccio/core";
|
|
3
|
+
import { DIST_TAGS, pkgUtils } from "@verdaccio/core";
|
|
4
4
|
import semver from "semver";
|
|
5
5
|
//#region src/lib/versions-utils.ts
|
|
6
6
|
var debug = buildDebug("verdaccio:storage:utils");
|
|
@@ -55,14 +55,13 @@ function tagVersionNext(manifest, version, tag) {
|
|
|
55
55
|
return data;
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
58
|
+
* Whether `newVersion` is strictly newer than `oldVersion` under loose semver.
|
|
59
|
+
* Equal versions in any spelling (`1.2.3`, `v1.2.3`, `01.2.3`, `1.2.3+build`) are
|
|
60
|
+
* not newer, so search merges keep the entry they saw first, which is the local one.
|
|
61
|
+
* Both arguments must already pass `pkgUtils.isValidVersion`.
|
|
62
62
|
*/
|
|
63
63
|
function isNewerVersion(newVersion, oldVersion) {
|
|
64
|
-
|
|
65
|
-
return comparisonResult === 1 || comparisonResult === 0;
|
|
64
|
+
return semver.compareLoose(newVersion, oldVersion) === 1;
|
|
66
65
|
}
|
|
67
66
|
/**
|
|
68
67
|
* Remove duplicates from search results.
|
|
@@ -71,7 +70,13 @@ function isNewerVersion(newVersion, oldVersion) {
|
|
|
71
70
|
*/
|
|
72
71
|
function removeLowerVersions(objects) {
|
|
73
72
|
const versionMap = /* @__PURE__ */ new Map();
|
|
74
|
-
objects.
|
|
73
|
+
const validObjects = objects.filter((item) => {
|
|
74
|
+
const version = item?.package?.version;
|
|
75
|
+
const valid = pkgUtils.isValidVersion(version);
|
|
76
|
+
if (!valid) debug("ignoring invalid search version %o", version);
|
|
77
|
+
return valid;
|
|
78
|
+
});
|
|
79
|
+
validObjects.forEach((item) => {
|
|
75
80
|
const { name, version } = item.package;
|
|
76
81
|
const key = name;
|
|
77
82
|
if (versionMap.has(name) === false || isNewerVersion(version, versionMap.get(name))) {
|
|
@@ -79,7 +84,7 @@ function removeLowerVersions(objects) {
|
|
|
79
84
|
versionMap.set(key, version);
|
|
80
85
|
}
|
|
81
86
|
});
|
|
82
|
-
return
|
|
87
|
+
return validObjects.reduce((acc, item) => {
|
|
83
88
|
const { name, version } = item.package;
|
|
84
89
|
if (versionMap.has(name) && versionMap.get(name) === version && acc.find((i) => i.package.name === name) === void 0) {
|
|
85
90
|
debug("adding %o@%o", name, version);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions-utils.mjs","names":[],"sources":["../../src/lib/versions-utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { isNil } from 'lodash-es';\nimport type { SemVer } from 'semver';\nimport semver from 'semver';\n\nimport type { searchUtils } from '@verdaccio/core';\nimport { DIST_TAGS } from '@verdaccio/core';\nimport type { Manifest, StringValue, Version, Versions } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:storage:utils');\n\n/**\n * Gets version from a package object taking into account semver weirdness.\n * @return {String} return the semantic version of a package\n */\nexport function getVersion(versions: Versions, version: string): Version | undefined {\n if (!versions) {\n return;\n }\n\n // this condition must allow cast\n if (isNil(versions[version]) === false) {\n return versions[version];\n }\n\n const versionSemver: SemVer | null = semver.parse(version, true);\n if (versionSemver === null) {\n return;\n }\n\n for (const versionItem in versions) {\n if (Object.prototype.hasOwnProperty.call(versions, versionItem)) {\n // @ts-ignore\n if (versionSemver.compare(semver.parse(versionItem, true)) === 0) {\n return versions[versionItem];\n }\n }\n }\n}\n\n/**\n * Function filters out bad semver versions and sorts the array.\n * @return {Array} sorted Array\n */\nexport function sortVersionsAndFilterInvalid(listVersions: string[] /* logger */): string[] {\n return listVersions\n .filter(function (version): boolean {\n if (!semver.parse(version, true)) {\n return false;\n }\n return true;\n })\n .sort(semver.compareLoose)\n .map(String);\n}\n\n/**\n * Create a tag for a package\n * @param {*} data\n * @param {*} version\n * @param {*} tag\n * @return {Boolean} whether a package has been tagged\n * @deprecated\n */\nexport function tagVersion(data: Manifest, version: string, tag: StringValue): boolean {\n if (tag && data[DIST_TAGS][tag] !== version && semver.parse(version, true)) {\n // valid version - store\n data[DIST_TAGS][tag] = version;\n return true;\n }\n return false;\n}\n\n/**\n *\n * @param manifest\n * @param version\n * @param tag\n * @returns\n */\nexport function tagVersionNext(manifest: Manifest, version: string, tag: StringValue): Manifest {\n const data = { ...manifest };\n if (tag && data[DIST_TAGS][tag] !== version && semver.parse(version, true)) {\n // valid version - store\n data[DIST_TAGS][tag] = version;\n }\n return data;\n}\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"versions-utils.mjs","names":[],"sources":["../../src/lib/versions-utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { isNil } from 'lodash-es';\nimport type { SemVer } from 'semver';\nimport semver from 'semver';\n\nimport type { searchUtils } from '@verdaccio/core';\nimport { DIST_TAGS, pkgUtils } from '@verdaccio/core';\nimport type { Manifest, StringValue, Version, Versions } from '@verdaccio/types';\n\nconst debug = buildDebug('verdaccio:storage:utils');\n\n/**\n * Gets version from a package object taking into account semver weirdness.\n * @return {String} return the semantic version of a package\n */\nexport function getVersion(versions: Versions, version: string): Version | undefined {\n if (!versions) {\n return;\n }\n\n // this condition must allow cast\n if (isNil(versions[version]) === false) {\n return versions[version];\n }\n\n const versionSemver: SemVer | null = semver.parse(version, true);\n if (versionSemver === null) {\n return;\n }\n\n for (const versionItem in versions) {\n if (Object.prototype.hasOwnProperty.call(versions, versionItem)) {\n // @ts-ignore\n if (versionSemver.compare(semver.parse(versionItem, true)) === 0) {\n return versions[versionItem];\n }\n }\n }\n}\n\n/**\n * Function filters out bad semver versions and sorts the array.\n * @return {Array} sorted Array\n */\nexport function sortVersionsAndFilterInvalid(listVersions: string[] /* logger */): string[] {\n return listVersions\n .filter(function (version): boolean {\n if (!semver.parse(version, true)) {\n return false;\n }\n return true;\n })\n .sort(semver.compareLoose)\n .map(String);\n}\n\n/**\n * Create a tag for a package\n * @param {*} data\n * @param {*} version\n * @param {*} tag\n * @return {Boolean} whether a package has been tagged\n * @deprecated\n */\nexport function tagVersion(data: Manifest, version: string, tag: StringValue): boolean {\n if (tag && data[DIST_TAGS][tag] !== version && semver.parse(version, true)) {\n // valid version - store\n data[DIST_TAGS][tag] = version;\n return true;\n }\n return false;\n}\n\n/**\n *\n * @param manifest\n * @param version\n * @param tag\n * @returns\n */\nexport function tagVersionNext(manifest: Manifest, version: string, tag: StringValue): Manifest {\n const data = { ...manifest };\n if (tag && data[DIST_TAGS][tag] !== version && semver.parse(version, true)) {\n // valid version - store\n data[DIST_TAGS][tag] = version;\n }\n return data;\n}\n\n/**\n * Whether `newVersion` is strictly newer than `oldVersion` under loose semver.\n * Equal versions in any spelling (`1.2.3`, `v1.2.3`, `01.2.3`, `1.2.3+build`) are\n * not newer, so search merges keep the entry they saw first, which is the local one.\n * Both arguments must already pass `pkgUtils.isValidVersion`.\n */\nexport function isNewerVersion(newVersion: string, oldVersion: string): boolean {\n return semver.compareLoose(newVersion, oldVersion) === 1;\n}\n\n/**\n * Remove duplicates from search results.\n * @param {Array} objects\n * @return {Array} filtered array\n */\nexport function removeLowerVersions(objects: searchUtils.SearchPackageItem[]) {\n const versionMap = new Map();\n const validObjects = objects.filter((item) => {\n const version = item?.package?.version;\n const valid = pkgUtils.isValidVersion(version);\n if (!valid) debug('ignoring invalid search version %o', version);\n return valid;\n });\n\n // Iterate through the array and keep the highest version for each name\n validObjects.forEach((item) => {\n const { name, version } = item.package;\n const key = name;\n\n if (versionMap.has(name) === false || isNewerVersion(version, versionMap.get(name))) {\n debug('keeping %o@%o', name, version);\n versionMap.set(key, version);\n }\n });\n\n // Filter objects based on the version map\n return validObjects.reduce((acc, item) => {\n const { name, version } = item.package;\n if (\n versionMap.has(name) &&\n versionMap.get(name) === version &&\n acc.find((i) => i.package.name === name) === undefined\n ) {\n debug('adding %o@%o', name, version);\n acc.push(item);\n }\n return acc;\n }, [] as searchUtils.SearchPackageItem[]);\n}\n"],"mappings":";;;;;AASA,IAAM,QAAQ,WAAW,yBAAyB;;;;;AAMlD,SAAgB,WAAW,UAAoB,SAAsC;CACnF,IAAI,CAAC,UACH;CAIF,IAAI,MAAM,SAAS,QAAQ,MAAM,OAC/B,OAAO,SAAS;CAGlB,MAAM,gBAA+B,OAAO,MAAM,SAAS,IAAI;CAC/D,IAAI,kBAAkB,MACpB;CAGF,KAAK,MAAM,eAAe,UACxB,IAAI,OAAO,UAAU,eAAe,KAAK,UAAU,WAAW,GAExD;MAAA,cAAc,QAAQ,OAAO,MAAM,aAAa,IAAI,CAAC,MAAM,GAC7D,OAAO,SAAS;CAAA;AAIxB;;;;;AAMA,SAAgB,6BAA6B,cAA+C;CAC1F,OAAO,aACJ,OAAO,SAAU,SAAkB;EAClC,IAAI,CAAC,OAAO,MAAM,SAAS,IAAI,GAC7B,OAAO;EAET,OAAO;CACT,CAAC,CAAC,CACD,KAAK,OAAO,YAAY,CAAC,CACzB,IAAI,MAAM;AACf;;;;;;;;;AAUA,SAAgB,WAAW,MAAgB,SAAiB,KAA2B;CACrF,IAAI,OAAO,KAAK,UAAU,CAAC,SAAS,WAAW,OAAO,MAAM,SAAS,IAAI,GAAG;EAE1E,KAAK,UAAU,CAAC,OAAO;EACvB,OAAO;CACT;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,eAAe,UAAoB,SAAiB,KAA4B;CAC9F,MAAM,OAAO,EAAE,GAAG,SAAS;CAC3B,IAAI,OAAO,KAAK,UAAU,CAAC,SAAS,WAAW,OAAO,MAAM,SAAS,IAAI,GAEvE,KAAK,UAAU,CAAC,OAAO;CAEzB,OAAO;AACT;;;;;;;AAQA,SAAgB,eAAe,YAAoB,YAA6B;CAC9E,OAAO,OAAO,aAAa,YAAY,UAAU,MAAM;AACzD;;;;;;AAOA,SAAgB,oBAAoB,SAA0C;CAC5E,MAAM,6BAAa,IAAI,IAAI;CAC3B,MAAM,eAAe,QAAQ,QAAQ,SAAS;EAC5C,MAAM,UAAU,MAAM,SAAS;EAC/B,MAAM,QAAQ,SAAS,eAAe,OAAO;EAC7C,IAAI,CAAC,OAAO,MAAM,sCAAsC,OAAO;EAC/D,OAAO;CACT,CAAC;CAGD,aAAa,SAAS,SAAS;EAC7B,MAAM,EAAE,MAAM,YAAY,KAAK;EAC/B,MAAM,MAAM;EAEZ,IAAI,WAAW,IAAI,IAAI,MAAM,SAAS,eAAe,SAAS,WAAW,IAAI,IAAI,CAAC,GAAG;GACnF,MAAM,iBAAiB,MAAM,OAAO;GACpC,WAAW,IAAI,KAAK,OAAO;EAC7B;CACF,CAAC;CAGD,OAAO,aAAa,QAAQ,KAAK,SAAS;EACxC,MAAM,EAAE,MAAM,YAAY,KAAK;EAC/B,IACE,WAAW,IAAI,IAAI,KACnB,WAAW,IAAI,IAAI,MAAM,WACzB,IAAI,MAAM,MAAM,EAAE,QAAQ,SAAS,IAAI,MAAM,KAAA,GAC7C;GACA,MAAM,gBAAgB,MAAM,OAAO;GACnC,IAAI,KAAK,IAAI;EACf;EACA,OAAO;CACT,GAAG,CAAC,CAAoC;AAC1C"}
|
package/build/storage.d.ts
CHANGED
|
@@ -42,6 +42,8 @@ declare class Storage {
|
|
|
42
42
|
* (privated and cached).
|
|
43
43
|
*/
|
|
44
44
|
search(options: ProxySearchParams): Promise<searchUtils.SearchPackageItem[]>;
|
|
45
|
+
/** Cumulative, stable prefixes for Search v1; consumers stop once their page is full. */
|
|
46
|
+
searchPages(options: ProxySearchParams): AsyncGenerator<searchUtils.SearchPackageItem[], void, unknown>;
|
|
45
47
|
private getTarballFromUpstream;
|
|
46
48
|
private fetchTarballFromDistFile;
|
|
47
49
|
/**
|
|
@@ -120,6 +122,16 @@ declare class Storage {
|
|
|
120
122
|
* @param tags list of dist-tags
|
|
121
123
|
*/
|
|
122
124
|
mergeTagsNext(name: string, tags: MergeTags): Promise<Manifest>;
|
|
125
|
+
/**
|
|
126
|
+
* Resolve the uplink to fetch a distfile url from, or null when the fetch
|
|
127
|
+
* must be refused.
|
|
128
|
+
*
|
|
129
|
+
* Off-uplink urls on a locally published package are not fetched: the
|
|
130
|
+
* client's `dist.tarball` is stored verbatim, and fetching it would be SSRF
|
|
131
|
+
* (and would attach uplink credentials when only one uplink is configured).
|
|
132
|
+
* Uplink-synced packages may still use an autogenerated proxy without
|
|
133
|
+
* credentials for CDN-hosted tarballs.
|
|
134
|
+
*/
|
|
123
135
|
private getUpLinkForDistFile;
|
|
124
136
|
updateManifest(manifest: Manifest | OwnerManifestBody | UnPublishManifest, options: UpdateManifestOptions): Promise<string | undefined>;
|
|
125
137
|
private deprecate;
|
package/build/storage.js
CHANGED
|
@@ -159,39 +159,79 @@ var Storage = class {
|
|
|
159
159
|
debug$1("unique results %o", uniqueResults.length);
|
|
160
160
|
return uniqueResults;
|
|
161
161
|
}
|
|
162
|
+
/** Cumulative, stable prefixes for Search v1; consumers stop once their page is full. */
|
|
163
|
+
async *searchPages(options) {
|
|
164
|
+
options.abort.signal.throwIfAborted();
|
|
165
|
+
const local = await this.getCachedPackages({
|
|
166
|
+
...options.query,
|
|
167
|
+
from: 0,
|
|
168
|
+
size: _verdaccio_search.SEARCH_MAX_CANDIDATES
|
|
169
|
+
});
|
|
170
|
+
const merged = /* @__PURE__ */ new Map();
|
|
171
|
+
let candidates = 0;
|
|
172
|
+
const append = (items) => {
|
|
173
|
+
options.abort.signal.throwIfAborted();
|
|
174
|
+
candidates += items.length;
|
|
175
|
+
if (candidates > _verdaccio_search.SEARCH_MAX_CANDIDATES) throw _verdaccio_core.errorUtils.getServiceUnavailable("search pagination budget exhausted");
|
|
176
|
+
for (const item of items) {
|
|
177
|
+
if (!_verdaccio_core.pkgUtils.isValidVersion(item?.package?.version)) {
|
|
178
|
+
this.logger.warn({
|
|
179
|
+
name: item?.package?.name,
|
|
180
|
+
version: item?.package?.version
|
|
181
|
+
}, "ignoring invalid search version for @{name}: @{version}");
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const previous = merged.get(item.package.name);
|
|
185
|
+
if (!previous || require_versions_utils.isNewerVersion(item.package.version, previous.package.version)) merged.set(item.package.name, item);
|
|
186
|
+
}
|
|
187
|
+
return [...merged.values()];
|
|
188
|
+
};
|
|
189
|
+
append(local);
|
|
190
|
+
let hadRound = false;
|
|
191
|
+
for await (const round of this.searchService.searchPages(options)) {
|
|
192
|
+
hadRound = true;
|
|
193
|
+
yield append(round);
|
|
194
|
+
}
|
|
195
|
+
if (!hadRound) yield [...merged.values()];
|
|
196
|
+
}
|
|
162
197
|
async getTarballFromUpstream(name, filename, { signal }) {
|
|
163
198
|
this.logger.info({
|
|
164
199
|
name,
|
|
165
200
|
filename
|
|
166
201
|
}, "get tarball for package @{name} filename @{filename} from uplink");
|
|
167
202
|
let cachedManifest = null;
|
|
203
|
+
let rawManifest = null;
|
|
168
204
|
try {
|
|
169
|
-
|
|
170
|
-
[cachedManifest] = await this.applyFilters(
|
|
205
|
+
rawManifest = await this.getPackageLocalMetadata(name);
|
|
206
|
+
[cachedManifest] = await this.applyFilters(rawManifest);
|
|
171
207
|
} catch (err) {
|
|
172
208
|
debug$1("error on get package local metadata %o", err);
|
|
173
209
|
}
|
|
174
210
|
const cachedDistFile = cachedManifest !== null ? require_storage_utils.lookupDistFile(cachedManifest, filename) : null;
|
|
175
211
|
if (cachedDistFile !== null && typeof cachedDistFile.url === "string") {
|
|
176
212
|
debug$1("dist file found, using it %o", cachedDistFile.url);
|
|
177
|
-
return this.fetchTarballFromDistFile(name, filename, cachedDistFile, { signal });
|
|
213
|
+
return this.fetchTarballFromDistFile(name, filename, cachedDistFile, cachedManifest, { signal });
|
|
178
214
|
} else {
|
|
179
215
|
debug$1("dist file not found, proceed update upstream");
|
|
180
|
-
const [updatedManifest] = await this.syncUplinksMetadata(name,
|
|
216
|
+
const [updatedManifest] = await this.syncUplinksMetadata(name, rawManifest, { uplinksLook: true });
|
|
181
217
|
const distFile = updatedManifest === null ? null : require_storage_utils.lookupDistFile(updatedManifest, filename);
|
|
182
218
|
if (updatedManifest === null || !distFile) {
|
|
183
219
|
debug$1("remote tarball not found");
|
|
184
220
|
throw _verdaccio_core.errorUtils.getNotFound(_verdaccio_core.API_ERROR.NO_SUCH_FILE);
|
|
185
221
|
}
|
|
186
|
-
return this.fetchTarballFromDistFile(name, filename, distFile, { signal });
|
|
222
|
+
return this.fetchTarballFromDistFile(name, filename, distFile, updatedManifest, { signal });
|
|
187
223
|
}
|
|
188
224
|
}
|
|
189
|
-
fetchTarballFromDistFile(name, filename, distFile, { signal }) {
|
|
225
|
+
fetchTarballFromDistFile(name, filename, distFile, origin, { signal }) {
|
|
190
226
|
let current_length = 0;
|
|
191
227
|
let expected_length;
|
|
192
228
|
let uplinkStatusError = null;
|
|
193
229
|
const passThroughRemoteStream = new node_stream.PassThrough();
|
|
194
|
-
const proxy = this.getUpLinkForDistFile(name, distFile);
|
|
230
|
+
const proxy = this.getUpLinkForDistFile(name, filename, distFile, origin);
|
|
231
|
+
if (proxy === null) {
|
|
232
|
+
setImmediate(() => passThroughRemoteStream.emit("error", _verdaccio_core.errorUtils.getNotFound(_verdaccio_core.API_ERROR.NO_SUCH_FILE)));
|
|
233
|
+
return passThroughRemoteStream;
|
|
234
|
+
}
|
|
195
235
|
const remoteStream = proxy.fetchTarball(distFile.url, { throwHttpErrors: false });
|
|
196
236
|
const readRemoteBody = () => new Promise((resolve) => {
|
|
197
237
|
const chunks = [];
|
|
@@ -296,7 +336,14 @@ var Storage = class {
|
|
|
296
336
|
const localStream = await this.getLocalTarball(name, filename, { signal });
|
|
297
337
|
forwardContentLength(localStream);
|
|
298
338
|
localStream.on("open", async () => {
|
|
299
|
-
|
|
339
|
+
try {
|
|
340
|
+
await (0, node_stream_promises.pipeline)(localStream, localTarballStream, { signal });
|
|
341
|
+
} catch (err) {
|
|
342
|
+
this.logger.warn({
|
|
343
|
+
err,
|
|
344
|
+
filename
|
|
345
|
+
}, "error streaming local tarball @{filename}: @{err.message}");
|
|
346
|
+
}
|
|
300
347
|
});
|
|
301
348
|
localStream.on("error", (err) => {
|
|
302
349
|
if (err.code === require_storage_utils.STORAGE.NO_SUCH_FILE_ERROR || err.code === _verdaccio_core.HTTP_STATUS.NOT_FOUND) this.getTarballFromUpstream(name, filename, { signal }).then((uplinkStream) => {
|
|
@@ -628,18 +675,45 @@ var Storage = class {
|
|
|
628
675
|
return newData;
|
|
629
676
|
});
|
|
630
677
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
678
|
+
/**
|
|
679
|
+
* Resolve the uplink to fetch a distfile url from, or null when the fetch
|
|
680
|
+
* must be refused.
|
|
681
|
+
*
|
|
682
|
+
* Off-uplink urls on a locally published package are not fetched: the
|
|
683
|
+
* client's `dist.tarball` is stored verbatim, and fetching it would be SSRF
|
|
684
|
+
* (and would attach uplink credentials when only one uplink is configured).
|
|
685
|
+
* Uplink-synced packages may still use an autogenerated proxy without
|
|
686
|
+
* credentials for CDN-hosted tarballs.
|
|
687
|
+
*/
|
|
688
|
+
getUpLinkForDistFile(pkgName, filename, distFile, origin) {
|
|
636
689
|
const candidates = [];
|
|
637
690
|
for (const uplinkName in this.uplinks) if ((0, _verdaccio_config.hasProxyTo)(pkgName, uplinkName, this.config.packages)) candidates.push(this.uplinks[uplinkName]);
|
|
638
691
|
let uplink = null;
|
|
639
|
-
|
|
640
|
-
|
|
692
|
+
if (distFile.registry && this.uplinks[distFile.registry]) {
|
|
693
|
+
const recorded = this.uplinks[distFile.registry];
|
|
694
|
+
if (require_storage_utils.uplinkServesUrl(recorded.url, distFile.url)) {
|
|
695
|
+
debug$1("tarball is served by the recorded uplink %o", distFile.registry);
|
|
696
|
+
uplink = recorded;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
if (uplink === null) {
|
|
700
|
+
for (const candidate of candidates) if (require_storage_utils.uplinkServesUrl(candidate.url, distFile.url)) uplink = candidate;
|
|
701
|
+
}
|
|
641
702
|
if (uplink === null) {
|
|
642
|
-
|
|
703
|
+
if (!Boolean(origin?._distfiles?.[filename])) {
|
|
704
|
+
debug$1("refusing off-uplink tarball fetch for locally published %o (%o)", pkgName, distFile.url);
|
|
705
|
+
this.logger.warn({
|
|
706
|
+
name: pkgName,
|
|
707
|
+
filename,
|
|
708
|
+
url: distFile.url
|
|
709
|
+
}, "refused off-uplink tarball fetch for @{name} (@{url})");
|
|
710
|
+
return null;
|
|
711
|
+
}
|
|
712
|
+
debug$1("upstream not found, creating one for %o without uplink credentials", pkgName);
|
|
713
|
+
this.logger.http({
|
|
714
|
+
name: pkgName,
|
|
715
|
+
url: distFile.url
|
|
716
|
+
}, "serving off-uplink tarball via autogenerated proxy for @{name} (@{url})");
|
|
643
717
|
uplink = new _verdaccio_proxy.ProxyStorage(`verdaccio-${pkgName}`, {
|
|
644
718
|
url: distFile.url,
|
|
645
719
|
cache: true
|
|
@@ -887,10 +961,24 @@ var Storage = class {
|
|
|
887
961
|
});
|
|
888
962
|
else {
|
|
889
963
|
const localStorageWriteStream = await storage.writeTarball(filename, { signal });
|
|
964
|
+
let uploadFailed = false;
|
|
890
965
|
localStorageWriteStream.on("open", async () => {
|
|
891
|
-
|
|
966
|
+
try {
|
|
967
|
+
await (0, node_stream_promises.pipeline)(uploadStream, transformHash, localStorageWriteStream, { signal });
|
|
968
|
+
} catch (err) {
|
|
969
|
+
uploadFailed = true;
|
|
970
|
+
this.logger.warn({
|
|
971
|
+
err,
|
|
972
|
+
filename,
|
|
973
|
+
pkgName
|
|
974
|
+
}, "error uploading tarball @{filename} for @{pkgName}: @{err.message}");
|
|
975
|
+
}
|
|
892
976
|
});
|
|
893
977
|
localStorageWriteStream.on("close", async () => {
|
|
978
|
+
if (uploadFailed) {
|
|
979
|
+
debug$1("skip metadata update for failed upload %o for %o", filename, pkgName);
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
894
982
|
try {
|
|
895
983
|
debug$1("uploaded tarball %o for %o", filename, pkgName);
|
|
896
984
|
await this.updatePackage(pkgName, async (data) => {
|
|
@@ -907,6 +995,7 @@ var Storage = class {
|
|
|
907
995
|
}
|
|
908
996
|
});
|
|
909
997
|
localStorageWriteStream.on("error", async (err) => {
|
|
998
|
+
uploadFailed = true;
|
|
910
999
|
uploadStream.emit("error", err);
|
|
911
1000
|
});
|
|
912
1001
|
}
|
|
@@ -1152,6 +1241,15 @@ var Storage = class {
|
|
|
1152
1241
|
break;
|
|
1153
1242
|
}
|
|
1154
1243
|
} catch (err) {
|
|
1244
|
+
const uplinkName = uplink;
|
|
1245
|
+
const upLinkMeta = localManifest?._uplinks?.[uplinkName];
|
|
1246
|
+
const etag = upLinkMeta?.etag;
|
|
1247
|
+
if (err.code === _verdaccio_core.HTTP_STATUS.NOT_MODIFIED && localManifest !== null && _verdaccio_core.validationUtils.isObject(upLinkMeta) && typeof etag === "string") {
|
|
1248
|
+
syncManifest = require_storage_utils.updateUpLinkMetadata(uplinkName, localManifest, etag);
|
|
1249
|
+
localManifest = syncManifest;
|
|
1250
|
+
found = true;
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1155
1253
|
debug$1("error captured on uplink %o", err.message);
|
|
1156
1254
|
uplinksErrors.push(err);
|
|
1157
1255
|
continue;
|