@verdaccio/store 6.0.0-6-next.21 → 6.0.0-6-next.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/build/index.d.ts +5 -4
  3. package/build/index.js +31 -15
  4. package/build/index.js.map +1 -1
  5. package/build/lib/TransFormResults.d.ts +15 -0
  6. package/build/lib/TransFormResults.js +61 -0
  7. package/build/lib/TransFormResults.js.map +1 -0
  8. package/build/lib/search-utils.d.ts +4 -0
  9. package/build/lib/search-utils.js +59 -0
  10. package/build/lib/search-utils.js.map +1 -0
  11. package/build/lib/star-utils.d.ts +14 -0
  12. package/build/{star-utils.js → lib/star-utils.js} +16 -2
  13. package/build/lib/star-utils.js.map +1 -0
  14. package/build/lib/storage-utils.d.ts +82 -0
  15. package/build/{storage-utils.js → lib/storage-utils.js} +173 -60
  16. package/build/lib/storage-utils.js.map +1 -0
  17. package/build/lib/uplink-util.d.ts +10 -0
  18. package/build/lib/uplink-util.js +49 -0
  19. package/build/lib/uplink-util.js.map +1 -0
  20. package/build/lib/versions-utils.d.ts +28 -0
  21. package/build/lib/versions-utils.js +104 -0
  22. package/build/lib/versions-utils.js.map +1 -0
  23. package/build/local-storage.d.ts +3 -165
  24. package/build/local-storage.js +6 -1166
  25. package/build/local-storage.js.map +1 -1
  26. package/build/storage.d.ts +242 -86
  27. package/build/storage.js +1681 -548
  28. package/build/storage.js.map +1 -1
  29. package/build/type.d.ts +42 -19
  30. package/build/type.js.map +1 -1
  31. package/jest.config.js +8 -2
  32. package/package.json +71 -71
  33. package/src/index.ts +5 -4
  34. package/src/lib/TransFormResults.ts +42 -0
  35. package/src/lib/search-utils.ts +50 -0
  36. package/src/{star-utils.ts → lib/star-utils.ts} +16 -5
  37. package/src/lib/storage-utils.ts +362 -0
  38. package/src/lib/uplink-util.ts +41 -0
  39. package/src/lib/versions-utils.ts +87 -0
  40. package/src/local-storage.ts +7 -1217
  41. package/src/storage.ts +1683 -635
  42. package/src/type.ts +47 -21
  43. package/test/fixtures/config/getTarballNext-getupstream.yaml +17 -0
  44. package/test/fixtures/config/syncDoubleUplinksMetadata.yaml +25 -0
  45. package/test/fixtures/config/syncNoUplinksMetadata.yaml +17 -0
  46. package/test/fixtures/config/syncSingleUplinksMetadata.yaml +21 -0
  47. package/test/fixtures/config/updateManifest-1.yaml +16 -0
  48. package/test/fixtures/manifests/foo-npmjs.json +253 -0
  49. package/test/fixtures/manifests/foo-verdaccio.json +253 -0
  50. package/test/fixtures/tarball.tgz +0 -0
  51. package/test/helpers.ts +22 -0
  52. package/test/local-store.__disabled__.ts +553 -0
  53. package/test/search.spec.ts +4 -5
  54. package/test/star.spec.ts +31 -0
  55. package/test/storage-utils.spec.ts +129 -42
  56. package/test/storage.spec.ts +943 -33
  57. package/test/versions.spec.ts +109 -0
  58. package/tsconfig.json +6 -3
  59. package/build/search.d.ts +0 -35
  60. package/build/search.js +0 -198
  61. package/build/search.js.map +0 -1
  62. package/build/star-utils.d.ts +0 -9
  63. package/build/star-utils.js.map +0 -1
  64. package/build/storage-utils.d.ts +0 -39
  65. package/build/storage-utils.js.map +0 -1
  66. package/build/uplink-util.d.ts +0 -7
  67. package/build/uplink-util.js +0 -38
  68. package/build/uplink-util.js.map +0 -1
  69. package/src/search.ts +0 -175
  70. package/src/storage-utils.ts +0 -263
  71. package/src/uplink-util.ts +0 -32
  72. package/test/local-storage.spec.ts +0 -583
