0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-16 21:56:25 -05:00

refactor: fetch package endpoint and basic integration fastify (#2750)

* refactor: download manifest endpoint and integrate fastify

* fix file not found issue

* add temporary migration method to storage memory

* sanitize fs methods

* restore tests

* chore: restore sanitilize

will do later

* add tests

* add changeset

* lint

* trying something test

* chore: lint

* restore code

* fix e2e

* fix lint
This commit is contained in:
Juan Picado 2021-12-12 18:00:19 +01:00 committed by GitHub
parent 5bb049a79b
commit a828271d63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 601 additions and 77 deletions

View file

@ -0,0 +1,37 @@
---
'@verdaccio/api': major
'@verdaccio/fastify-migration': major
'@verdaccio/tarball': major
'@verdaccio/local-storage': major
'verdaccio-memory': major
'@verdaccio/server': major
'@verdaccio/store': major
'@verdaccio/utils': major
---
refactor: download manifest endpoint and integrate fastify
Much simpler API for fetching a package
```
const manifest = await storage.getPackageNext({
name,
uplinksLook: true,
req,
version: queryVersion,
requestOptions,
});
```
> not perfect, the `req` still is being passed to the proxy (this has to be refactored at proxy package) and then removed from here, in proxy we pass the request instance to the `request` library.
### Details
- `async/await` sugar for getPackage()
- Improve and reuse code between current implementation and new fastify endpoint (add scaffolding for request manifest)
- Improve performance
- Add new tests
### Breaking changes
All storage plugins will stop to work since the storage uses `getPackageNext` method which is Promise based, I won't replace this now because will force me to update all plugins, I'll follow up in another PR. Currently will throw http 500

View file

@ -15,7 +15,6 @@
'@verdaccio/logger': patch
'@verdaccio/logger-prettify': patch
'@verdaccio/middleware': patch
'@verdaccio/mock': patch
'@verdaccio/node-api': patch
'@verdaccio/proxy': patch
'@verdaccio/server': patch

View file

@ -204,8 +204,8 @@ jobs:
run: pnpm recursive install --frozen-lockfile
- name: Test CLI
run: pnpm test:e2e:cli
# env:
# DEBUG: verdaccio*
env:
DEBUG: verdaccio*
test-windows:
needs: [format, lint]
runs-on: windows-latest

View file

@ -19,6 +19,7 @@ node_modules/
packages/core/local-storage/_storage/**
packages/partials/storage_default_storage/
packages/standalone/dist/bundle.js
packages/verdaccio/dist/bundle.js
docker-examples/v5/reverse_proxy/nginx/relative_path/storage/*
build/
.vscode/

View file

@ -46,7 +46,6 @@
"@verdaccio/logger": "workspace:6.0.0-6-next.7",
"@verdaccio/middleware": "workspace:6.0.0-6-next.15",
"@verdaccio/store": "workspace:6.0.0-6-next.16",
"@verdaccio/tarball": "workspace:11.0.0-6-next.10",
"@verdaccio/utils": "workspace:6.0.0-6-next.9",
"abortcontroller-polyfill": "1.7.3",
"cookies": "0.8.0",

View file

@ -56,7 +56,7 @@ export default function (config: Config, auth: IAuth, storage: Storage): Router
app.use(encodeScopePackage);
// for "npm whoami"
whoami(app);
pkg(app, auth, storage, config);
pkg(app, auth, storage);
profile(app, auth);
// @deprecated endpoint, 404 by default
search(app);

View file

@ -1,14 +1,10 @@
import buildDebug from 'debug';
import { Router } from 'express';
import _ from 'lodash';
import { IAuth } from '@verdaccio/auth';
import { API_ERROR, DIST_TAGS, HEADERS, errorUtils } from '@verdaccio/core';
import { HEADERS, errorUtils } from '@verdaccio/core';
import { allow } from '@verdaccio/middleware';
import { Storage } from '@verdaccio/store';
import { convertDistRemoteToLocalTarballUrls } from '@verdaccio/tarball';
import { Config, Package } from '@verdaccio/types';
import { getVersion } from '@verdaccio/utils';
import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';
@ -18,7 +14,7 @@ const downloadStream = (
packageName: string,
filename: string,
storage: any,
req: $RequestExtend,
_req: $RequestExtend,
res: $ResponseExtend
): void => {
const stream = storage.getTarball(packageName, filename);
@ -35,13 +31,17 @@ const downloadStream = (
stream.pipe(res);
};
export default function (route: Router, auth: IAuth, storage: Storage, config: Config): void {
export default function (route: Router, auth: IAuth, storage: Storage): void {
const can = allow(auth);
// TODO: anonymous user?
route.get(
'/:package/:version?',
can('access'),
function (req: $RequestExtend, _res: $ResponseExtend, next: $NextFunctionVer): void {
async function (
req: $RequestExtend,
_res: $ResponseExtend,
next: $NextFunctionVer
): Promise<void> {
debug('init package by version');
const name = req.params.package;
let queryVersion = req.params.version;
@ -51,57 +51,27 @@ export default function (route: Router, auth: IAuth, storage: Storage, config: C
// FIXME: if we migrate to req.hostname, the port is not longer included.
host: req.host,
};
const getPackageMetaCallback = function (err, metadata: Package): void {
if (err) {
debug('error on fetch metadata for %o with error %o', name, err.message);
return next(err);
try {
// TODO: this is just temporary while I migrate all plugins to use the new API
// the method will be renamed to getPackage again but Promise Based.
if (!storage.getPackageNext) {
throw errorUtils.getInternalError(
'getPackageNext not implemented, check pr-2750 for more details'
);
}
debug('convert dist remote to local with prefix %o', config?.url_prefix);
metadata = convertDistRemoteToLocalTarballUrls(
metadata,
const manifest = await storage.getPackageNext({
name,
uplinksLook: true,
req,
version: queryVersion,
requestOptions,
config?.url_prefix
);
debug('query by param version: %o', queryVersion);
if (_.isNil(queryVersion)) {
debug('param %o version found', queryVersion);
return next(metadata);
}
let version = getVersion(metadata.versions, queryVersion);
debug('query by latest version %o and result %o', queryVersion, version);
if (_.isNil(version) === false) {
debug('latest version found %o', version);
return next(version);
}
if (_.isNil(metadata[DIST_TAGS]) === false) {
if (_.isNil(metadata[DIST_TAGS][queryVersion]) === false) {
queryVersion = metadata[DIST_TAGS][queryVersion];
debug('dist-tag version found %o', queryVersion);
version = getVersion(metadata.versions, queryVersion);
if (_.isNil(version) === false) {
debug('dist-tag found %o', version);
return next(version);
}
}
} else {
debug('dist tag not detected');
}
debug('package version not found %o', queryVersion);
return next(errorUtils.getNotFound(`${API_ERROR.VERSION_NOT_EXIST}: ${queryVersion}`));
};
debug('get package name %o', name);
debug('uplinks look up enabled');
storage.getPackage({
name,
uplinksLook: true,
req,
callback: getPackageMetaCallback,
});
});
next(manifest);
} catch (err) {
next(err);
}
}
);

View file

@ -0,0 +1,48 @@
import buildDebug from 'debug';
import { FastifyInstance } from 'fastify';
import { Package, Version } from '@verdaccio/types';
const debug = buildDebug('verdaccio:web:api:sidebar');
export type $SidebarPackage = Package & { latest: Version };
async function manifestRoute(fastify: FastifyInstance) {
fastify.get('/:packageName', async (request) => {
// @ts-ignore
const { packageName } = request.params;
const storage = fastify.storage;
debug('pkg name %s ', packageName);
const data = await storage?.getPackageNext({
name: packageName,
req: request.raw,
uplinksLook: true,
requestOptions: {
protocol: request.protocol,
headers: request.headers as any,
host: request.hostname,
},
});
return data;
});
fastify.get('/:packageName/:version', async (request) => {
// @ts-ignore
const { packageName, version } = request.params;
const storage = fastify.storage;
debug('pkg name %s, with version / tag: %s ', packageName, version);
const data = await storage?.getPackageNext({
name: packageName,
req: request.raw,
version,
uplinksLook: true,
requestOptions: {
protocol: request.protocol,
headers: request.headers as any,
host: request.hostname,
},
});
return data;
});
}
export default manifestRoute;

View file

@ -5,6 +5,7 @@ import { Config as AppConfig, createAnonymousRemoteUser } from '@verdaccio/confi
import { Config as IConfig, RemoteUser } from '@verdaccio/types';
import distTags from './endpoints/dist-tags';
import manifest from './endpoints/package';
import ping from './endpoints/ping';
import search from './endpoints/search';
import tarball from './endpoints/tarball';
@ -37,6 +38,7 @@ async function startServer({ logger, config }) {
instance.register(user, { prefix: '/-/user' });
instance.register(search);
instance.register(whoami);
instance.register(manifest);
instance.register(tarball);
instance.register(distTags);
instance.register(readme, { prefix: '/-/verdaccio' });

View file

@ -1,2 +1,6 @@
import { RequestOptions } from '@verdaccio/url';
export { convertDistRemoteToLocalTarballUrls } from './convertDistRemoteToLocalTarballUrls';
export { getLocalRegistryTarballUri } from './getLocalRegistryTarballUri';
export { RequestOptions };

View file

@ -45,6 +45,7 @@
"debug": "4.3.3",
"globby": "11.0.4",
"lockfile": "1.0.4",
"sanitize-filename": "1.6.3",
"lodash": "4.17.21",
"lowdb": "1.0.0",
"lru-cache": "6.0.0"

View file

@ -160,6 +160,21 @@ export default class LocalFS implements ILocalFSPackageManager {
this._writeFile(this._getStorage(packageJSONFileName), this._convertToString(value), cb);
}
public async readPackageNext(name: string): Promise<Package> {
debug('read a package %o', name);
try {
const res = await this._readStorageFile(this._getStorage(packageJSONFileName));
const data: any = JSON.parse(res.toString('utf8'));
debug('read storage file %o has succeed', name);
return data;
} catch (err: any) {
debug('parse error');
this.logger.error({ err, name }, 'error @{err.message} on parse @{name}');
throw err;
}
}
public readPackage(name: string, cb: Callback): void {
debug('read a package %o', name);
@ -177,7 +192,7 @@ export default class LocalFS implements ILocalFSPackageManager {
}
})
.catch((err) => {
this.logger.error({ err }, 'error on read storage file @{err.message}');
debug('error on read storage file %o', err.message);
return cb(err);
});
}

View file

@ -91,6 +91,15 @@ class MemoryHandler implements IPackageStorageManager {
}
}
public async readPackageNext(name: string): Promise<Package> {
const json = this._getStorage(name);
try {
return typeof json === 'undefined' ? errorUtils.getNotFound() : null, parsePackage(json);
} catch (err: any) {
throw errorUtils.getNotFound();
}
}
public readPackage(name: string, cb: ReadPackageCallback): void {
debug('read package %o', name);
const json = this._getStorage(name);

View file

@ -47,6 +47,7 @@
"@verdaccio/proxy": "workspace:6.0.0-6-next.15",
"@verdaccio/streams": "workspace:11.0.0-6-next.5",
"@verdaccio/utils": "workspace:6.0.0-6-next.9",
"@verdaccio/tarball": "workspace:11.0.0-6-next.10",
"JSONStream": "1.3.5",
"abortcontroller-polyfill": "1.7.3",
"async": "3.1.1",
@ -61,9 +62,12 @@
"@types/node": "16.11.11",
"@verdaccio/mock": "workspace:6.0.0-6-next.12",
"@verdaccio/types": "workspace:11.0.0-6-next.9",
"@verdaccio/helper": "workspace:1.0.0",
"undici": "4.7.3",
"nock": "13.0.11",
"undici-fetch": "1.0.0-rc.4",
"tmp-promise": "3.0.3"
"tmp-promise": "3.0.3",
"node-mocks-http": "1.10.1"
},
"funding": {
"type": "opencollective",

View file

@ -706,11 +706,24 @@ class LocalStorage {
return stream;
}
public async getPackageMetadataNext(name: string): Promise<Package> {
const storage: IPackageStorage = this._getLocalStorage(name);
debug('get package metadata for %o', name);
if (typeof storage === 'undefined') {
// TODO: this might be a better an error to throw
// if storage is not there cannot be 404.
throw errorUtils.getNotFound();
}
return await this._readPackageNext(name, storage);
}
/**
* Retrieve a package by name.
* @param {*} name
* @param {*} callback
* @return {Function}
* @deprecated
*/
public getPackageMetadata(name: string, callback: Callback = (): void => {}): void {
const storage: IPackageStorage = this._getLocalStorage(name);
@ -790,6 +803,7 @@ class LocalStorage {
* Read a json file from storage.
* @param {Object} storage
* @param {Function} callback
* @deprecated
*/
private _readPackage(name: string, storage: any, callback: Callback): void {
storage.readPackage(name, (err, result): void => {
@ -805,6 +819,24 @@ class LocalStorage {
});
}
private async _readPackageNext(name: string, storage: any): Promise<Package> {
try {
const result: Package = await storage.readPackageNext(name);
return normalizePackage(result);
} catch (err: any) {
if (err.code === STORAGE.NO_SUCH_FILE_ERROR || err.code === HTTP_STATUS.NOT_FOUND) {
debug('package %s not found', name);
throw errorUtils.getNotFound();
}
this.logger.error(
{ err: err, file: STORAGE.PACKAGE_FILE_NAME },
`error reading @{file}: @{!err.message}`
);
throw errorUtils.getInternalError();
}
}
/**
* Retrieve either a previous created local package or a boilerplate.
* @param {*} pkgName

View file

@ -11,6 +11,7 @@ import { logger } from '@verdaccio/logger';
import { ProxyStorage } from '@verdaccio/proxy';
import { IProxy, ProxyList } from '@verdaccio/proxy';
import { ReadTarball } from '@verdaccio/streams';
import { convertDistRemoteToLocalTarballUrls } from '@verdaccio/tarball';
import {
Callback,
CallbackAction,
@ -28,7 +29,7 @@ import {
Version,
Versions,
} from '@verdaccio/types';
import { normalizeDistTags } from '@verdaccio/utils';
import { getVersion, normalizeDistTags } from '@verdaccio/utils';
import { LocalStorage } from './local-storage';
import { SearchInstance, SearchManager } from './search';
@ -40,7 +41,7 @@ import {
mergeUplinkTimeIntoLocal,
publishPackage,
} from './storage-utils';
import { IGetPackageOptions, IPluginFilters, ISyncUplinks } from './type';
import { IGetPackageOptions, IGetPackageOptionsNext, IPluginFilters, ISyncUplinks } from './type';
import { setupUpLinks, updateVersionsHiddenUpLink } from './uplink-util';
if (semver.lte(process.version, 'v15.0.0')) {
@ -101,9 +102,10 @@ class Storage {
);
debug('publishing a package for %o', name);
await publishPackage(name, metadata, this.localStorage as LocalStorage);
callback();
// TODO: return published data and replace callback by a promise
callback(null, true);
} catch (err: any) {
debug('error on add a package for %o with error %o', name, err?.error);
debug('error on add a package for %o with error %o', name, err);
callback(err);
}
}
@ -344,6 +346,113 @@ class Storage {
}
}
public async getPackageNext(options: IGetPackageOptionsNext): Promise<Package | Version> {
const { name } = options;
debug('get package for %o', name);
try {
let data: Package;
try {
data = await this.localStorage.getPackageMetadataNext(name);
} catch (err: any) {
// we don't have package locally, so we need to fetch it from uplinks
if (err && (!err.status || err.status >= HTTP_STATUS.INTERNAL_ERROR)) {
throw err;
}
}
// time to sync with uplinks if we have any
debug('sync uplinks for %o', name);
// @ts-expect-error
const [manifest, errors] = await this._syncUplinksMetadataNext(name, data, {
req: options.req,
uplinksLook: options.uplinksLook,
keepUpLinkData: options.keepUpLinkData,
});
debug('no. sync uplinks errors %o', errors?.length);
// TODO: we could improve performance here, if a specific version is requested
// we just convert that version and return it otherwise we convert
// the whole manifest, bonus points for contribution :)
// convert dist remotes to local bars
const convertedManifest = convertDistRemoteToLocalTarballUrls(
manifest,
options.requestOptions,
this.config.url_prefix
);
// if no version we return the whole manifest
if (_.isNil(options.version)) {
return convertedManifest;
}
// we have version, so we need to return specific version
const queryVersion = options.version as string;
const version: Version | undefined = getVersion(convertedManifest.versions, options.version);
debug('query by latest version %o and result %o', options.version, version);
if (typeof version !== 'undefined') {
debug('latest version found %o', version);
return version;
}
// the version could be a dist-tag eg: beta, alpha, so we find the matched version
// on disg-tag list
if (_.isNil(convertedManifest[DIST_TAGS]) === false) {
if (_.isNil(convertedManifest[DIST_TAGS][queryVersion]) === false) {
// the version found as a distag
const matchedDisTagVersion: string = convertedManifest[DIST_TAGS][queryVersion];
debug('dist-tag version found %o', matchedDisTagVersion);
const disTagVersion: Version | undefined = getVersion(
convertedManifest.versions,
matchedDisTagVersion
);
if (typeof disTagVersion !== 'undefined') {
debug('dist-tag found %o', disTagVersion);
return disTagVersion;
}
}
} else {
debug('dist tag not detected');
}
// we didn't find the version, not found error
debug('package version not found %o', queryVersion);
throw errorUtils.getNotFound(`${API_ERROR.VERSION_NOT_EXIST}: ${queryVersion}`);
} catch (err: any) {
this.logger.error(
{ name, err: err.message },
'error on get package for @{name} with error @{err}'
);
throw err;
}
}
private _syncUplinksMetadataNext(
name: string,
data: Package,
{ uplinksLook, keepUpLinkData, req }
): Promise<[Package, any[]]> {
return new Promise((resolve, reject) => {
this._syncUplinksMetadata(
name,
data,
{ req: req, uplinksLook },
function getPackageSynUpLinksCallback(err, result: Package, uplinkErrors): void {
if (err) {
debug('error on sync package for %o with error %o', name, err?.message);
return reject(err);
}
const normalizedPkg = Object.assign({}, result, {
...normalizeDistTags(cleanUpLinksRef(result, keepUpLinkData)),
_attachments: {},
});
debug('no. sync uplinks errors %o', uplinkErrors?.length);
resolve([normalizedPkg, uplinkErrors]);
}
);
});
}
/**
Retrieve a package metadata for {name} package
Function invokes localStorage.getPackage and uplink.get_package for every
@ -451,6 +560,8 @@ class Storage {
}
}
// notas, debo migrar _syncUplinksMetadata algo mas lindo
/**
* Function fetches package metadata from uplinks and synchronizes it with local data
if package is available locally, it MUST be provided in pkginfo

View file

@ -1,5 +1,6 @@
import { Callback, Config, IPluginStorageFilter } from '@verdaccio/types';
// @deprecated
export interface IGetPackageOptions {
callback: Callback;
name: string;
@ -7,6 +8,22 @@ export interface IGetPackageOptions {
uplinksLook: boolean;
req: any;
}
export type IGetPackageOptionsNext = {
// @deprecated remove this soon
req: any;
name: string;
version?: string;
keepUpLinkData?: boolean;
uplinksLook: boolean;
requestOptions: {
// RequestOptions from url package
host: string;
protocol: string;
headers: { [key: string]: string };
};
};
export interface ISyncUplinks {
uplinksLook?: boolean;
etag?: string;

View file

@ -8,8 +8,6 @@ import { SearchInstance } from '../src/search';
setup([]);
// jest.mock('@verdaccio/logger');
describe('search', () => {
describe('search manager utils', () => {
test('remove duplicates', () => {
@ -18,6 +16,9 @@ describe('search', () => {
package: {
name: 'foo',
},
['dist-tags']: {
latest: '1.0.0',
},
// @ts-expect-error
score: {},
searchScore: 0.4,

View file

@ -0,0 +1,245 @@
import nock from 'nock';
import * as httpMocks from 'node-mocks-http';
import { Config } from '@verdaccio/config';
import { HEADERS, errorUtils } from '@verdaccio/core';
import { generatePackageMetadata } from '@verdaccio/helper';
import { setup } from '@verdaccio/logger';
import { configExample, generateRamdonStorage } from '@verdaccio/mock';
import { Storage } from '../src';
setup([]);
const domain = 'http://localhost:4873';
const fakeHost = 'localhost:4873';
const fooManifest = generatePackageMetadata('foo', '1.0.0');
describe('storage', () => {
beforeEach(() => {
nock.cleanAll();
nock.abortPendingRequests();
jest.clearAllMocks();
});
describe('add packages', () => {
test('add package item', async () => {
nock(domain).get('/foo').reply(404);
const config = new Config(
configExample({
storage: generateRamdonStorage(),
})
);
const storage = new Storage(config);
await storage.init(config);
await storage.addPackage('foo', fooManifest, (err) => {
expect(err).toBeNull();
});
});
});
// TODO: getPackageNext should replace getPackage eventually
describe('get packages getPackageNext()', () => {
describe('with uplinks', () => {
test('should get 201 and merge from uplink', async () => {
nock(domain).get('/foo').reply(201, fooManifest);
const config = new Config(
configExample({
storage: generateRamdonStorage(),
})
);
const req = httpMocks.createRequest({
method: 'GET',
connection: { remoteAddress: fakeHost },
headers: {
host: fakeHost,
[HEADERS.FORWARDED_PROTO]: 'http',
},
url: '/',
});
const storage = new Storage(config);
await storage.init(config);
await expect(
storage.getPackageNext({
name: 'foo',
uplinksLook: true,
req,
requestOptions: {
headers: req.headers as any,
protocol: req.protocol,
host: req.get('host'),
},
})
).resolves.toEqual(expect.objectContaining({ name: 'foo' }));
});
test('should get 201 and merge from uplink with version', async () => {
nock(domain).get('/foo').reply(201, fooManifest);
const config = new Config(
configExample({
storage: generateRamdonStorage(),
})
);
const req = httpMocks.createRequest({
method: 'GET',
connection: { remoteAddress: fakeHost },
headers: {
host: fakeHost,
[HEADERS.FORWARDED_PROTO]: 'http',
},
url: '/',
});
const storage = new Storage(config);
await storage.init(config);
await expect(
storage.getPackageNext({
name: 'foo',
version: '1.0.0',
uplinksLook: true,
req,
requestOptions: {
headers: req.headers as any,
protocol: req.protocol,
host: req.get('host'),
},
})
).resolves.toEqual(expect.objectContaining({ name: 'foo' }));
});
test('should get 201 and merge from uplink with dist-tag', async () => {
nock(domain).get('/foo').reply(201, fooManifest);
const config = new Config(
configExample({
storage: generateRamdonStorage(),
})
);
const req = httpMocks.createRequest({
method: 'GET',
connection: { remoteAddress: fakeHost },
headers: {
host: fakeHost,
[HEADERS.FORWARDED_PROTO]: 'http',
},
url: '/',
});
const storage = new Storage(config);
await storage.init(config);
await expect(
storage.getPackageNext({
name: 'foo',
version: 'latest',
uplinksLook: true,
req,
requestOptions: {
headers: req.headers as any,
protocol: req.protocol,
host: req.get('host'),
},
})
).resolves.toEqual(expect.objectContaining({ name: 'foo' }));
});
test('should get 404 for version does not exist', async () => {
nock(domain).get('/foo').reply(201, fooManifest);
const config = new Config(
configExample({
storage: generateRamdonStorage(),
})
);
const req = httpMocks.createRequest({
method: 'GET',
connection: { remoteAddress: fakeHost },
headers: {
host: fakeHost,
[HEADERS.FORWARDED_PROTO]: 'http',
},
url: '/',
});
const storage = new Storage(config);
await storage.init(config);
await expect(
storage.getPackageNext({
name: 'foo',
version: '1.0.0-does-not-exist',
uplinksLook: true,
req,
requestOptions: {
headers: req.headers as any,
protocol: req.protocol,
host: req.get('host'),
},
})
).rejects.toThrow(
errorUtils.getNotFound("this version doesn't exist: 1.0.0-does-not-exist")
);
});
test('should get 404', async () => {
nock(domain).get('/foo2').reply(404);
const config = new Config(
configExample({
storage: generateRamdonStorage(),
})
);
const req = httpMocks.createRequest({
method: 'GET',
connection: { remoteAddress: fakeHost },
headers: {
host: fakeHost,
[HEADERS.FORWARDED_PROTO]: 'http',
},
url: '/',
});
const storage = new Storage(config);
await storage.init(config);
await expect(
storage.getPackageNext({
name: 'foo2',
uplinksLook: true,
req,
requestOptions: {
headers: req.headers as any,
protocol: req.protocol,
host: req.get('host'),
},
})
).rejects.toThrow(errorUtils.getNotFound());
});
test('should get ETIMEDOUT with uplink', async () => {
nock(domain).get('/foo2').replyWithError({
code: 'ETIMEDOUT',
errno: 'ETIMEDOUT',
});
const config = new Config(
configExample({
storage: generateRamdonStorage(),
})
);
const req = httpMocks.createRequest({
method: 'GET',
connection: { remoteAddress: fakeHost },
headers: {
host: fakeHost,
[HEADERS.FORWARDED_PROTO]: 'http',
},
url: '/',
});
const storage = new Storage(config);
await storage.init(config);
await expect(
storage.getPackageNext({
name: 'foo2',
uplinksLook: true,
req,
requestOptions: {
headers: req.headers as any,
protocol: req.protocol,
host: req.get('host'),
},
})
).rejects.toThrow(errorUtils.getServiceUnavailable());
});
});
});
});

View file

@ -1,6 +1,7 @@
{
"name": "@verdaccio/mock",
"version": "6.0.0-6-next.12",
"private": true,
"author": {
"name": "Juan Picado",
"email": "juanpicado19@gmail.com"

View file

@ -1,8 +1,11 @@
import buildDebug from 'debug';
import _ from 'lodash';
import path from 'path';
import { parseConfigFile } from '@verdaccio/config';
const debug = buildDebug('verdaccio:mock:config');
/**
* Override the default.yaml configuration file with any new config provided.
*/
@ -14,8 +17,9 @@ function configExample(
const locationFile = location
? path.join(location, configFile)
: path.join(__dirname, `./config/yaml/${configFile}`);
debug('config location: %s', locationFile);
const config = parseConfigFile(locationFile);
debug('config file: %o', JSON.stringify(config));
return _.assign({}, _.cloneDeep(config), externalConfig);
}

View file

@ -8,7 +8,7 @@ import { Package, Version, Versions } from '@verdaccio/types';
* Gets version from a package object taking into account semver weirdness.
* @return {String} return the semantic version of a package
*/
export function getVersion(versions: Versions, version: any): Version | void {
export function getVersion(versions: Versions, version: any): Version | undefined {
if (!versions) {
return;
}

View file

@ -40,7 +40,6 @@
"@verdaccio/cli": "workspace:6.0.0-6-next.25",
"@verdaccio/hooks": "workspace:6.0.0-6-next.9",
"@verdaccio/logger": "workspace:6.0.0-6-next.7",
"@verdaccio/mock": "workspace:6.0.0-6-next.12",
"@verdaccio/node-api": "workspace:6.0.0-6-next.24",
"@verdaccio/ui-theme": "workspace:6.0.0-6-next.12",
"@verdaccio/utils": "workspace:6.0.0-6-next.9",
@ -48,6 +47,7 @@
"verdaccio-htpasswd": "workspace:11.0.0-6-next.10"
},
"devDependencies": {
"@verdaccio/mock": "workspace:6.0.0-6-next.12",
"@verdaccio/auth": "workspace:6.0.0-6-next.15",
"@verdaccio/core": "workspace:6.0.0-6-next.3",
"@verdaccio/config": "workspace:6.0.0-6-next.11",

View file

@ -196,7 +196,6 @@ importers:
'@verdaccio/middleware': workspace:6.0.0-6-next.15
'@verdaccio/server': workspace:6.0.0-6-next.23
'@verdaccio/store': workspace:6.0.0-6-next.16
'@verdaccio/tarball': workspace:11.0.0-6-next.10
'@verdaccio/types': workspace:11.0.0-6-next.9
'@verdaccio/utils': workspace:6.0.0-6-next.9
abortcontroller-polyfill: 1.7.3
@ -216,7 +215,6 @@ importers:
'@verdaccio/logger': link:../logger
'@verdaccio/middleware': link:../middleware
'@verdaccio/store': link:../store
'@verdaccio/tarball': link:../core/tarball
'@verdaccio/utils': link:../utils
abortcontroller-polyfill: 1.7.3
body-parser: 1.19.0
@ -694,6 +692,7 @@ importers:
lowdb: 1.0.0
lru-cache: 6.0.0
minimatch: 3.0.4
sanitize-filename: 1.6.3
tmp-promise: 3.0.3
dependencies:
'@verdaccio/core': link:../../core/core
@ -707,6 +706,7 @@ importers:
lodash: 4.17.21
lowdb: 1.0.0
lru-cache: 6.0.0
sanitize-filename: 1.6.3
devDependencies:
'@types/minimatch': 3.0.5
'@verdaccio/config': link:../../config
@ -1011,12 +1011,14 @@ importers:
'@types/node': 16.11.11
'@verdaccio/config': workspace:6.0.0-6-next.11
'@verdaccio/core': workspace:6.0.0-6-next.3
'@verdaccio/helper': workspace:1.0.0
'@verdaccio/loaders': workspace:6.0.0-6-next.7
'@verdaccio/local-storage': workspace:11.0.0-6-next.10
'@verdaccio/logger': workspace:6.0.0-6-next.7
'@verdaccio/mock': workspace:6.0.0-6-next.12
'@verdaccio/proxy': workspace:6.0.0-6-next.15
'@verdaccio/streams': workspace:11.0.0-6-next.5
'@verdaccio/tarball': workspace:11.0.0-6-next.10
'@verdaccio/types': workspace:11.0.0-6-next.9
'@verdaccio/utils': workspace:6.0.0-6-next.9
abortcontroller-polyfill: 1.7.3
@ -1027,6 +1029,8 @@ importers:
lunr: 2.3.9
lunr-mutable-indexes: 2.3.2
merge2: 1.4.1
nock: 13.0.11
node-mocks-http: 1.10.1
semver: 7.3.5
tmp-promise: 3.0.3
undici: 4.7.3
@ -1039,6 +1043,7 @@ importers:
'@verdaccio/logger': link:../logger
'@verdaccio/proxy': link:../proxy
'@verdaccio/streams': link:../core/streams
'@verdaccio/tarball': link:../core/tarball
'@verdaccio/utils': link:../utils
abortcontroller-polyfill: 1.7.3
async: 3.1.1
@ -1051,8 +1056,11 @@ importers:
semver: 7.3.5
devDependencies:
'@types/node': 16.11.11
'@verdaccio/helper': link:../tools/helpers
'@verdaccio/mock': link:../tools/mock
'@verdaccio/types': link:../core/types
nock: 13.0.11
node-mocks-http: 1.10.1
tmp-promise: 3.0.3
undici: 4.7.3
undici-fetch: 1.0.0-rc.4
@ -1179,7 +1187,6 @@ importers:
'@verdaccio/cli': link:../cli
'@verdaccio/hooks': link:../hooks
'@verdaccio/logger': link:../logger
'@verdaccio/mock': link:../tools/mock
'@verdaccio/node-api': link:../node-api
'@verdaccio/ui-theme': link:../plugins/ui-theme
'@verdaccio/utils': link:../utils
@ -1189,6 +1196,7 @@ importers:
'@verdaccio/auth': link:../auth
'@verdaccio/config': link:../config
'@verdaccio/core': link:../core/core
'@verdaccio/mock': link:../tools/mock
'@verdaccio/store': link:../store
fastify: 3.24.1
@ -19586,6 +19594,12 @@ packages:
/safer-buffer/2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
/sanitize-filename/1.6.3:
resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==}
dependencies:
truncate-utf8-bytes: 1.0.2
dev: false
/sass-loader/10.2.0_sass@1.39.0:
resolution: {integrity: sha512-kUceLzC1gIHz0zNJPpqRsJyisWatGYNFRmv2CKZK2/ngMJgLqxTbXwe/hJ85luyvZkgqU3VlJ33UVF2T/0g6mw==}
engines: {node: '>= 10.13.0'}
@ -21226,6 +21240,12 @@ packages:
/trough/1.0.5:
resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==}
/truncate-utf8-bytes/1.0.2:
resolution: {integrity: sha1-QFkjkJWS1W94pYGENLC3hInKXys=}
dependencies:
utf8-byte-length: 1.0.4
dev: false
/ts-essentials/2.0.12:
resolution: {integrity: sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==}
dev: false
@ -21847,6 +21867,10 @@ packages:
resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==}
engines: {node: '>=0.10.0'}
/utf8-byte-length/1.0.4:
resolution: {integrity: sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=}
dev: false
/util-deprecate/1.0.2:
resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=}