@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/src/search.ts DELETED
@@ -1,175 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
- // eslint-disable no-invalid-this
3
- import buildDebug from 'debug';
4
- import _ from 'lodash';
5
- import { PassThrough, Transform, pipeline } from 'stream';
6
-
7
- import { VerdaccioError } from '@verdaccio/core';
8
- import { errorUtils, searchUtils } from '@verdaccio/core';
9
- import { logger } from '@verdaccio/logger';
10
- import { IProxy, ProxyList, ProxySearchParams } from '@verdaccio/proxy';
11
- import { Version } from '@verdaccio/types';
12
-
13
- import { LocalStorage } from './local-storage';
14
- import { Storage } from './storage';
15
-
16
- const debug = buildDebug('verdaccio:storage:search');
17
- export interface ISearchResult {
18
- ref: string;
19
- score: number;
20
- }
21
- // @deprecated not longer used
22
- export interface IWebSearch {
23
- storage: Storage;
24
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
- query(query: string): ISearchResult[];
26
- add(pkg: Version): void;
27
- remove(name: string): void;
28
- reindex(): void;
29
- configureStorage(storage: Storage): void;
30
- }
31
-
32
- export function removeDuplicates(results: searchUtils.SearchPackageItem[]) {
33
- const pkgNames: any[] = [];
34
- const orderByResults = _.orderBy(results, ['verdaccioPrivate', 'asc']);
35
- return orderByResults.filter((pkg) => {
36
- if (pkgNames.includes(pkg?.package?.name)) {
37
- return false;
38
- }
39
- pkgNames.push(pkg?.package?.name);
40
- return true;
41
- });
42
- }
43
-
44
- class TransFormResults extends Transform {
45
- public constructor(options) {
46
- super(options);
47
- }
48
-
49
- /**
50
- * Transform either array of packages or a single package into a stream of packages.
51
- * From uplinks the chunks are array but from local packages are objects.
52
- * @param {string} chunk
53
- * @param {string} encoding
54
- * @param {function} done
55
- * @returns {void}
56
- * @override
57
- */
58
- public _transform(chunk, _encoding, callback) {
59
- if (_.isArray(chunk)) {
60
- // from remotes we should expect chunks as arrays
61
- (chunk as searchUtils.SearchItem[])
62
- .filter((pkgItem) => {
63
- debug(`streaming remote pkg name ${pkgItem?.package?.name}`);
64
- return true;
65
- })
66
- .forEach((pkgItem) => {
67
- this.push({ ...pkgItem, verdaccioPkgCached: false, verdaccioPrivate: false });
68
- });
69
- return callback();
70
- } else {
71
- // local we expect objects
72
- debug(`streaming local pkg name ${chunk?.package?.name}`);
73
- this.push(chunk);
74
- return callback();
75
- }
76
- }
77
- }
78
-
79
- export class SearchManager {
80
- public readonly uplinks: ProxyList;
81
- public readonly localStorage: LocalStorage;
82
- constructor(uplinks: ProxyList, storage: LocalStorage) {
83
- this.uplinks = uplinks;
84
- this.localStorage = storage;
85
- }
86
-
87
- public get proxyList() {
88
- const uplinksList = Object.keys(this.uplinks);
89
-
90
- return uplinksList;
91
- }
92
-
93
- /**
94
- * Handle search on packages and proxies.
95
- * Iterate all proxies configured and search in all endpoints in v2 and pipe all responses
96
- * to a stream, once the proxies request has finished search in local storage for all packages
97
- * (privated and cached).
98
- */
99
- public async search(options: ProxySearchParams): Promise<searchUtils.SearchPackageItem[]> {
100
- const transformResults = new TransFormResults({ objectMode: true });
101
- const streamPassThrough = new PassThrough({ objectMode: true });
102
- const upLinkList = this.proxyList;
103
-
104
- const searchUplinksStreams = upLinkList.map((uplinkId) => {
105
- const uplink = this.uplinks[uplinkId];
106
- if (!uplink) {
107
- // this should never tecnically happens
108
- logger.fatal({ uplinkId }, 'uplink @upLinkId not found');
109
- }
110
- return this.consumeSearchStream(uplinkId, uplink, options, streamPassThrough);
111
- });
112
-
113
- try {
114
- debug('search uplinks');
115
- // we only process those streams end successfully, if all fails
116
- // we just include local storage
117
- await Promise.allSettled([...searchUplinksStreams]);
118
- debug('search uplinks done');
119
- } catch (err: any) {
120
- logger.error({ err: err?.message }, ' error on uplinks search @{err}');
121
- streamPassThrough.emit('error', err);
122
- }
123
- debug('search local');
124
- try {
125
- await this.localStorage.search(streamPassThrough, options.query as searchUtils.SearchQuery);
126
- } catch (err: any) {
127
- logger.error({ err: err?.message }, ' error on local search @{err}');
128
- streamPassThrough.emit('error', err);
129
- }
130
- const data: searchUtils.SearchPackageItem[] = [];
131
- const outPutStream = new PassThrough({ objectMode: true });
132
- pipeline(streamPassThrough, transformResults, outPutStream, (err) => {
133
- if (err) {
134
- throw errorUtils.getInternalError(err ? err.message : 'unknown error');
135
- } else {
136
- debug('pipeline succeeded');
137
- }
138
- });
139
-
140
- outPutStream.on('data', (chunk) => {
141
- data.push(chunk);
142
- });
143
-
144
- return new Promise((resolve) => {
145
- outPutStream.on('finish', async () => {
146
- const searchFinalResults: searchUtils.SearchPackageItem[] = removeDuplicates(data);
147
- debug('search stream total results: %o', searchFinalResults.length);
148
- return resolve(searchFinalResults);
149
- });
150
- debug('search done');
151
- });
152
- }
153
-
154
- /**
155
- * Consume the upstream and pipe it to a transformable stream.
156
- */
157
- private consumeSearchStream(
158
- uplinkId: string,
159
- uplink: IProxy,
160
- options: ProxySearchParams,
161
- searchPassThrough: PassThrough
162
- ): Promise<any> {
163
- return uplink.search({ ...options }).then((bodyStream) => {
164
- bodyStream.pipe(searchPassThrough, { end: false });
165
- bodyStream.on('error', (err: VerdaccioError): void => {
166
- logger.error(
167
- { uplinkId, err: err },
168
- 'search error for uplink @{uplinkId}: @{err?.message}'
169
- );
170
- searchPassThrough.end();
171
- });
172
- return new Promise((resolve) => bodyStream.on('end', resolve));
173
- });
174
- }
175
- }
@@ -1,263 +0,0 @@
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, Package, StringValue, Version, Versions } from '@verdaccio/types';
7
- import { generateRandomHexString, isNil, isObject, normalizeDistTags } from '@verdaccio/utils';
8
-
9
- import { LocalStorage } from './local-storage';
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
- export function generatePackageTemplate(name: string): Package {
19
- return {
20
- // standard things
21
- name,
22
- versions: {},
23
- time: {},
24
- [USERS]: {},
25
- [DIST_TAGS]: {},
26
- _uplinks: {},
27
- _distfiles: {},
28
- _attachments: {},
29
- _rev: '',
30
- };
31
- }
32
-
33
- /**
34
- * Normalize package properties, tags, revision id.
35
- * @param {Object} pkg package reference.
36
- */
37
- export function normalizePackage(pkg: Package): Package {
38
- const pkgProperties = ['versions', 'dist-tags', '_distfiles', '_attachments', '_uplinks', 'time'];
39
-
40
- pkgProperties.forEach((key): void => {
41
- const pkgProp = pkg[key];
42
-
43
- if (isNil(pkgProp) || validatioUtils.isObject(pkgProp) === false) {
44
- pkg[key] = {};
45
- }
46
- });
47
-
48
- if (_.isString(pkg._rev) === false) {
49
- pkg._rev = STORAGE.DEFAULT_REVISION;
50
- }
51
-
52
- if (_.isString(pkg._id) === false) {
53
- pkg._id = pkg.name;
54
- }
55
-
56
- // normalize dist-tags
57
- return normalizeDistTags(pkg);
58
- }
59
-
60
- export function generateRevision(rev: string): string {
61
- const _rev = rev.split('-');
62
-
63
- return (+_rev[0] || 0) + 1 + '-' + generateRandomHexString();
64
- }
65
-
66
- export function getLatestReadme(pkg: Package): string {
67
- const versions = pkg['versions'] || {};
68
- const distTags = pkg[DIST_TAGS] || {};
69
- // FIXME: here is a bit tricky add the types
70
- const latestVersion: Version | any = distTags['latest'] ? versions[distTags['latest']] || {} : {};
71
- let readme = _.trim(pkg.readme || latestVersion.readme || '');
72
- if (readme) {
73
- return readme;
74
- }
75
-
76
- // In case of empty readme - trying to get ANY readme in the following order:
77
- // 'next','beta','alpha','test','dev','canary'
78
- const readmeDistTagsPriority = ['next', 'beta', 'alpha', 'test', 'dev', 'canary'];
79
- readmeDistTagsPriority.forEach(function (tag): string | void {
80
- if (readme) {
81
- return readme;
82
- }
83
- const version: Version | any = distTags[tag] ? versions[distTags[tag]] || {} : {};
84
- readme = _.trim(version.readme || readme);
85
- });
86
- return readme;
87
- }
88
-
89
- // FIXME: type any due this
90
- export function cleanUpReadme(version: any): Version {
91
- if (isNil(version) === false) {
92
- delete version.readme;
93
- }
94
-
95
- return version;
96
- }
97
-
98
- export const WHITELIST = [
99
- '_rev',
100
- 'name',
101
- 'versions',
102
- 'dist-tags',
103
- 'readme',
104
- 'time',
105
- '_id',
106
- 'users',
107
- ];
108
-
109
- export function cleanUpLinksRef(result: Package, keepUpLinkData?: boolean): Package {
110
- const propertyToKeep = [...WHITELIST];
111
- if (keepUpLinkData === true) {
112
- propertyToKeep.push('_uplinks');
113
- }
114
-
115
- for (const i in result) {
116
- if (propertyToKeep.indexOf(i) === -1) {
117
- // Remove sections like '_uplinks' from response
118
- delete result[i];
119
- }
120
- }
121
-
122
- return result;
123
- }
124
-
125
- /**
126
- * Check whether a package it is already a local package
127
- * @param {*} name
128
- * @param {*} localStorage
129
- */
130
- export function checkPackageLocal(name: string, localStorage: LocalStorage): Promise<any> {
131
- return new Promise<void>((resolve, reject): void => {
132
- localStorage.getPackageMetadata(name, (err, results): void => {
133
- if (!isNil(err) && err.status !== HTTP_STATUS.NOT_FOUND) {
134
- return reject(err);
135
- }
136
- if (results) {
137
- return reject(errorUtils.getConflict(API_ERROR.PACKAGE_EXIST));
138
- }
139
- return resolve();
140
- });
141
- });
142
- }
143
-
144
- export function publishPackage(
145
- name: string,
146
- metadata: any,
147
- localStorage: LocalStorage
148
- ): Promise<any> {
149
- return new Promise<void>((resolve, reject): void => {
150
- localStorage.addPackage(name, metadata, (err): void => {
151
- if (!_.isNull(err)) {
152
- return reject(err);
153
- }
154
- return resolve();
155
- });
156
- });
157
- }
158
-
159
- export function checkPackageRemote(
160
- name: string,
161
- isAllowPublishOffline: boolean,
162
- syncMetadata: Function
163
- ): Promise<any> {
164
- return new Promise<void>((resolve, reject): void => {
165
- syncMetadata(name, null, {}, (err, packageJsonLocal, upLinksErrors): void => {
166
- // something weird
167
- if (err && err.status !== HTTP_STATUS.NOT_FOUND) {
168
- return reject(err);
169
- }
170
-
171
- // checking package exist already
172
- if (isNil(packageJsonLocal) === false) {
173
- return reject(errorUtils.getConflict(API_ERROR.PACKAGE_EXIST));
174
- }
175
-
176
- for (let errorItem = 0; errorItem < upLinksErrors.length; errorItem++) {
177
- // checking error
178
- // if uplink fails with a status other than 404, we report failure
179
- if (isNil(upLinksErrors[errorItem][0]) === false) {
180
- if (upLinksErrors[errorItem][0].status !== HTTP_STATUS.NOT_FOUND) {
181
- if (isAllowPublishOffline) {
182
- return resolve();
183
- }
184
-
185
- return reject(errorUtils.getServiceUnavailable(API_ERROR.UPLINK_OFFLINE_PUBLISH));
186
- }
187
- }
188
- }
189
-
190
- return resolve();
191
- });
192
- });
193
- }
194
-
195
- export function mergeUplinkTimeIntoLocal(localMetadata: Package, remoteMetadata: Package): any {
196
- if ('time' in remoteMetadata) {
197
- return Object.assign({}, localMetadata.time, remoteMetadata.time);
198
- }
199
-
200
- return localMetadata.time;
201
- }
202
-
203
- export function prepareSearchPackage(data: Package): 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
- /**
232
- * Create a tag for a package
233
- * @param {*} data
234
- * @param {*} version
235
- * @param {*} tag
236
- * @return {Boolean} whether a package has been tagged
237
- */
238
- export function tagVersion(data: Package, version: string, tag: StringValue): boolean {
239
- if (tag && data[DIST_TAGS][tag] !== version && semver.parse(version, true)) {
240
- // valid version - store
241
- data[DIST_TAGS][tag] = version;
242
- return true;
243
- }
244
- return false;
245
- }
246
-
247
- export function isDifferentThanOne(versions: Versions | AttachMents): boolean {
248
- return Object.keys(versions).length !== 1;
249
- }
250
-
251
- export function hasInvalidPublishBody(manifest: Pick<Package, '_attachments' | 'versions'>) {
252
- if (!manifest) {
253
- return false;
254
- }
255
-
256
- const { _attachments, versions } = manifest;
257
- const res =
258
- isObject(_attachments) === false ||
259
- isDifferentThanOne(_attachments) ||
260
- isObject(versions) === false ||
261
- isDifferentThanOne(versions);
262
- return res;
263
- }
@@ -1,32 +0,0 @@
1
- import { IProxy, ProxyList, ProxyStorage } from '@verdaccio/proxy';
2
- import { Config, Versions } from '@verdaccio/types';
3
-
4
- /**
5
- * Set up the Up Storage for each link.
6
- */
7
- export function setupUpLinks(config: Config): ProxyList {
8
- const uplinks: ProxyList = {};
9
-
10
- for (const uplinkName in config.uplinks) {
11
- if (Object.prototype.hasOwnProperty.call(config.uplinks, uplinkName)) {
12
- // instance for each up-link definition
13
- const proxy: IProxy = new ProxyStorage(config.uplinks[uplinkName], config);
14
- proxy.upname = uplinkName;
15
-
16
- uplinks[uplinkName] = proxy;
17
- }
18
- }
19
-
20
- return uplinks;
21
- }
22
-
23
- export function updateVersionsHiddenUpLink(versions: Versions, upLink: IProxy): void {
24
- for (const i in versions) {
25
- if (Object.prototype.hasOwnProperty.call(versions, i)) {
26
- const version = versions[i];
27
-
28
- // holds a "hidden" value to be used by the package storage.
29
- version[Symbol.for('__verdaccio_uplink')] = upLink.upname;
30
- }
31
- }
32
- }