package/package.json CHANGED
@@ -1,72 +1,72 @@
1
1
  {
2
- "name": "@verdaccio/store",
3
- "version": "6.0.0-6-next.21",
4
- "description": "loaders logic",
5
- "main": "./build/index.js",
6
- "types": "build/index.d.ts",
7
- "author": {
8
- "name": "Juan Picado",
9
- "email": "juanpicado19@gmail.com"
10
- },
11
- "repository": {
12
- "type": "https",
13
- "url": "https://github.com/verdaccio/verdaccio"
14
- },
15
- "license": "MIT",
16
- "homepage": "https://verdaccio.org",
17
- "keywords": [
18
- "private",
19
- "package",
20
- "repository",
21
- "registry",
22
- "enterprise",
23
- "modules",
24
- "proxy",
25
- "server",
26
- "verdaccio"
27
- ],
28
- "engines": {
29
- "node": ">=14",
30
- "npm": ">=6"
31
- },
32
- "dependencies": {
33
- "@verdaccio/config": "6.0.0-6-next.13",
34
- "@verdaccio/core": "6.0.0-6-next.5",
35
- "@verdaccio/loaders": "6.0.0-6-next.12",
36
- "@verdaccio/local-storage": "11.0.0-6-next.12",
37
- "@verdaccio/logger": "6.0.0-6-next.11",
38
- "@verdaccio/proxy": "6.0.0-6-next.19",
39
- "@verdaccio/streams": "11.0.0-6-next.5",
40
- "@verdaccio/utils": "6.0.0-6-next.11",
41
- "@verdaccio/tarball": "11.0.0-6-next.12",
42
- "JSONStream": "1.3.5",
43
- "async": "3.2.3",
44
- "debug": "4.3.3",
45
- "lodash": "4.17.21",
46
- "merge2": "1.4.1",
47
- "semver": "7.3.5"
48
- },
49
- "devDependencies": {
50
- "@types/node": "16.11.21",
51
- "@verdaccio/mock": "6.0.0-6-next.14",
52
- "@verdaccio/types": "11.0.0-6-next.11",
53
- "@verdaccio/test-helper": "1.1.0-6-next.0",
54
- "undici": "4.15.0",
55
- "nock": "13.2.2",
56
- "tmp-promise": "3.0.3",
57
- "node-mocks-http": "1.11.0"
58
- },
59
- "funding": {
60
- "type": "opencollective",
61
- "url": "https://opencollective.com/verdaccio"
62
- },
63
- "scripts": {
64
- "clean": "rimraf ./build",
65
- "test": "cross-env NODE_ENV=test BABEL_ENV=test jest",
66
- "type-check": "tsc --noEmit -p tsconfig.build.json",
67
- "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
68
- "build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
69
- "watch": "pnpm build:js -- --watch",
70
- "build": "pnpm run build:js && pnpm run build:types"
71
- }
72
- }
2
+ "name": "@verdaccio/store",
3
+ "version": "6.0.0-6-next.24",
4
+ "description": "loaders logic",
5
+ "main": "./build/index.js",
6
+ "types": "build/index.d.ts",
7
+ "author": {
8
+ "name": "Juan Picado",
9
+ "email": "juanpicado19@gmail.com"
10
+ },
11
+ "repository": {
12
+ "type": "https",
13
+ "url": "https://github.com/verdaccio/verdaccio"
14
+ },
15
+ "license": "MIT",
16
+ "homepage": "https://verdaccio.org",
17
+ "keywords": [
18
+ "private",
19
+ "package",
20
+ "repository",
21
+ "registry",
22
+ "enterprise",
23
+ "modules",
24
+ "proxy",
25
+ "server",
26
+ "verdaccio"
27
+ ],
28
+ "engines": {
29
+ "node": ">=16",
30
+ "npm": ">=6"
31
+ },
32
+ "dependencies": {
33
+ "@verdaccio/config": "6.0.0-6-next.15",
34
+ "@verdaccio/core": "6.0.0-6-next.6",
35
+ "@verdaccio/hooks": "6.0.0-6-next.14",
36
+ "@verdaccio/loaders": "6.0.0-6-next.13",
37
+ "@verdaccio/local-storage": "11.0.0-6-next.14",
38
+ "@verdaccio/logger": "6.0.0-6-next.12",
39
+ "@verdaccio/proxy": "6.0.0-6-next.22",
40
+ "@verdaccio/url": "11.0.0-6-next.10",
41
+ "@verdaccio/utils": "6.0.0-6-next.12",
42
+ "@verdaccio/tarball": "11.0.0-6-next.13",
43
+ "JSONStream": "1.3.5",
44
+ "debug": "4.3.4",
45
+ "lodash": "4.17.21",
46
+ "merge2": "1.4.1",
47
+ "semver": "7.3.7"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "16.11.51",
51
+ "@verdaccio/types": "11.0.0-6-next.14",
52
+ "@verdaccio/test-helper": "1.1.0-6-next.2",
53
+ "undici": "4.16.0",
54
+ "nock": "13.2.9",
55
+ "node-mocks-http": "1.11.0",
56
+ "mockdate": "3.0.5"
57
+ },
58
+ "funding": {
59
+ "type": "opencollective",
60
+ "url": "https://opencollective.com/verdaccio"
61
+ },
62
+ "scripts": {
63
+ "clean": "rimraf ./build",
64
+ "test": "jest",
65
+ "type-check": "tsc --noEmit -p tsconfig.build.json",
66
+ "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
67
+ "build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
68
+ "watch": "pnpm build:js -- --watch",
69
+ "build": "pnpm run build:js && pnpm run build:types"
70
+ },
71
+ "readme": "# @verdaccio/store\n\n[![backers](https://opencollective.com/verdaccio/tiers/backer/badge.svg?label=Backer&color=brightgreen)](https://opencollective.com/verdaccio)\n[![stackshare](https://img.shields.io/badge/Follow%20on-StackShare-blue.svg?logo=stackshare&style=flat)](https://stackshare.io/verdaccio)\n[![MIT](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/verdaccio/verdaccio/blob/master/LICENSE)\n[![Crowdin](https://d322cqt584bo4o.cloudfront.net/verdaccio/localized.svg)](https://crowdin.com/project/verdaccio)\n[![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/verdaccio/verdaccio)](https://www.tickgit.com/browse?repo=github.com/verdaccio/verdaccio)\n\n[![Twitter followers](https://img.shields.io/twitter/follow/verdaccio_npm.svg?style=social&label=Follow)](https://twitter.com/verdaccio_npm)\n[![Github](https://img.shields.io/github/stars/verdaccio/verdaccio.svg?style=social&label=Stars)](https://github.com/verdaccio/verdaccio/stargazers)\n\n## Donations\n\nVerdaccio is run by **volunteers**; nobody is working full-time on it. If you find this project to be useful and would like to support its development, consider making a donation - **your logo might end up in this readme.** 😉\n\n**[Donate](https://opencollective.com/verdaccio)** 💵👍🏻 starting from _\\$1/month_ or just one single contribution.\n\n## Report a vulnerability\n\nIf you want to report a security vulnerability, please follow the steps which we have defined for you in our [security policy](https://github.com/verdaccio/verdaccio/security/policy).\n\n## Open Collective Sponsors\n\nSupport this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/verdaccio#sponsor)]\n\n[![sponsor](https://opencollective.com/verdaccio/sponsor/0/avatar.svg)](https://opencollective.com/verdaccio/sponsor/0/website)\n[![sponsor](https://opencollective.com/verdaccio/sponsor/1/avatar.svg)](https://opencollective.com/verdaccio/sponsor/1/website)\n[![sponsor](https://opencollective.com/verdaccio/sponsor/2/avatar.svg)](https://opencollective.com/verdaccio/sponsor/2/website)\n[![sponsor](https://opencollective.com/verdaccio/sponsor/3/avatar.svg)](https://opencollective.com/verdaccio/sponsor/3/website)\n[![sponsor](https://opencollective.com/verdaccio/sponsor/4/avatar.svg)](https://opencollective.com/verdaccio/sponsor/4/website)\n[![sponsor](https://opencollective.com/verdaccio/sponsor/5/avatar.svg)](https://opencollective.com/verdaccio/sponsor/5/website)\n[![sponsor](https://opencollective.com/verdaccio/sponsor/6/avatar.svg)](https://opencollective.com/verdaccio/sponsor/6/website)\n[![sponsor](https://opencollective.com/verdaccio/sponsor/7/avatar.svg)](https://opencollective.com/verdaccio/sponsor/7/website)\n[![sponsor](https://opencollective.com/verdaccio/sponsor/8/avatar.svg)](https://opencollective.com/verdaccio/sponsor/8/website)\n[![sponsor](https://opencollective.com/verdaccio/sponsor/9/avatar.svg)](https://opencollective.com/verdaccio/sponsor/9/website)\n\n## Open Collective Backers\n\nThank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/verdaccio#backer)]\n\n[![backers](https://opencollective.com/verdaccio/backers.svg?width=890)](https://opencollective.com/verdaccio#backers)\n\n## Special Thanks\n\nThanks to the following companies to help us to achieve our goals providing free open source licenses.\n\n[![jetbrain](assets/thanks/jetbrains/logo.png)](https://www.jetbrains.com/)\n[![crowdin](assets/thanks/crowdin/logo.png)](https://crowdin.com/)\n[![balsamiq](assets/thanks/balsamiq/logo.jpg)](https://balsamiq.com/)\n\n## Contributors\n\nThis project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].\n\n[![contributors](https://opencollective.com/verdaccio/contributors.svg?width=890&button=true)](../../graphs/contributors)\n\n### FAQ / Contact / Troubleshoot\n\nIf you have any issue you can try the following options, do no desist to ask or check our issues database, perhaps someone has asked already what you are looking for.\n\n- [Blog](https://verdaccio.org/blog/)\n- [Donations](https://opencollective.com/verdaccio)\n- [Reporting an issue](https://github.com/verdaccio/verdaccio/blob/master/CONTRIBUTING.md#reporting-a-bug)\n- [Running discussions](https://github.com/verdaccio/verdaccio/issues?q=is%3Aissue+is%3Aopen+label%3Adiscuss)\n- [Chat](http://chat.verdaccio.org/)\n- [Logos](https://verdaccio.org/docs/en/logo)\n- [Docker Examples](https://github.com/verdaccio/docker-examples)\n- [FAQ](https://github.com/verdaccio/verdaccio/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Aquestion%20)\n\n### License\n\nVerdaccio is [MIT licensed](https://github.com/verdaccio/verdaccio/blob/master/LICENSE)\n\nThe Verdaccio documentation and logos (excluding /thanks, e.g., .md, .png, .sketch) files within the /assets folder) is\n[Creative Commons licensed](https://github.com/verdaccio/verdaccio/blob/master/LICENSE-docs).\n"
72
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
- export * from './storage';
2
- export * from './storage-utils';
3
- export * from './star-utils';
4
- export * from './search';
1
+ export { Storage } from './storage';
2
+ export * from './lib/storage-utils';
3
+ export * from './lib/search-utils';
4
+ export * from './lib/versions-utils';
5
+ export * from './lib/star-utils';
5
6
  export * from './type';
