@verdaccio/store 9.0.0-next-9.31 → 9.0.0-next-9.32
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 +102 -14
- package/build/storage.js.map +1 -1
- package/build/storage.mjs +105 -17
- 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,6 +159,41 @@ 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,
|
|
@@ -174,7 +209,7 @@ var Storage = class {
|
|
|
174
209
|
const cachedDistFile = cachedManifest !== null ? require_storage_utils.lookupDistFile(cachedManifest, filename) : null;
|
|
175
210
|
if (cachedDistFile !== null && typeof cachedDistFile.url === "string") {
|
|
176
211
|
debug$1("dist file found, using it %o", cachedDistFile.url);
|
|
177
|
-
return this.fetchTarballFromDistFile(name, filename, cachedDistFile, { signal });
|
|
212
|
+
return this.fetchTarballFromDistFile(name, filename, cachedDistFile, cachedManifest, { signal });
|
|
178
213
|
} else {
|
|
179
214
|
debug$1("dist file not found, proceed update upstream");
|
|
180
215
|
const [updatedManifest] = await this.syncUplinksMetadata(name, cachedManifest, { uplinksLook: true });
|
|
@@ -183,15 +218,19 @@ var Storage = class {
|
|
|
183
218
|
debug$1("remote tarball not found");
|
|
184
219
|
throw _verdaccio_core.errorUtils.getNotFound(_verdaccio_core.API_ERROR.NO_SUCH_FILE);
|
|
185
220
|
}
|
|
186
|
-
return this.fetchTarballFromDistFile(name, filename, distFile, { signal });
|
|
221
|
+
return this.fetchTarballFromDistFile(name, filename, distFile, updatedManifest, { signal });
|
|
187
222
|
}
|
|
188
223
|
}
|
|
189
|
-
fetchTarballFromDistFile(name, filename, distFile, { signal }) {
|
|
224
|
+
fetchTarballFromDistFile(name, filename, distFile, origin, { signal }) {
|
|
190
225
|
let current_length = 0;
|
|
191
226
|
let expected_length;
|
|
192
227
|
let uplinkStatusError = null;
|
|
193
228
|
const passThroughRemoteStream = new node_stream.PassThrough();
|
|
194
|
-
const proxy = this.getUpLinkForDistFile(name, distFile);
|
|
229
|
+
const proxy = this.getUpLinkForDistFile(name, filename, distFile, origin);
|
|
230
|
+
if (proxy === null) {
|
|
231
|
+
setImmediate(() => passThroughRemoteStream.emit("error", _verdaccio_core.errorUtils.getNotFound(_verdaccio_core.API_ERROR.NO_SUCH_FILE)));
|
|
232
|
+
return passThroughRemoteStream;
|
|
233
|
+
}
|
|
195
234
|
const remoteStream = proxy.fetchTarball(distFile.url, { throwHttpErrors: false });
|
|
196
235
|
const readRemoteBody = () => new Promise((resolve) => {
|
|
197
236
|
const chunks = [];
|
|
@@ -296,7 +335,14 @@ var Storage = class {
|
|
|
296
335
|
const localStream = await this.getLocalTarball(name, filename, { signal });
|
|
297
336
|
forwardContentLength(localStream);
|
|
298
337
|
localStream.on("open", async () => {
|
|
299
|
-
|
|
338
|
+
try {
|
|
339
|
+
await (0, node_stream_promises.pipeline)(localStream, localTarballStream, { signal });
|
|
340
|
+
} catch (err) {
|
|
341
|
+
this.logger.warn({
|
|
342
|
+
err,
|
|
343
|
+
filename
|
|
344
|
+
}, "error streaming local tarball @{filename}: @{err.message}");
|
|
345
|
+
}
|
|
300
346
|
});
|
|
301
347
|
localStream.on("error", (err) => {
|
|
302
348
|
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 +674,45 @@ var Storage = class {
|
|
|
628
674
|
return newData;
|
|
629
675
|
});
|
|
630
676
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
677
|
+
/**
|
|
678
|
+
* Resolve the uplink to fetch a distfile url from, or null when the fetch
|
|
679
|
+
* must be refused.
|
|
680
|
+
*
|
|
681
|
+
* Off-uplink urls on a locally published package are not fetched: the
|
|
682
|
+
* client's `dist.tarball` is stored verbatim, and fetching it would be SSRF
|
|
683
|
+
* (and would attach uplink credentials when only one uplink is configured).
|
|
684
|
+
* Uplink-synced packages may still use an autogenerated proxy without
|
|
685
|
+
* credentials for CDN-hosted tarballs.
|
|
686
|
+
*/
|
|
687
|
+
getUpLinkForDistFile(pkgName, filename, distFile, origin) {
|
|
636
688
|
const candidates = [];
|
|
637
689
|
for (const uplinkName in this.uplinks) if ((0, _verdaccio_config.hasProxyTo)(pkgName, uplinkName, this.config.packages)) candidates.push(this.uplinks[uplinkName]);
|
|
638
690
|
let uplink = null;
|
|
639
|
-
|
|
640
|
-
|
|
691
|
+
if (distFile.registry && this.uplinks[distFile.registry]) {
|
|
692
|
+
const recorded = this.uplinks[distFile.registry];
|
|
693
|
+
if (require_storage_utils.uplinkServesUrl(recorded.url, distFile.url)) {
|
|
694
|
+
debug$1("tarball is served by the recorded uplink %o", distFile.registry);
|
|
695
|
+
uplink = recorded;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
if (uplink === null) {
|
|
699
|
+
for (const candidate of candidates) if (require_storage_utils.uplinkServesUrl(candidate.url, distFile.url)) uplink = candidate;
|
|
700
|
+
}
|
|
641
701
|
if (uplink === null) {
|
|
642
|
-
|
|
702
|
+
if (!Boolean(origin?._distfiles?.[filename])) {
|
|
703
|
+
debug$1("refusing off-uplink tarball fetch for locally published %o (%o)", pkgName, distFile.url);
|
|
704
|
+
this.logger.warn({
|
|
705
|
+
name: pkgName,
|
|
706
|
+
filename,
|
|
707
|
+
url: distFile.url
|
|
708
|
+
}, "refused off-uplink tarball fetch for @{name} (@{url})");
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
debug$1("upstream not found, creating one for %o without uplink credentials", pkgName);
|
|
712
|
+
this.logger.http({
|
|
713
|
+
name: pkgName,
|
|
714
|
+
url: distFile.url
|
|
715
|
+
}, "serving off-uplink tarball via autogenerated proxy for @{name} (@{url})");
|
|
643
716
|
uplink = new _verdaccio_proxy.ProxyStorage(`verdaccio-${pkgName}`, {
|
|
644
717
|
url: distFile.url,
|
|
645
718
|
cache: true
|
|
@@ -887,10 +960,24 @@ var Storage = class {
|
|
|
887
960
|
});
|
|
888
961
|
else {
|
|
889
962
|
const localStorageWriteStream = await storage.writeTarball(filename, { signal });
|
|
963
|
+
let uploadFailed = false;
|
|
890
964
|
localStorageWriteStream.on("open", async () => {
|
|
891
|
-
|
|
965
|
+
try {
|
|
966
|
+
await (0, node_stream_promises.pipeline)(uploadStream, transformHash, localStorageWriteStream, { signal });
|
|
967
|
+
} catch (err) {
|
|
968
|
+
uploadFailed = true;
|
|
969
|
+
this.logger.warn({
|
|
970
|
+
err,
|
|
971
|
+
filename,
|
|
972
|
+
pkgName
|
|
973
|
+
}, "error uploading tarball @{filename} for @{pkgName}: @{err.message}");
|
|
974
|
+
}
|
|
892
975
|
});
|
|
893
976
|
localStorageWriteStream.on("close", async () => {
|
|
977
|
+
if (uploadFailed) {
|
|
978
|
+
debug$1("skip metadata update for failed upload %o for %o", filename, pkgName);
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
894
981
|
try {
|
|
895
982
|
debug$1("uploaded tarball %o for %o", filename, pkgName);
|
|
896
983
|
await this.updatePackage(pkgName, async (data) => {
|
|
@@ -907,6 +994,7 @@ var Storage = class {
|
|
|
907
994
|
}
|
|
908
995
|
});
|
|
909
996
|
localStorageWriteStream.on("error", async (err) => {
|
|
997
|
+
uploadFailed = true;
|
|
910
998
|
uploadStream.emit("error", err);
|
|
911
999
|
});
|
|
912
1000
|
}
|