@@ -0,0 +1,42 @@
1
+ import buildDebug from 'debug';
2
+ import _ from 'lodash';
3
+ import { Transform } from 'stream';
4
+
5
+ import { searchUtils } from '@verdaccio/core';
6
+
7
+ const debug = buildDebug('verdaccio:storage:search:transform');
8
+
9
+ export class TransFormResults extends Transform {
10
+ public constructor(options) {
11
+ super(options);
12
+ }
13
+
14
+ /**
15
+ * Transform either array of packages or a single package into a stream of packages.
16
+ * From uplinks the chunks are array but from local packages are objects.
17
+ * @param {string} chunk
18
+ * @param {string} encoding
19
+ * @param {function} done
20
+ * @returns {void}
21
+ * @override
22
+ */
23
+ public _transform(chunk, _encoding, callback) {
24
+ if (_.isArray(chunk)) {
25
+ // from remotes we should expect chunks as arrays
26
+ (chunk as searchUtils.SearchItem[])
27
+ .filter((pkgItem) => {
28
+ debug(`streaming remote pkg name ${pkgItem?.package?.name}`);
29
+ return true;
30
+ })
31
+ .forEach((pkgItem) => {
32
+ this.push({ ...pkgItem, verdaccioPkgCached: false, verdaccioPrivate: false });
33
+ });
34
+ return callback();
35
+ } else {
36
+ // local we expect objects
37
+ debug(`streaming local pkg name ${chunk?.package?.name}`);
38
+ this.push(chunk);
39
+ return callback();
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,50 @@
1
+ import { orderBy } from 'lodash';
2
+
3
+ import { pkgUtils, searchUtils } from '@verdaccio/core';
4
+ import { Manifest, Version } from '@verdaccio/types';
5
+
6
+ export function removeDuplicates(results: searchUtils.SearchPackageItem[]) {
7
+ const pkgNames: any[] = [];
8
+ const orderByResults = orderBy(results, ['verdaccioPrivate', 'asc']);
9
+ return orderByResults.filter((pkg) => {
10
+ if (pkgNames.includes(pkg?.package?.name)) {
11
+ return false;
12
+ }
13
+ pkgNames.push(pkg?.package?.name);
14
+ return true;
15
+ });
16
+ }
17
+
18
+ export function mapManifestToSearchPackageBody(
19
+ pkg: Manifest,
20
+ searchItem: searchUtils.SearchItem
21
+ ): searchUtils.SearchPackageBody {
22
+ const latest = pkgUtils.getLatest(pkg);
23
+ const version: Version = pkg.versions[latest];
24
+ const result: searchUtils.SearchPackageBody = {
25
+ name: version.name,
26
+ scope: '',
27
+ description: version.description,
28
+ version: latest,
29
+ keywords: version.keywords,
30
+ date: pkg.time[latest],
31
+ // FIXME: type
32
+ author: version.author as any,
33
+ // FIXME: not possible fill this out from a private package
34
+ publisher: {},
35
+ // FIXME: type
36
+ maintainers: version.maintainers as any,
37
+ links: {
38
+ npm: '',
39
+ homepage: version.homepage,
40
+ repository: version.repository,
41
+ bugs: version.bugs,
42
+ },
43
+ };
44
+
45
+ if (typeof searchItem.package.scoped === 'string') {
46
+ result.scope = searchItem.package.scoped;
47
+ }
48
+
49
+ return result;
50
+ }
@@ -1,21 +1,28 @@
1
1
  import _ from 'lodash';
2
2
 
3
- import { Package } from '@verdaccio/types';
3
+ import { validatioUtils } from '@verdaccio/core';
4
+ import { Manifest } from '@verdaccio/types';
4
5
 
5
- import { Users } from '.';
6
+ import { Users } from '../type';
6
7
 
7
8
  /**
8
9
  * Check whether the package metadta has enough data to be published
9
10
  * @param pkg metadata
10
11
  */
11
12
 
12
- export function isPublishablePackage(pkg: Package): boolean {
13
+ /**
14
+ * Check whether the package metadta has enough data to be published
15
+ * @param pkg metadata
16
+ */
17
+ export function isPublishablePackage(pkg: Manifest): boolean {
18
+ // TODO: we can do better, no need get keys
13
19
  const keys: string[] = Object.keys(pkg);
14
20
 
15
- return _.includes(keys, 'versions');
21
+ return keys.includes('versions');
16
22
  }
17
23
 
18
- export function isRelatedToDeprecation(pkgInfo: Package): boolean {
24
+ // @deprecated don't think this is used anymore (REMOVE)
25
+ export function isRelatedToDeprecation(pkgInfo: Manifest): boolean {
19
26
  const { versions } = pkgInfo;
20
27
  for (const version in versions) {
21
28
  if (Object.prototype.hasOwnProperty.call(versions[version], 'deprecated')) {
@@ -36,3 +43,7 @@ export function validateInputs(localUsers: Users, username: string, isStar: bool
36
43
  }
37
44
  return false;
38
45
  }
46
+
47
+ export function isStarManifest(manifest: Manifest): boolean {
48
+ return isPublishablePackage(manifest) === false && validatioUtils.isObject(manifest.users);
49
+ }
@@ -0,0 +1,362 @@
1
+ import _ from 'lodash';
2
+ import semver from 'semver';
3
+
4
+ import { errorUtils, pkgUtils, validatioUtils } from '@verdaccio/core';
5
+ import { API_ERROR, DIST_TAGS, HTTP_STATUS, USERS } from '@verdaccio/core';
6
+ import { AttachMents, Manifest, Version, Versions } from '@verdaccio/types';
7
+ import { generateRandomHexString, isNil, isObject } from '@verdaccio/utils';
8
+
9
+ import { sortVersionsAndFilterInvalid } from './versions-utils';
10
+
11
+ export const STORAGE = {
12
+ PACKAGE_FILE_NAME: 'package.json',
13
+ FILE_EXIST_ERROR: 'EEXISTS',
14
+ NO_SUCH_FILE_ERROR: 'ENOENT',
15
+ DEFAULT_REVISION: '0-0000000000000000',
16
+ };
17
+
18
+ /**
19
+ * Create a new package in the storage, return a boilerplate package
20
+ * @param name package name
21
+ * @returns {Manifest}
22
+ */
23
+ export function generatePackageTemplate(name: string): Manifest {
24
+ return {
25
+ // standard things
26
+ name,
27
+ versions: {},
28
+ time: {},
29
+ [USERS]: {},
30
+ [DIST_TAGS]: {},
31
+ _uplinks: {},
32
+ _distfiles: {},
33
+ _attachments: {},
34
+ _rev: '',
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Normalize package properties, tags, revision id.
40
+ * @param {Object} pkg package reference.
41
+ */
42
+ export function normalizePackage(pkg: Manifest): Manifest {
43
+ const pkgProperties = ['versions', 'dist-tags', '_distfiles', '_attachments', '_uplinks', 'time'];
44
+
45
+ pkgProperties.forEach((key): void => {
46
+ const pkgProp = pkg[key];
47
+
48
+ if (isNil(pkgProp) || validatioUtils.isObject(pkgProp) === false) {
49
+ pkg[key] = {};
50
+ }
51
+ });
52
+
53
+ if (typeof pkg?._rev !== 'string') {
54
+ pkg._rev = STORAGE.DEFAULT_REVISION;
55
+ }
56
+
57
+ if (typeof pkg?._id !== 'string') {
58
+ pkg._id = pkg.name;
59
+ }
60
+
61
+ // normalize dist-tags
62
+ return normalizeDistTags(pkg);
63
+ }
64
+
65
+ export function generateRevision(rev: string): string {
66
+ const _rev = rev.split('-');
67
+
68
+ return (+_rev[0] || 0) + 1 + '-' + generateRandomHexString();
69
+ }
70
+
71
+ export function getLatestReadme(pkg: Manifest): string {
72
+ const versions = pkg['versions'] || {};
73
+ const distTags = pkg[DIST_TAGS] || {};
74
+ // FIXME: here is a bit tricky add the types
75
+ const latestVersion: Version | any = distTags['latest'] ? versions[distTags['latest']] || {} : {};
76
+ let readme = _.trim(pkg.readme || latestVersion.readme || '');
77
+ if (readme) {
78
+ return readme;
79
+ }
80
+
81
+ // In case of empty readme - trying to get ANY readme in the following order:
82
+ // 'next','beta','alpha','test','dev','canary'
83
+ const readmeDistTagsPriority = ['next', 'beta', 'alpha', 'test', 'dev', 'canary'];
84
+ readmeDistTagsPriority.forEach(function (tag): string | void {
85
+ if (readme) {
86
+ return readme;
87
+ }
88
+ const version: Version | any = distTags[tag] ? versions[distTags[tag]] || {} : {};
89
+ readme = _.trim(version.readme || readme);
90
+ });
91
+ return readme;
92
+ }
93
+
94
+ // FIXME: type any due this
95
+ export function cleanUpReadme(version: any): Version {
96
+ if (isNil(version) === false) {
97
+ delete version.readme;
98
+ }
99
+
100
+ return version;
101
+ }
102
+
103
+ export const WHITELIST = [
104
+ '_rev',
105
+ 'name',
106
+ 'versions',
107
+ 'dist-tags',
108
+ 'readme',
109
+ 'time',
110
+ '_id',
111
+ 'users',
112
+ ];
113
+
114
+ export function cleanUpLinksRef(result: Manifest, keepUpLinkData?: boolean): Manifest {
115
+ const propertyToKeep = [...WHITELIST];
116
+ if (keepUpLinkData === true) {
117
+ propertyToKeep.push('_uplinks');
118
+ }
119
+
120
+ for (const i in result) {
121
+ if (propertyToKeep.indexOf(i) === -1) {
122
+ // Remove sections like '_uplinks' from response
123
+ delete result[i];
124
+ }
125
+ }
126
+
127
+ return result;
128
+ }
129
+
130
+ // TODO: move to abstract storage
131
+ // @deprecated use abstract.storage.ts:checkPackageRemote
132
+ export function checkPackageRemote(
133
+ name: string,
134
+ isAllowPublishOffline: boolean,
135
+ syncMetadata: Function
136
+ ): Promise<any> {
137
+ return new Promise<void>((resolve, reject): void => {
138
+ syncMetadata(name, null, {}, (err, packageJsonLocal, upLinksErrors): void => {
139
+ // something weird
140
+ if (err && err.status !== HTTP_STATUS.NOT_FOUND) {
141
+ return reject(err);
142
+ }
143
+
144
+ // checking package exist already
145
+ if (isNil(packageJsonLocal) === false) {
146
+ return reject(errorUtils.getConflict(API_ERROR.PACKAGE_EXIST));
147
+ }
148
+
149
+ for (let errorItem = 0; errorItem < upLinksErrors.length; errorItem++) {
150
+ // checking error
151
+ // if uplink fails with a status other than 404, we report failure
152
+ if (isNil(upLinksErrors[errorItem][0]) === false) {
153
+ if (upLinksErrors[errorItem][0].status !== HTTP_STATUS.NOT_FOUND) {
154
+ if (isAllowPublishOffline) {
155
+ return resolve();
156
+ }
157
+
158
+ return reject(errorUtils.getServiceUnavailable(API_ERROR.UPLINK_OFFLINE_PUBLISH));
159
+ }
160
+ }
161
+ }
162
+
163
+ return resolve();
164
+ });
165
+ });
166
+ }
167
+
168
+ // @deprecated use export function mergeUplinkTimeIntoLocalNext
169
+ export function mergeUplinkTimeIntoLocal(localMetadata: Manifest, remoteMetadata: Manifest): any {
170
+ if ('time' in remoteMetadata) {
171
+ return Object.assign({}, localMetadata.time, remoteMetadata.time);
172
+ }
173
+
174
+ return localMetadata.time;
175
+ }
176
+
177
+ export function mergeUplinkTimeIntoLocalNext(
178
+ cacheManifest: Manifest,
179
+ remoteManifest: Manifest
180
+ ): Manifest {
181
+ if ('time' in remoteManifest) {
182
+ // remote override cache time conflicts
183
+ return { ...cacheManifest, time: { ...cacheManifest.time, ...remoteManifest.time } };
184
+ }
185
+
186
+ return cacheManifest;
187
+ }
188
+
189
+ export function updateUpLinkMetadata(uplinkId, manifest: Manifest, etag: string) {
190
+ const _uplinks = {
191
+ ...manifest._uplinks,
192
+ [uplinkId]: {
193
+ etag,
194
+ fetched: Date.now(),
195
+ },
196
+ };
197
+ return {
198
+ ...manifest,
199
+ _uplinks,
200
+ };
201
+ }
202
+
203
+ export function prepareSearchPackage(data: Manifest): any {
204
+ const latest = pkgUtils.getLatest(data);
205
+
206
+ if (latest && data.versions[latest]) {
207
+ const version: Version = data.versions[latest];
208
+ const versions: any = { [latest]: 'latest' };
209
+ const pkg: any = {
210
+ name: version.name,
211
+ description: version.description,
212
+ [DIST_TAGS]: { latest },
213
+ maintainers: version.maintainers || [version.author].filter(Boolean),
214
+ author: version.author,
215
+ repository: version.repository,
216
+ readmeFilename: version.readmeFilename || '',
217
+ homepage: version.homepage,
218
+ keywords: version.keywords,
219
+ bugs: version.bugs,
220
+ license: version.license,
221
+ // time: {
222
+ // modified: time,
223
+ // },
224
+ versions,
225
+ };
226
+
227
+ return pkg;
228
+ }
229
+ }
230
+
231
+ export function isDifferentThanOne(versions: Versions | AttachMents): boolean {
232
+ return Object.keys(versions).length !== 1;
233
+ }
234
+
235
+ // @deprecated use validationUtils.validatePublishNewPackage
236
+ export function hasInvalidPublishBody(manifest: Pick<Manifest, '_attachments' | 'versions'>) {
237
+ if (!manifest) {
238
+ return false;
239
+ }
240
+
241
+ const { _attachments, versions } = manifest;
242
+ const res =
243
+ isObject(_attachments) === false ||
244
+ isDifferentThanOne(_attachments) ||
245
+ isObject(versions) === false ||
246
+ isDifferentThanOne(versions);
247
+ return res;
248
+ }
249
+
250
+ /**
251
+ * Function gets a local info and an info from uplinks and tries to merge it
252
+ exported for unit tests only.
253
+ * @param {*} local
254
+ * @param {*} remoteManifest
255
+ * @param {*} config configuration file
256
+ */
257
+ export function mergeVersions(cacheManifest: Manifest, remoteManifest: Manifest): Manifest {
258
+ let _cacheManifest = { ...cacheManifest };
259
+ const { versions, time } = remoteManifest;
260
+ // copy new versions to a cache
261
+ // NOTE: if a certain version was updated, we can't refresh it reliably
262
+ for (const i in versions) {
263
+ if (typeof cacheManifest.versions[i] === 'undefined') {
264
+ _cacheManifest.versions[i] = versions[i];
265
+ }
266
+ }
267
+
268
+ for (const i in time) {
269
+ if (typeof cacheManifest.time[i] === 'undefined') {
270
+ _cacheManifest.time[i] = time[i];
271
+ }
272
+ }
273
+
274
+ for (const distTag in remoteManifest[DIST_TAGS]) {
275
+ if (_cacheManifest[DIST_TAGS][distTag] !== remoteManifest[DIST_TAGS][distTag]) {
276
+ if (
277
+ !_cacheManifest[DIST_TAGS][distTag] ||
278
+ semver.lte(_cacheManifest[DIST_TAGS][distTag], remoteManifest[DIST_TAGS][distTag])
279
+ ) {
280
+ _cacheManifest[DIST_TAGS][distTag] = remoteManifest[DIST_TAGS][distTag];
281
+ }
282
+ if (
283
+ distTag === 'latest' &&
284
+ _cacheManifest[DIST_TAGS][distTag] === remoteManifest[DIST_TAGS][distTag]
285
+ ) {
286
+ // NOTE: this override the latest publish readme from local cache with
287
+ // the remote one
288
+ cacheManifest = { ..._cacheManifest, readme: remoteManifest.readme };
289
+ }
290
+ }
291
+ }
292
+
293
+ return cacheManifest;
294
+ }
295
+
296
+ /**
297
+ * Normalize dist-tags.
298
+ *
299
+ * There is a legacy behaviour where the dist-tags could be an array, in such
300
+ * case, the array is orderded and the highest version becames the
301
+ * latest.
302
+ *
303
+ * The dist-tag tags must be plain strigs, if the latest is empty (for whatever reason) is
304
+ * normalized to be the highest version available.
305
+ *
306
+ * This function cleans up every invalid version on dist-tags, but does not remove
307
+ * invalid versions from the manifest.
308
+ *
309
+ * @param {*} data
310
+ */
311
+ export function normalizeDistTags(manifest: Manifest): Manifest {
312
+ let sorted;
313
+ // handle missing latest dist-tag
314
+ if (!manifest[DIST_TAGS].latest) {
315
+ // if there is no latest tag, set the highest known version based on semver sort
316
+ sorted = sortVersionsAndFilterInvalid(Object.keys(manifest.versions));
317
+ if (sorted?.length) {
318
+ // get the highest published version
319
+ manifest[DIST_TAGS].latest = sorted.pop();
320
+ }
321
+ }
322
+
323
+ for (const tag in manifest[DIST_TAGS]) {
324
+ // deprecated (will be removed un future majors)
325
+ // this should not happen, tags should be plain strings, legacy fallback
326
+ if (_.isArray(manifest[DIST_TAGS][tag])) {
327
+ if (manifest[DIST_TAGS][tag].length) {
328
+ // sort array
329
+ // FIXME: this is clearly wrong, we need to research why this is like this.
330
+ // @ts-ignore
331
+ sorted = sortVersionsAndFilterInvalid(manifest[DIST_TAGS][tag]);
332
+ if (sorted.length) {
333
+ // use highest version based on semver sort
334
+ manifest[DIST_TAGS][tag] = sorted.pop();
335
+ }
336
+ } else {
337
+ delete manifest[DIST_TAGS][tag];
338
+ }
339
+ } else if (_.isString(manifest[DIST_TAGS][tag])) {
340
+ if (!semver.parse(manifest[DIST_TAGS][tag], true)) {
341
+ // if the version is invalid, delete the dist-tag entry
342
+ delete manifest[DIST_TAGS][tag];
343
+ }
344
+ }
345
+ }
346
+
347
+ return manifest;
348
+ }
349
+
350
+ export function hasDeprecatedVersions(pkgInfo: Manifest): boolean {
351
+ const { versions } = pkgInfo;
352
+ for (const version in versions) {
353
+ if (Object.prototype.hasOwnProperty.call(versions[version], 'deprecated')) {
354
+ return true;
355
+ }
356
+ }
357
+ return false;
358
+ }
359
+
360
+ export function isDeprecatedManifest(manifest: Manifest): boolean {
361
+ return hasDeprecatedVersions(manifest) && Object.keys(manifest._attachments).length === 0;
362
+ }