0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-03-11 02:15:57 -05:00

feat: improve node-api (#2165)

* refactor: improve node-api

* chore: add test for run server
This commit is contained in:
Juan Picado 2021-04-04 21:13:16 +02:00
parent 9886b93e85
commit 8f43bf17df
31 changed files with 569 additions and 1326 deletions

View file

@ -0,0 +1,28 @@
---
'@verdaccio/cli': major
'@verdaccio/config': major
'@verdaccio/types': major
'@verdaccio/logger': major
'@verdaccio/node-api': major
'verdaccio-google-cloud': major
'verdaccio': major
---
feat: node api new structure based on promise
```js
import { runServer } from '@verdaccio/node-api';
// or
import { runServer } from 'verdaccio';
const app = await runServer(); // default configuration
const app = await runServer('./config/config.yaml');
const app = await runServer({ configuration });
app.listen(4000, (event) => {
// do something
});
```
### Breaking Change
If you are using the node-api, the new structure is Promise based and less arguments.

View file

@ -1,15 +1,13 @@
import { Command, Option } from 'clipanion';
import { ConfigRuntime } from '@verdaccio/types';
import { findConfigFile, parseConfigFile } from '@verdaccio/config';
import { startVerdaccio, listenDefaultCallback } from '@verdaccio/node-api';
import { initServer } from '@verdaccio/node-api';
export const DEFAULT_PROCESS_NAME: string = 'verdaccio';
export class InitCommand extends Command {
static paths = [Command.Default];
listen = Option.String('-l,--listen', {
port = Option.String('-l,-p,--listen,--port', {
description: 'host:port number to listen on (default: localhost:4873)',
});
@ -25,8 +23,8 @@ export class InitCommand extends Command {
The optional arguments are:
- \`--listen\` to switch the default server port,
- \`--config\` to define a different configuration path location,
- \`-l | --listen | -p | --port\` to switch the default server port,
- \`-c | --config\` to define a different configuration path location,
`,
examples: [
@ -44,65 +42,19 @@ export class InitCommand extends Command {
});
async execute() {
let configPathLocation;
let verdaccioConfiguration: ConfigRuntime;
try {
configPathLocation = findConfigFile(this.config as string);
verdaccioConfiguration = parseConfigFile(configPathLocation);
const { web, https } = verdaccioConfiguration;
const configPathLocation = findConfigFile(this.config as string);
const configParsed = parseConfigFile(configPathLocation);
const { web } = configParsed;
process.title = web?.title || DEFAULT_PROCESS_NAME;
if (!https) {
verdaccioConfiguration = Object.assign({}, verdaccioConfiguration, {
https: { enable: false },
});
}
const { version, name } = require('../../package.json');
startVerdaccio(
verdaccioConfiguration,
this.listen as string,
configPathLocation,
version,
name,
listenDefaultCallback
);
await initServer(configParsed, this.port as string, version, name);
} catch (err) {
console.error(err);
process.exit(1);
}
}
}
// export default function initProgram(commander, pkgVersion, pkgName) {
// const cliListener = commander.listen;
// let configPathLocation;
// let verdaccioConfiguration: ConfigRuntime;
// try {
// configPathLocation = findConfigFile(commander.config);
// verdaccioConfiguration = parseConfigFile(configPathLocation);
// const { web, https } = verdaccioConfiguration;
// process.title = web?.title || DEFAULT_PROCESS_NAME;
// if (!https) {
// verdaccioConfiguration = Object.assign({}, verdaccioConfiguration, {
// https: { enable: false },
// });
// }
// // initLogger.warn({file: configPathLocation}, 'config file - @{file}');
// startVerdaccio(
// verdaccioConfiguration,
// cliListener,
// configPathLocation,
// pkgVersion,
// pkgName,
// listenDefaultCallback
// );
// } catch (err) {
// process.exit(1);
// }
// }

View file

@ -28,8 +28,8 @@ const debug = buildDebug('verdaccio:config');
* Find and get the first config file that match.
* @return {String} the config file path
*/
function findConfigFile(configPath: string): string {
if (_.isNil(configPath) === false) {
function findConfigFile(configPath: string | undefined): string {
if (typeof configPath !== 'undefined') {
return Path.resolve(configPath);
}

View file

@ -352,10 +352,9 @@ declare module '@verdaccio/types' {
export type ServerSettingsConf = {
// express-rate-limit settings
rateLimit: RateLimit;
// deprecated
keepAliveTimeout?: number;
//F
publicUrl?: string;
// force http2 if https is defined
http2?: boolean;
};
type URLPrefix = {

View file

@ -74,6 +74,7 @@ export function createLogger(
export function getLogger() {
if (_.isNil(logger)) {
// FIXME: not sure about display here a warning
process.emitWarning('logger is not defined');
return;
}
@ -153,4 +154,6 @@ export function setup(options: LoggerConfig | LoggerConfigItem = [DEFAULT_LOGGER
process.on('SIGQUIT', () => finalHandler(null, 'SIGQUIT'));
process.on('SIGTERM', () => finalHandler(null, 'SIGTERM'));
}
return logger;
}

View file

@ -0,0 +1,5 @@
{
"rules": {
"no-console": "off"
}
}

View file

@ -0,0 +1,8 @@
const { runServer } = require('../build');
(async () => {
const app = await runServer();
app.listen(4000, () => {
console.log('server started');
});
})();

View file

@ -1,5 +1,3 @@
const config = require('../../jest/config');
module.exports = Object.assign({}, config, {
collectCoverage: false,
});
module.exports = Object.assign({}, config, {});

View file

@ -25,7 +25,7 @@
"verdaccio"
],
"engines": {
"node": ">=10",
"node": ">=12",
"npm": ">=6"
},
"scripts": {
@ -43,15 +43,17 @@
"@verdaccio/config": "workspace:6.0.0-alpha.3",
"@verdaccio/cli-ui": "workspace:6.0.0-alpha.3",
"@verdaccio/server": "workspace:6.0.0-6-next.8",
"@verdaccio/logger": "workspace:6.0.0-alpha.3",
"core-js": "^3.6.5",
"debug": "^4.2.0",
"lodash": "^4.17.20",
"selfsigned": "1.10.7"
"lodash": "^4.17.20"
},
"devDependencies": {
"@verdaccio/mock": "workspace:6.0.0-alpha.3",
"@verdaccio/types": "workspace:11.0.0-alpha.3",
"jest-mock-process": "^1.4.0"
"jest-mock-process": "^1.4.0",
"selfsigned": "1.10.7",
"supertest": "^6.1.3"
},
"publishConfig": {
"access": "public"

View file

@ -1,25 +0,0 @@
import { Application } from 'express';
import { Callback } from '@verdaccio/types';
/**
* Trigger the server after configuration has been loaded.
* @param {Object} config
* @param {Object} cliArguments
* @param {String} configPath
* @param {String} pkgVersion
* @param {String} pkgName
*/
declare function startVerdaccio(
config: any,
cliListen: string,
configPath: string,
pkgVersion: string,
pkgName: string,
callback: Callback
): void;
declare function listenDefaultCallback(
webServer: Application,
addr: any,
pkgName: string,
pkgVersion: string
): void;
export { startVerdaccio, listenDefaultCallback };

View file

@ -1,196 +0,0 @@
import URL from 'url';
import fs from 'fs';
import http from 'http';
import https from 'https';
import constants from 'constants';
import { Application } from 'express';
import { assign, isObject, isFunction } from 'lodash';
import buildDebug from 'debug';
import { displayError, displayMessage, displayLink } from '@verdaccio/cli-ui';
import {
ConfigRuntime,
Callback,
ConfigWithHttps,
HttpsConfKeyCert,
HttpsConfPfx,
} from '@verdaccio/types';
import { API_ERROR } from '@verdaccio/commons-api';
import server from '@verdaccio/server';
export const keyPem = 'verdaccio-key.pem';
export const certPem = 'verdaccio-cert.pem';
export const csrPem = 'verdaccio-csr.pem';
import { getListListenAddresses, resolveConfigPath } from './cli-utils';
import { displayExperimentsInfoBox } from './experiments';
const debug = buildDebug('verdaccio:runtime');
function launchServer(
app,
addr,
config,
configPath: string,
pkgVersion: string,
pkgName: string,
callback: Callback
): void {
let webServer;
if (addr.proto === 'https') {
debug('https enabled');
webServer = handleHTTPS(app, configPath, config);
} else {
// http
debug('http enabled');
webServer = http.createServer(app);
}
if (
config.server &&
typeof config.server.keepAliveTimeout !== 'undefined' &&
config.server.keepAliveTimeout !== 'null'
) {
// library definition for node is not up to date (doesn't contain recent 8.0 changes)
webServer.keepAliveTimeout = config.server.keepAliveTimeout * 1000;
}
unlinkAddressPath(addr);
callback(webServer, addr, pkgName, pkgVersion);
}
async function startVerdaccio(
config: ConfigRuntime,
cliListen: string,
configPath: string,
pkgVersion: string,
pkgName: string,
callback: Callback
): Promise<void> {
if (isObject(config) === false) {
throw new Error(API_ERROR.CONFIG_BAD_FORMAT);
}
const app = await server(config);
const addresses = getListListenAddresses(cliListen, config.listen);
displayExperimentsInfoBox(config.flags);
addresses.forEach((addr) =>
launchServer(app, addr, config, configPath, pkgVersion, pkgName, callback)
);
}
function unlinkAddressPath(addr) {
if (addr.path && fs.existsSync(addr.path)) {
fs.unlinkSync(addr.path);
}
}
function logHTTPSError(storageLocation) {
displayError(
[
'You have enabled HTTPS and need to specify either ',
' "https.key" and "https.cert" or ',
' "https.pfx" and optionally "https.passphrase" ',
'to run https server',
'',
// commands are borrowed from node.js docs
'To quickly create self-signed certificate, use:',
' $ openssl genrsa -out ' + resolveConfigPath(storageLocation, keyPem) + ' 2048',
' $ openssl req -new -sha256 -key ' +
resolveConfigPath(storageLocation, keyPem) +
' -out ' +
resolveConfigPath(storageLocation, csrPem),
' $ openssl x509 -req -in ' +
resolveConfigPath(storageLocation, csrPem) +
' -signkey ' +
resolveConfigPath(storageLocation, keyPem) +
' -out ' +
resolveConfigPath(storageLocation, certPem),
'',
'And then add to config file (' + storageLocation + '):',
' https:',
` key: ${resolveConfigPath(storageLocation, keyPem)}`,
` cert: ${resolveConfigPath(storageLocation, certPem)}`,
].join('\n')
);
displayError(displayLink('https://verdaccio.org/docs/en/configuration#https'));
process.exit(2);
}
function handleHTTPS(app: Application, configPath: string, config: ConfigWithHttps): https.Server {
try {
let httpsOptions = {
// disable insecure SSLv2 and SSLv3
secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3,
};
const keyCertConfig = config.https as HttpsConfKeyCert;
const pfxConfig = config.https as HttpsConfPfx;
// https must either have key and cert or a pfx and (optionally) a passphrase
if (!((keyCertConfig.key && keyCertConfig.cert) || pfxConfig.pfx)) {
logHTTPSError(configPath);
process.exit(1);
}
if (pfxConfig.pfx) {
const { pfx, passphrase } = pfxConfig;
httpsOptions = assign(httpsOptions, {
pfx: fs.readFileSync(pfx),
passphrase: passphrase || '',
});
} else {
const { key, cert, ca } = keyCertConfig;
httpsOptions = assign(httpsOptions, {
key: fs.readFileSync(key),
cert: fs.readFileSync(cert),
...(ca && {
ca: fs.readFileSync(ca),
}),
});
}
return https.createServer(httpsOptions, app);
} catch (err) {
displayError(`cannot create server: ${err.message}`);
process.exit(2);
}
}
function listenDefaultCallback(
webServer: Application,
addr: any,
pkgName: string,
pkgVersion: string
): void {
webServer
.listen(addr.port || addr.path, addr.host, (): void => {
// send a message for test
if (isFunction(process.send)) {
process.send({
verdaccio_started: true,
});
}
const addressServer = `${
addr.path
? URL.format({
protocol: 'unix',
pathname: addr.path,
})
: URL.format({
protocol: addr.proto,
hostname: addr.host,
port: addr.port,
pathname: '/',
})
}`;
displayMessage(`http address ${displayLink(addressServer)}`);
displayMessage(`${pkgName} / ${pkgVersion}`);
})
.on('error', function (err): void {
displayError(`cannot create server: ${err.message}`);
process.exit(2);
});
}
export { startVerdaccio, listenDefaultCallback };

View file

@ -1,7 +1,3 @@
import path from 'path';
import { displayLink, displayWarning } from '@verdaccio/cli-ui';
export const DEFAULT_PORT = '4873';
export const DEFAULT_PROTOCOL = 'http';
export const DEFAULT_DOMAIN = 'localhost';
@ -46,10 +42,6 @@ export function parseAddress(urlAddress: any): any {
return null;
}
export const resolveConfigPath = function (storageLocation: string, file: string) {
return path.resolve(path.dirname(storageLocation), file);
};
/**
* Retrieve all addresses defined in the config file.
* Verdaccio is able to listen multiple ports
@ -61,7 +53,7 @@ export const resolveConfigPath = function (storageLocation: string, file: string
- localhost:5557
@return {Array}
*/
export function getListListenAddresses(argListen: string, configListen: any): any {
export function getListListenAddresses(argListen: string | void, configListen: any): any {
// command line || config file || default
let addresses;
if (argListen) {
@ -79,11 +71,11 @@ export function getListListenAddresses(argListen: string, configListen: any): an
const parsedAddr = parseAddress(addr);
if (!parsedAddr) {
displayWarning(
process.emitWarning(
// eslint-disable-next-line max-len
`invalid address - ${addr}, we expect a port (e.g. "4873"), host:port (e.g. "localhost:4873") or full url '(e.g. "http://localhost:4873/")`
);
displayWarning(displayLink('https://verdaccio.org/docs/en/configuration#listen-port'));
process.emitWarning('https://verdaccio.org/docs/en/configuration#listen-port');
}
return parsedAddr;

View file

@ -1 +1 @@
export { listenDefaultCallback, startVerdaccio } from './bootstrap';
export { initServer, runServer } from './server';

View file

@ -0,0 +1,186 @@
/* eslint-disable */
import _, { assign, isFunction } from 'lodash';
import http from 'http';
import https from 'https';
import constants from 'constants';
import buildDebug from 'debug';
import fs from 'fs';
import url from 'url';
import { findConfigFile, parseConfigFile } from '@verdaccio/config';
import { API_ERROR } from '@verdaccio/commons-api';
import { ConfigRuntime, HttpsConfKeyCert, HttpsConfPfx } from '@verdaccio/types';
import { setup } from '@verdaccio/logger';
import server from '@verdaccio/server';
import { getListListenAddresses } from './cli-utils';
import { displayExperimentsInfoBox } from './experiments';
const debug = buildDebug('verdaccio:node-api');
function unlinkAddressPath(addr) {
if (addr.path && fs.existsSync(addr.path)) {
fs.unlinkSync(addr.path);
}
}
/**
* Return a native HTTP/HTTPS server instance
* @param config
* @param addr
* @param app
*/
export function createServerFactory(config: ConfigRuntime, addr, app) {
let serverFactory;
if (addr.proto === 'https') {
debug('https enabled');
try {
let httpsOptions = {
// disable insecure SSLv2 and SSLv3
secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3,
};
const keyCertConfig = config.https as HttpsConfKeyCert;
const pfxConfig = config.https as HttpsConfPfx;
// https must either have key and cert or a pfx and (optionally) a passphrase
if (!((keyCertConfig.key && keyCertConfig.cert) || pfxConfig.pfx)) {
// logHTTPSError(configPath);
throw Error('bad format https configuration');
}
if (pfxConfig.pfx) {
const { pfx, passphrase } = pfxConfig;
httpsOptions = assign(httpsOptions, {
pfx: fs.readFileSync(pfx),
passphrase: passphrase || '',
});
} else {
const { key, cert, ca } = keyCertConfig;
httpsOptions = assign(httpsOptions, {
key: fs.readFileSync(key),
cert: fs.readFileSync(cert),
...(ca && {
ca: fs.readFileSync(ca),
}),
});
}
// TODO: enable http2 as feature
// if (config.server.http2) <-- check if force http2
serverFactory = https.createServer(httpsOptions, app);
} catch (err) {
throw new Error(`cannot create https server: ${err.message}`);
}
} else {
// http
debug('http enabled');
serverFactory = http.createServer(app);
}
if (
config.server &&
typeof config.server.keepAliveTimeout !== 'undefined' &&
// @ts-ignore
config.server.keepAliveTimeout !== 'null'
) {
// library definition for node is not up to date (doesn't contain recent 8.0 changes)
serverFactory.keepAliveTimeout = config.server.keepAliveTimeout * 1000;
}
// FIXE: I could not find the reason of this code.
unlinkAddressPath(addr);
return serverFactory;
}
/**
* Start the server on the port defined
* @param config
* @param port
* @param version
* @param pkgName
*/
export async function initServer(
config: ConfigRuntime,
port: string | void,
version: string,
pkgName: string
): Promise<void> {
return new Promise(async (resolve, reject) => {
// FIXME: get only the first match, the multiple address will be removed
const [addr] = getListListenAddresses(port, config.listen);
const logger = setup((config as ConfigRuntime).logs);
displayExperimentsInfoBox(config.flags);
const app = await server(config);
const serverFactory = createServerFactory(config, addr, app);
serverFactory
.listen(addr.port || addr.path, addr.host, (): void => {
// send a message for test
if (isFunction(process.send)) {
process.send({
verdaccio_started: true,
});
}
const addressServer = `${
addr.path
? url.format({
protocol: 'unix',
pathname: addr.path,
})
: url.format({
protocol: addr.proto,
hostname: addr.host,
port: addr.port,
pathname: '/',
})
}`;
console.log(`http address ${addressServer}`);
console.log(`${pkgName} / ${version}`);
resolve();
})
.on('error', function (err): void {
reject(err);
process.exitCode = 1;
});
function handleShutdownGracefully() {
logger.fatal('received shutdown signal - closing server gracefully...');
serverFactory.close(() => {
logger.info('server closed.');
process.exit(0);
});
}
process.on('SIGINT', handleShutdownGracefully);
process.on('SIGTERM', handleShutdownGracefully);
process.on('SIGHUP', handleShutdownGracefully);
});
}
/**
* Exposes a server factory to be instantiated programmatically.
*
const app = await runServer(); // default configuration
const app = await runServer('./config/config.yaml');
const app = await runServer({ configuration });
app.listen(4000, (event) => {
// do something
});
* @param config
*/
export async function runServer(config?: string | ConfigRuntime): Promise<any> {
let configurationParsed: ConfigRuntime;
if (config === undefined || typeof config === 'string') {
const configPathLocation = findConfigFile(config);
configurationParsed = parseConfigFile(configPathLocation);
} else if (_.isObject(config)) {
configurationParsed = config;
} else {
throw new Error(API_ERROR.CONFIG_BAD_FORMAT);
}
setup(configurationParsed.logs);
displayExperimentsInfoBox(configurationParsed.flags);
// FIXME: get only the first match, the multiple address will be removed
const [addr] = getListListenAddresses(undefined, configurationParsed.listen);
const app = await server(configurationParsed);
return createServerFactory(configurationParsed, addr, app);
}

View file

@ -1,183 +0,0 @@
import path from 'path';
import os from 'os';
import fs from 'fs';
import selfsigned from 'selfsigned';
import { configExample } from '@verdaccio/mock';
import { parseConfigFile } from '@verdaccio/config';
import { startVerdaccio } from '../src';
import { DEFAULT_DOMAIN, DEFAULT_PROTOCOL } from '../src/cli-utils';
const mockProcess = require('jest-mock-process');
describe('startServer via API', () => {
const parseConfigurationFile = (name) => {
return parseConfigFile(path.join(__dirname, `./partials/config/yaml/${name}.yaml`));
};
describe('startServer launcher', () => {
test('should provide all HTTP server data', async (done) => {
const store = path.join(__dirname, 'partials/store');
const serverName = 'verdaccio-test';
const version = '1.0.0';
const port = '6000';
await startVerdaccio(
configExample(),
port,
store,
version,
serverName,
(webServer, addrs, pkgName, pkgVersion) => {
expect(webServer).toBeDefined();
expect(addrs).toBeDefined();
expect(addrs.proto).toBe(DEFAULT_PROTOCOL);
expect(addrs.host).toBe(DEFAULT_DOMAIN);
expect(addrs.port).toBe(port);
expect(pkgName).toBeDefined();
expect(pkgVersion).toBeDefined();
expect(pkgVersion).toBe(version);
expect(pkgName).toBe(serverName);
done();
}
);
});
test('should set keepAliveTimeout to 0 seconds', async (done) => {
const store = path.join(__dirname, 'partials/store');
const serverName = 'verdaccio-test';
const version = '1.0.0';
const port = '6100';
await startVerdaccio(
configExample(parseConfigurationFile('server/keepalivetimeout-0')),
port,
store,
version,
serverName,
(webServer, addrs, pkgName, pkgVersion) => {
expect(webServer).toBeDefined();
expect(webServer.keepAliveTimeout).toBeDefined();
expect(webServer.keepAliveTimeout).toBe(0);
expect(addrs).toBeDefined();
expect(addrs.proto).toBe(DEFAULT_PROTOCOL);
expect(addrs.host).toBe(DEFAULT_DOMAIN);
expect(addrs.port).toBe(port);
expect(pkgName).toBeDefined();
expect(pkgVersion).toBeDefined();
expect(pkgVersion).toBe(version);
expect(pkgName).toBe(serverName);
done();
}
);
});
test('should set keepAliveTimeout to 60 seconds', async (done) => {
const store = path.join(__dirname, 'partials/store');
const serverName = 'verdaccio-test';
const version = '1.0.0';
const port = '6200';
await startVerdaccio(
configExample(parseConfigurationFile('server/keepalivetimeout-60')),
port,
store,
version,
serverName,
(webServer, addrs, pkgName, pkgVersion) => {
expect(webServer).toBeDefined();
expect(webServer.keepAliveTimeout).toBeDefined();
expect(webServer.keepAliveTimeout).toBe(60000);
expect(addrs).toBeDefined();
expect(addrs.proto).toBe(DEFAULT_PROTOCOL);
expect(addrs.host).toBe(DEFAULT_DOMAIN);
expect(addrs.port).toBe(port);
expect(pkgName).toBeDefined();
expect(pkgVersion).toBeDefined();
expect(pkgVersion).toBe(version);
expect(pkgName).toBe(serverName);
done();
}
);
});
test('should set keepAliveTimeout to 5 seconds per default', async (done) => {
const store = path.join(__dirname, 'partials/store');
const serverName = 'verdaccio-test';
const version = '1.0.0';
const port = '6300';
await startVerdaccio(
configExample(parseConfigurationFile('server/keepalivetimeout-undefined')),
port,
store,
version,
serverName,
(webServer, addrs, pkgName, pkgVersion) => {
expect(webServer).toBeDefined();
expect(webServer.keepAliveTimeout).toBeDefined();
expect(webServer.keepAliveTimeout).toBe(5000);
expect(addrs).toBeDefined();
expect(addrs.proto).toBe(DEFAULT_PROTOCOL);
expect(addrs.host).toBe(DEFAULT_DOMAIN);
expect(addrs.port).toBe(port);
expect(pkgName).toBeDefined();
expect(pkgVersion).toBeDefined();
expect(pkgVersion).toBe(version);
expect(pkgName).toBe(serverName);
done();
}
);
});
test('should provide all HTTPS server fails', async (done) => {
let mockExit = mockProcess.mockProcessExit();
const store = path.join(__dirname, 'partials/store');
const serverName = 'verdaccio-test';
const version = '1.0.0';
const address = 'https://www.domain.com:443';
const conf = configExample({});
conf.https = {};
// save process to catch exist
await startVerdaccio(conf, address, store, version, serverName, () => {
expect(mockExit).toHaveBeenCalledWith(2);
done();
});
});
test('should start a https server with key and cert', async (done) => {
const store = path.join(__dirname, 'partials/store');
const serverName = 'verdaccio-test';
const version = '1.0.0';
const address = 'https://www.domain.com:443';
const { private: key, cert } = selfsigned.generate();
const keyPath = path.join(os.tmpdir(), 'key.pem');
const certPath = path.join(os.tmpdir(), 'crt.pem');
fs.writeFileSync(keyPath, key);
fs.writeFileSync(certPath, cert);
const conf = configExample();
conf.https = {
key: keyPath,
cert: certPath,
};
await startVerdaccio(conf, address, store, version, serverName, (webServer, addrs) => {
expect(webServer).toBeDefined();
expect(addrs).toBeDefined();
expect(addrs.proto).toBe('https');
done();
});
});
test('should fails if config is missing', async () => {
try {
// @ts-ignore
await startVerdaccio();
} catch (e) {
expect(e.message).toEqual('config file must be an object');
}
});
});
});

View file

@ -0,0 +1,20 @@
import request from 'supertest';
import { runServer } from '../src';
describe('startServer via API', () => {
test('should provide all HTTP server data', async () => {
const webServer = await runServer();
expect(webServer).toBeDefined();
await request(webServer).get('/').expect(200);
});
test('should fail on start with empty configuration', async () => {
// @ts-expect-error
await expect(runServer({})).rejects.toThrow(
'AssertionError [ERR_ASSERTION]: CONFIG: storage path not defined'
);
});
test('should fail on start with null as entry', async () => {
await expect(runServer(null)).rejects.toThrow('config file must be an object');
});
});

View file

@ -1,7 +1,7 @@
import _ from 'lodash';
import { Logger, ILocalPackageManager } from '@verdaccio/types';
import { VerdaccioError } from '@verdaccio/commons-api';
import { HTTP_STATUS } from '@verdaccio/commons-api/lib';
import { HTTP_STATUS } from '@verdaccio/commons-api';
import { ERROR_MISSING_CONFIG } from '../src/data-storage';
import { VerdaccioConfigGoogleStorage } from '../src/types';

View file

@ -1,3 +1 @@
// @verdaccio-cli is only accesible via .bin/ folder
export { listenDefaultCallback, startVerdaccio } from '@verdaccio/node-api';
export { runServer } from '@verdaccio/node-api';

530
pnpm-lock.yaml generated
View file

@ -101,7 +101,7 @@ importers:
supertest: 4.0.2
ts-node: 9.1.1_typescript@4.1.3
typescript: 4.1.3
verdaccio: 5.0.0-alpha.4
verdaccio: 5.0.0-alpha.5
verdaccio-audit: link:packages/plugins/audit
verdaccio-auth-memory: link:packages/plugins/auth-memory
verdaccio-htpasswd: link:packages/core/htpasswd
@ -579,19 +579,22 @@ importers:
'@verdaccio/cli-ui': link:../core/cli-ui
'@verdaccio/commons-api': link:../core/commons-api
'@verdaccio/config': link:../config
'@verdaccio/logger': link:../logger
'@verdaccio/server': link:../server
core-js: 3.6.5
debug: 4.2.0
lodash: 4.17.20
selfsigned: 1.10.7
devDependencies:
'@verdaccio/mock': link:../mock
'@verdaccio/types': link:../core/types
jest-mock-process: 1.4.0
selfsigned: 1.10.7
supertest: 6.1.3
specifiers:
'@verdaccio/cli-ui': workspace:6.0.0-alpha.3
'@verdaccio/commons-api': workspace:11.0.0-alpha.3
'@verdaccio/config': workspace:6.0.0-alpha.3
'@verdaccio/logger': workspace:6.0.0-alpha.3
'@verdaccio/mock': workspace:6.0.0-alpha.3
'@verdaccio/server': workspace:6.0.0-6-next.8
'@verdaccio/types': workspace:11.0.0-alpha.3
@ -600,6 +603,7 @@ importers:
jest-mock-process: ^1.4.0
lodash: ^4.17.20
selfsigned: 1.10.7
supertest: ^6.1.3
packages/plugins/active-directory:
dependencies:
'@verdaccio/commons-api': link:../../core/commons-api
@ -7649,57 +7653,267 @@ packages:
graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0
resolution:
integrity: sha512-e4IXXQ4nes3KyusgYV925DuzfDAfo4ex7Ls3tZfOExkxEcXh0i0XnizXp0rvZmWRch69YCkc+Lh1Gy2aY49HTQ==
/@verdaccio/commons-api/10.0.0:
/@verdaccio/api/5.0.0-alpha.4:
dependencies:
'@verdaccio/auth': 5.0.0-alpha.3
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/config': 5.0.0-alpha.3
'@verdaccio/hooks': 5.0.0-alpha.3
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/middleware': 5.0.0-alpha.3
'@verdaccio/store': 5.0.0-alpha.4
'@verdaccio/utils': 5.0.0-alpha.3
cookies: 0.8.0
debug: 4.3.1
express: 4.17.1
lodash: 4.17.21
mime: 2.4.4
semver: 7.3.2
dev: true
resolution:
integrity: sha512-i7jc7cuPaRJTEPgAjd5MJx8EzFj3XJrldr/uSEzi0dNlAogozuB3RxJCnUIE2VoaWe/HdoBU1KoSPvcOyxXBbg==
/@verdaccio/auth/5.0.0-alpha.3:
dependencies:
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/config': 5.0.0-alpha.3
'@verdaccio/loaders': 5.0.0-alpha.3
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/utils': 5.0.0-alpha.3
debug: 4.3.1
express: 4.17.1
jsonwebtoken: 8.5.1
lodash: 4.17.15
dev: true
resolution:
integrity: sha512-wDu+2Ge0fECVTvFJllZE6Vvz00DvkUc2/s5gA1XV3Tw+FRP6jI7V25q+qJolzkf8X9hXjb0UDYxV0jt0pan/DA==
/@verdaccio/cli/5.0.0-alpha.4:
dependencies:
'@verdaccio/config': 5.0.0-alpha.3
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/node-api': 5.0.0-alpha.4
commander: 6.2.0
envinfo: 7.4.0
kleur: 3.0.3
semver: 7.3.2
dev: true
hasBin: true
resolution:
integrity: sha512-xIxAn5odTphACluPrTrc2poCsI1fnwZ3dcWkCvw1y3aFqxj7ECo/SvHBNribc9h5fPkK8Wp4iGBtX6oAVvq91g==
/@verdaccio/commons-api/10.0.0-alpha.3:
dependencies:
http-errors: 1.8.0
http-status-codes: 1.4.0
dev: true
engines:
node: '>=8'
node: '>=10'
resolution:
integrity: sha512-UC8wrRI9FvqjfDeB1RijF7aVI0JJhCOI8RkEDibCT/JD8zVngphrNmgSWcjo8Es3lRiu7NugWXDSuggCCeCfUg==
/@verdaccio/file-locking/10.0.0:
integrity: sha512-P3JR94/ogwNxyLy2f+2MpVQmhV1Ska+9af7dRsaKUQY1uRfxUneyICEBbBOAtcjhuu+Ih+CNz6t1P7o7THmiTw==
/@verdaccio/config/5.0.0-alpha.3:
dependencies:
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/utils': 5.0.0-alpha.3
debug: 4.3.1
js-yaml: 3.14.0
lodash: 4.17.21
minimatch: 3.0.4
mkdirp: 0.5.5
yup: 0.29.3
dev: true
resolution:
integrity: sha512-E/x1VmGsqKPEFZ4xnxLK4+O7PiSibLz2H9+D+eBXidcga0zHpo6jvzdILhU4wCN2ZCluUoK9vhvNgsyGFl9fQw==
/@verdaccio/file-locking/10.0.0-alpha.3:
dependencies:
lockfile: 1.0.4
dev: true
engines:
node: '>=8'
resolution:
integrity: sha512-2tQUbJF3tQ3CY9grAlpovaF/zu8G56CBYMaeHwMBHo9rAmsJI9i7LfliHGS6Jygbs8vd0cOCPT7vl2CL9T8upw==
/@verdaccio/local-storage/10.0.1:
integrity: sha512-4HaHURZSSFcEPOCHudKdXB2j4vo7aAaWhlHnSqLNaTTnKdUltPbbJwXOacbduMnSBAJO19MMYq8xaToa30eNjQ==
/@verdaccio/hooks/5.0.0-alpha.3:
dependencies:
'@verdaccio/commons-api': 10.0.0
'@verdaccio/file-locking': 10.0.0
'@verdaccio/streams': 10.0.0
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/logger': 5.0.0-alpha.3
debug: 4.3.1
handlebars: 4.5.3
node-fetch: 2.6.1
request: 2.87.0
dev: true
resolution:
integrity: sha512-LAjkVNjsomYSSygMds1tnCFmqNKvsEGwlmi4Z/vKItp8dhml9OauAvcENVJo3FY8OmfYSNiYx+0kiXYaPNBWYA==
/@verdaccio/loaders/5.0.0-alpha.3:
dependencies:
'@verdaccio/logger': 5.0.0-alpha.3
debug: 4.3.1
lodash: 4.17.15
dev: true
resolution:
integrity: sha512-aa+7+DuOl5za8iP02OiOd7Pc2L3vEudyhrFNnYM7t052BPk7WD0MWv8ZOdy0Dbm+2xUbW0E/My67Lpf5vJkBUQ==
/@verdaccio/local-storage/10.0.0-alpha.4:
dependencies:
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/file-locking': 10.0.0-alpha.3
'@verdaccio/streams': 10.0.0-alpha.3
async: 3.2.0
debug: 4.3.1
lodash: 4.17.21
lowdb: 1.0.0
mkdirp: 1.0.4
mkdirp: 0.5.5
dev: true
engines:
node: '>=8'
node: '>=10'
resolution:
integrity: sha512-dnrBZeuftSFjtQhp7Y+abbWPtM1luxEhP5+6152d8dMnNmomTMZWJcr/eUwKkw6o9d39d4NA4Pimm9bXEBGrdA==
/@verdaccio/readme/10.0.0:
integrity: sha512-I4k301LweTtJ03NgIH3ZSBmJNm9g0Ud0OjEyea43mOBdN5FZ5kgbxEhe6uRTxsGR8Zj0XYqwPU3x43WDySJPoQ==
/@verdaccio/logger-prettify/5.0.0-alpha.3:
dependencies:
dompurify: 2.2.7
'@verdaccio/commons-api': 10.0.0-alpha.3
dayjs: 1.8.36
fast-safe-stringify: 2.0.7
kleur: 3.0.3
lodash: 4.17.20
pad-left: 2.1.0
pad-right: 0.2.2
prettier-bytes: 1.0.4
pretty-ms: 5.1.0
dev: true
resolution:
integrity: sha512-V6I8YgFTEyTdkqAu8+ZbCbtmEfHwcHHouKmQKd9DJ1NLg/z+adAuXWbbmcH1BXKCsdsyKJwmSZb6Hh/o+wHA1Q==
/@verdaccio/logger/5.0.0-alpha.3:
dependencies:
'@verdaccio/logger-prettify': 5.0.0-alpha.3
debug: 4.3.1
lodash: 4.17.21
pino: 6.11.2
dev: true
resolution:
integrity: sha512-lGGusOrcxl1GwlQBI26baYJwxR5sVSxEFYba4Oz4Jgnza6lnF8zLfTn6Ij8RpYlfKkxYDmaTzKDDx6Q5NUp/cA==
/@verdaccio/middleware/5.0.0-alpha.3:
dependencies:
'@verdaccio/auth': 5.0.0-alpha.3
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/utils': 5.0.0-alpha.3
lodash: 4.17.15
dev: true
resolution:
integrity: sha512-QIbVh958nfaLL5cjihjq3P5hSYTZqsCtaIoMn+Sv3iv0DaFrsMNxns6YDdJzfOTjhxHODnPIrjM6pRLLWa1X7w==
/@verdaccio/mock/5.0.0-alpha.3:
dependencies:
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/config': 5.0.0-alpha.3
'@verdaccio/utils': 5.0.0-alpha.3
debug: 4.3.1
fs-extra: 8.1.0
lodash: 4.17.21
request: 2.87.0
supertest: 4.0.2
dev: true
resolution:
integrity: sha512-FhniH1OV5c+3RFj1UoSF+kQtPAwYfIyGt75MforClzTzr3CBAy4+jyT1AcGel6Dn/724dO3NwDlHulcOoQmWkg==
/@verdaccio/node-api/5.0.0-alpha.4:
dependencies:
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/config': 5.0.0-alpha.3
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/server': 5.0.0-alpha.4
core-js: 3.8.3
debug: 4.3.1
lodash: 4.17.21
selfsigned: 1.10.7
dev: true
resolution:
integrity: sha512-cHmMVHfCaklZm7am8D8SQkPelNqC85fBSbfAtYhJVZu0ReQIeMrxZ9zGJldPtaeK0E3h8r4TeTbbCRyZGZSeew==
/@verdaccio/proxy/5.0.0-alpha.4:
dependencies:
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/config': 5.0.0-alpha.3
'@verdaccio/local-storage': 10.0.0-alpha.4
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/streams': 10.0.0-alpha.3
'@verdaccio/utils': 5.0.0-alpha.3
JSONStream: 1.3.5
lodash: 4.17.21
request: 2.87.0
dev: true
resolution:
integrity: sha512-hWKAsy4N/KhJwVY0zCPtywlGBWa0L3Vmk8bRbqTrh5lmf6DBoKeSqR50FyK3nQDZ86HvQ4Nqh5TuBYX52b8eRw==
/@verdaccio/readme/10.0.0-alpha.3:
dependencies:
dompurify: 2.0.8
jsdom: 15.2.1
marked: 2.0.1
marked: 1.1.1
dev: true
resolution:
integrity: sha512-OD3dMnRC8SvhgytEzczMBleN+K/3lMqyWw/epeXvolCpCd7mW/Dl5zSR25GiHh/2h3eTKP/HMs4km8gS1MMLgA==
/@verdaccio/streams/10.0.0:
dev: true
engines:
node: '>=8'
npm: '>=5'
resolution:
integrity: sha512-PqxxY11HhweN6z1lwfn9ydLCdnOkCPpthMZs+SGCDz8Rt6gOyrjJVslV7o4uobDipjD9+hUPpJHDeO33Qt24uw==
/@verdaccio/ui-theme/3.0.0:
integrity: sha512-V+FeAd07bnYXUz6wOpHLGjO3EZPWXaKlurHC9W6jI9oauFW/iMaorA4EggiQ8Z9X3tyA0oC4V78a5FfcQ27uMQ==
/@verdaccio/server/5.0.0-alpha.4:
dependencies:
'@verdaccio/api': 5.0.0-alpha.4
'@verdaccio/auth': 5.0.0-alpha.3
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/config': 5.0.0-alpha.3
'@verdaccio/loaders': 5.0.0-alpha.3
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/middleware': 5.0.0-alpha.3
'@verdaccio/store': 5.0.0-alpha.4
'@verdaccio/utils': 5.0.0-alpha.3
'@verdaccio/web': 5.0.0-alpha.4
compression: 1.7.4
cors: 2.8.5
express: 4.17.1
express-rate-limit: 5.2.3
lodash: 4.17.15
dev: true
resolution:
integrity: sha512-fp3vgkcZlC/4+ilNavywTddJj2nJcDTHjIq3subz3cUMIiLSiFAwm65pLsRyHjPPRy7GtQZPNQ2vEBIrYMG5Vw==
integrity: sha512-shbeApfZaNS054CxfTcsnRSoecfd6VdSloV05nOtTGAVtmUsdVu4BVZh7PvAJ2EZu9s0rdLTdU+coZuK36Atyw==
/@verdaccio/store/5.0.0-alpha.4:
dependencies:
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/config': 5.0.0-alpha.3
'@verdaccio/loaders': 5.0.0-alpha.3
'@verdaccio/local-storage': 10.0.0-alpha.4
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/proxy': 5.0.0-alpha.4
'@verdaccio/streams': 10.0.0-alpha.3
'@verdaccio/utils': 5.0.0-alpha.3
async: 3.1.1
debug: 4.3.1
lodash: 4.17.15
lunr-mutable-indexes: 2.3.2
semver: 7.1.2
dev: true
resolution:
integrity: sha512-wvyoqQa7Ia0LWrOheqYwY7v/JzVwpnCz1zYjQAmiukbPNik2vORa+qP9NpXkusVvXL1kba3tzNdGl8h0pSDhMQ==
/@verdaccio/streams/10.0.0-alpha.3:
dev: true
resolution:
integrity: sha512-f5FFWWDPhNZQFcBQ99hu2GsECvLKfX/wmwB3gqibvn62AteHRY2nRE2i7oIIL3NKItKPr15Aql0ZDzseNs64Zg==
/@verdaccio/ui-theme/5.0.0-alpha.4:
dev: true
resolution:
integrity: sha512-Q7j4JovDLmnC/P3ok8AYdk9I48lCRCuiXCwDd7PBu3XPA8v5Xg42TCLpNjX94WkPVWL8O6gtCf2X/OFjI+rvNQ==
/@verdaccio/utils/5.0.0-alpha.3:
dependencies:
'@verdaccio/commons-api': 10.0.0-alpha.3
semver: 7.3.2
dev: true
resolution:
integrity: sha512-CZLm4hgxwUEquGLcKcO4Fqhh321XFKvT0DIfdi+Hce6wUjKNokl9//PsYoIMSZbGQABAkSwlhqA4QUvxT/t9Ag==
/@verdaccio/web/5.0.0-alpha.4:
dependencies:
'@verdaccio/auth': 5.0.0-alpha.3
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/config': 5.0.0-alpha.3
'@verdaccio/loaders': 5.0.0-alpha.3
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/middleware': 5.0.0-alpha.3
'@verdaccio/readme': 10.0.0-alpha.3
'@verdaccio/store': 5.0.0-alpha.4
'@verdaccio/utils': 5.0.0-alpha.3
body-parse: 0.1.0
body-parser: 1.19.0
debug: 4.3.1
express: 4.17.1
lodash: 4.17.21
dev: true
resolution:
integrity: sha512-rrJtQyji5N6v5tYJdQEhdCsInAOTlWwaGE7RaLCzK7oXuTEeFK8fRS0jTKx3whdr/P+oVAKTGXYMnx4w30neBQ==
/@webassemblyjs/ast/1.11.0:
dependencies:
'@webassemblyjs/helper-numbers': 1.11.0
@ -8527,10 +8741,6 @@ packages:
sprintf-js: 1.0.3
resolution:
integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
/argparse/2.0.1:
dev: true
resolution:
integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
/argv/0.0.2:
dev: true
engines:
@ -8784,7 +8994,6 @@ packages:
resolution:
integrity: sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
/async/3.1.1:
dev: false
resolution:
integrity: sha512-X5Dj8hK1pJNC2Wzo2Rcp9FBVdJMGRR/S7V+lH46s8GVFhtbo5O4Le5GECCF/8PISVdkUA6mMPvgz7qTTD1rf1g==
/async/3.2.0:
@ -8855,10 +9064,6 @@ packages:
/aws4/1.10.1:
resolution:
integrity: sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==
/aws4/1.11.0:
dev: true
resolution:
integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
/axe-core/3.5.5:
dev: false
engines:
@ -9458,7 +9663,6 @@ packages:
resolution:
integrity: sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
/body-parse/0.1.0:
dev: false
resolution:
integrity: sha512-k0PDF7vZZpspXlwoM8ywh9PIHZokooS0Rek4M8Vekoro7XuuaWVhjgTpdzIRrfKj5oLQahwjn621/4kG4d91xw==
/body-parser/1.19.0:
@ -10385,6 +10589,7 @@ packages:
/clipanion/3.0.0-rc.11:
dependencies:
typanion: 3.3.0
dev: false
resolution:
integrity: sha512-e0GyZXjprnxRuls/pHH0cqAgKtpiceQy8PztEZP9fdnkMxuo05D5en9fx60Iiqqjge8pmrMfsiglueS8SWmlgg==
/clipboard/2.0.6:
@ -11614,12 +11819,7 @@ packages:
dev: true
resolution:
integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
/dayjs/1.10.4:
dev: true
resolution:
integrity: sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw==
/dayjs/1.8.36:
dev: false
resolution:
integrity: sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==
/dayjs/1.9.7:
@ -12202,13 +12402,8 @@ packages:
resolution:
integrity: sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==
/dompurify/2.0.8:
dev: false
resolution:
integrity: sha512-vIOSyOXkMx81ghEalh4MLBtDHMx1bhKlaqHDMqM2yeitJ996SLOk5mGdDpI9ifJAgokred8Rmu219fX4OltqXw==
/dompurify/2.2.7:
dev: true
resolution:
integrity: sha512-jdtDffdGNY+C76jvodNTu9jt5yYj59vuTUyx+wXdzcSwAGTYZDAQkQ7Iwx9zcGrA4ixC1syU4H3RZROqRxokxg==
/domutils/1.5.1:
dependencies:
dom-serializer: 0.1.1
@ -12568,7 +12763,6 @@ packages:
resolution:
integrity: sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
/envinfo/7.4.0:
dev: false
engines:
node: '>=4'
hasBin: true
@ -12580,13 +12774,6 @@ packages:
hasBin: true
resolution:
integrity: sha512-46+j5QxbPWza0PB1i15nZx0xQ4I/EfQxg9J8Had3b408SV63nEtor2e+oiY63amTo9KTuh2a3XLObNwduxYwwA==
/envinfo/7.7.4:
dev: true
engines:
node: '>=4'
hasBin: true
resolution:
integrity: sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ==
/eol/0.9.1:
dev: false
resolution:
@ -12740,15 +12927,6 @@ packages:
dev: true
resolution:
integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
/es6-weak-map/2.0.3:
dependencies:
d: 1.0.1
es5-ext: 0.10.53
es6-iterator: 2.0.3
es6-symbol: 3.1.3
dev: true
resolution:
integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==
/escalade/3.0.2:
engines:
node: '>=6'
@ -13324,13 +13502,6 @@ packages:
node: '>= 0.6'
resolution:
integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
/event-emitter/0.3.5:
dependencies:
d: 1.0.1
es5-ext: 0.10.53
dev: true
resolution:
integrity: sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=
/event-source-polyfill/1.0.17:
dev: false
resolution:
@ -13571,7 +13742,6 @@ packages:
resolution:
integrity: sha512-wccd9Lb6oeJ8yHpUs/8LcnGjFUUQYmOG9A5BNLybRdCzGw0PeUrtBxsIR8bfiur6uSW4OvPkVDoYH06z6/N9+w==
/express-rate-limit/5.2.3:
dev: false
resolution:
integrity: sha512-cjQH+oDrEPXxc569XvxhHC6QXqJiuBT6BhZ70X3bdAImcnHnTNMVuMAJaT0TXPoRiEErUrVPRcOTpZpM36VbOQ==
/express/4.17.1:
@ -14112,7 +14282,6 @@ packages:
resolution:
integrity: sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=
/fn-name/3.0.0:
dev: false
engines:
node: '>=8'
resolution:
@ -15372,6 +15541,8 @@ packages:
minimatch: 3.0.4
once: 1.4.0
path-is-absolute: 1.0.1
dev: false
optional: true
resolution:
integrity: sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=
/glob/7.1.6:
@ -15829,7 +16000,6 @@ packages:
neo-async: 2.6.2
optimist: 0.6.1
source-map: 0.6.1
dev: false
engines:
node: '>=0.4.7'
hasBin: true
@ -15851,20 +16021,6 @@ packages:
uglify-js: 3.12.4
resolution:
integrity: sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==
/handlebars/4.7.7:
dependencies:
minimist: 1.2.5
neo-async: 2.6.2
source-map: 0.6.1
wordwrap: 1.0.0
dev: true
engines:
node: '>=0.4.7'
hasBin: true
optionalDependencies:
uglify-js: 3.12.4
resolution:
integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
/har-schema/2.0.0:
engines:
node: '>=4'
@ -18163,13 +18319,6 @@ packages:
hasBin: true
resolution:
integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
/js-yaml/4.0.0:
dependencies:
argparse: 2.0.1
dev: true
hasBin: true
resolution:
integrity: sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==
/jsbn/0.1.1:
resolution:
integrity: sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
@ -18972,7 +19121,6 @@ packages:
resolution:
integrity: sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==
/lodash-es/4.17.15:
dev: false
resolution:
integrity: sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
/lodash._reinterpolate/3.0.0:
@ -19259,12 +19407,6 @@ packages:
node: '>=10'
resolution:
integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
/lru-queue/0.1.0:
dependencies:
es5-ext: 0.10.53
dev: true
resolution:
integrity: sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=
/lunr-mutable-indexes/2.3.2:
dependencies:
lunr: 2.3.9
@ -19367,19 +19509,11 @@ packages:
resolution:
integrity: sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==
/marked/1.1.1:
dev: false
engines:
node: '>= 8.16.2'
hasBin: true
resolution:
integrity: sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw==
/marked/2.0.1:
dev: true
engines:
node: '>= 8.16.2'
hasBin: true
resolution:
integrity: sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw==
/matcher/1.1.1:
dependencies:
escape-string-regexp: 1.0.5
@ -19548,19 +19682,6 @@ packages:
node: '>= 4.0.0'
resolution:
integrity: sha512-f/xxz2TpdKv6uDn6GtHee8ivFyxwxmPuXatBb1FBwxYNuVpbM3k/Y1Z+vC0mH/dIXXrukYfe3qe5J32Dfjg93A==
/memoizee/0.4.15:
dependencies:
d: 1.0.1
es5-ext: 0.10.53
es6-weak-map: 2.0.3
event-emitter: 0.3.5
is-promise: 2.2.2
lru-queue: 0.1.0
next-tick: 1.1.0
timers-ext: 0.1.7
dev: true
resolution:
integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==
/memory-fs/0.4.1:
dependencies:
errno: 0.1.7
@ -19780,7 +19901,6 @@ packages:
resolution:
integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
/mime/2.4.4:
dev: false
engines:
node: '>=4.0.0'
hasBin: true
@ -19916,7 +20036,6 @@ packages:
resolution:
integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==
/minimist/0.0.10:
dev: false
resolution:
integrity: sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
/minimist/0.2.1:
@ -20077,8 +20196,10 @@ packages:
mkdirp: 0.5.5
ncp: 2.0.0
rimraf: 2.4.5
dev: false
engines:
node: '>=0.8.0'
optional: true
resolution:
integrity: sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=
/name-all-modules-plugin/1.0.1:
@ -20123,7 +20244,9 @@ packages:
resolution:
integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
/ncp/2.0.0:
dev: false
hasBin: true
optional: true
resolution:
integrity: sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
/negotiator/0.6.2:
@ -20139,6 +20262,7 @@ packages:
resolution:
integrity: sha1-yobR/ogoFpsBICCOPchCS524NCw=
/next-tick/1.1.0:
dev: false
resolution:
integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
/nice-try/1.0.5:
@ -20884,7 +21008,6 @@ packages:
dependencies:
minimist: 0.0.10
wordwrap: 0.0.3
dev: false
resolution:
integrity: sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
/optimize-css-assets-webpack-plugin/5.0.3_webpack@4.43.0:
@ -21220,6 +21343,22 @@ packages:
node: '>=8'
resolution:
integrity: sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==
/pad-left/2.1.0:
dependencies:
repeat-string: 1.6.1
dev: true
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-FuajstRKjhOMsIOMx8tAOk/J6ZQ=
/pad-right/0.2.2:
dependencies:
repeat-string: 1.6.1
dev: true
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=
/pako/1.0.11:
dev: false
resolution:
@ -21674,12 +21813,6 @@ packages:
node: '>=10'
resolution:
integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==
/pkginfo/0.4.1:
dev: true
engines:
node: '>= 0.4.0'
resolution:
integrity: sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=
/please-upgrade-node/3.2.0:
dependencies:
semver-compare: 1.0.0
@ -22438,7 +22571,6 @@ packages:
resolution:
integrity: sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==
/property-expr/2.0.4:
dev: false
resolution:
integrity: sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==
/property-information/4.2.0:
@ -23693,33 +23825,6 @@ packages:
node: '>= 4'
resolution:
integrity: sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==
/request/2.88.0:
dependencies:
aws-sign2: 0.7.0
aws4: 1.11.0
caseless: 0.12.0
combined-stream: 1.0.8
extend: 3.0.2
forever-agent: 0.6.1
form-data: 2.3.3
har-validator: 5.1.5
http-signature: 1.2.0
is-typedarray: 1.0.0
isstream: 0.1.2
json-stringify-safe: 5.0.1
mime-types: 2.1.28
oauth-sign: 0.9.0
performance-now: 2.1.0
qs: 6.5.2
safe-buffer: 5.2.1
tough-cookie: 2.4.3
tunnel-agent: 0.6.0
uuid: 3.4.0
dev: true
engines:
node: '>= 4'
resolution:
integrity: sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
/request/2.88.2:
dependencies:
aws-sign2: 0.7.0
@ -23931,7 +24036,9 @@ packages:
/rimraf/2.4.5:
dependencies:
glob: 6.0.4
dev: false
hasBin: true
optional: true
resolution:
integrity: sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=
/rimraf/2.6.3:
@ -24219,14 +24326,12 @@ packages:
resolution:
integrity: sha512-WfuG+fl6eh3eZ2qAf6goB7nhiCd7NPXhmyFxigB/TOkQyeLP8w8GsVehvtGNtnNmyboz4TgeK40B1Kbql/8c5A==
/semver/7.1.2:
dev: false
engines:
node: '>=10'
hasBin: true
resolution:
integrity: sha512-BJs9T/H8sEVHbeigqzIEo57Iu/3DG6c4QoqTfbQB3BPA4zgzAomh/Fk9E7QtjWQ8mx2dgA9YCfSF4y9k9bHNpQ==
/semver/7.3.2:
dev: false
engines:
node: '>=10'
hasBin: true
@ -25660,7 +25765,6 @@ packages:
resolution:
integrity: sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA==
/synchronous-promise/2.0.15:
dev: false
resolution:
integrity: sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg==
/tabbable/4.0.0:
@ -25974,13 +26078,6 @@ packages:
node: '>=0.6.0'
resolution:
integrity: sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==
/timers-ext/0.1.7:
dependencies:
es5-ext: 0.10.53
next-tick: 1.1.0
dev: true
resolution:
integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==
/timm/1.7.0:
dev: false
resolution:
@ -26105,15 +26202,6 @@ packages:
node: '>=0.8'
resolution:
integrity: sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==
/tough-cookie/2.4.3:
dependencies:
psl: 1.8.0
punycode: 1.4.1
dev: true
engines:
node: '>=0.8'
resolution:
integrity: sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
/tough-cookie/2.5.0:
dependencies:
psl: 1.8.0
@ -26304,6 +26392,7 @@ packages:
resolution:
integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
/typanion/3.3.0:
dev: false
resolution:
integrity: sha512-e+54C4+ozFsTorFe50JNQlXlt4HVGQUvqul7VS0GbDfKlxh3aXbJY87Yu9IdtzvJWCyTgDX7q1PeMd3FH9zZqA==
/type-check/0.3.2:
@ -26403,7 +26492,6 @@ packages:
resolution:
integrity: sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==
/uglify-js/3.10.2:
dev: false
engines:
node: '>=0.8.0'
hasBin: true
@ -26991,6 +27079,7 @@ packages:
resolution:
integrity: sha512-8GfPiwzzRoWTg7OV1zva1KvrSemuMkv07MA9TTl91hfhe+wKrsrgVN4H2QSFd/U/FhiU3iWPYVgvbsOGwhyFWw==
/validator/13.5.2:
dev: false
engines:
node: '>= 0.10'
resolution:
@ -27015,76 +27104,45 @@ packages:
/vendors/1.0.4:
resolution:
integrity: sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==
/verdaccio-audit/10.0.0:
/verdaccio-audit/10.0.0-alpha.3:
dependencies:
express: 4.17.1
request: 2.88.2
https-proxy-agent: 5.0.0
node-fetch: 2.6.1
dev: true
engines:
node: '>=8'
resolution:
integrity: sha512-Epsh+C7ZEdq39PR9QeDBTWktbeqc0zOQjMzWte6Ut5Jh6fPLZzxGF8VK8O67B6mnTwLvGy50A1aPVM97Ysh5Rw==
/verdaccio-htpasswd/10.0.0:
integrity: sha512-IADe0VeOdTnQF/bBS0SxWklH8maq7LWxKEDdr9qgzoSiHVShZM78zfPxfnKPVi7IJ6Agh2oHewZuvRjfuIniGw==
/verdaccio-htpasswd/10.0.0-alpha.4:
dependencies:
'@verdaccio/file-locking': 10.0.0
'@verdaccio/commons-api': 10.0.0-alpha.3
'@verdaccio/file-locking': 10.0.0-alpha.3
apache-md5: 1.1.2
bcryptjs: 2.4.3
http-errors: 1.8.0
unix-crypt-td-js: 1.1.4
dev: true
engines:
node: '>=8'
node: '>=10'
resolution:
integrity: sha512-3TKwiLwl8/fbaTDawHvjSYcsyMmdARg58keP/1plv74x+Jw0sC66HbbRwQ/tPO5mqoG0UwoWW+lkO8h/OiWi9w==
/verdaccio/5.0.0-alpha.4:
integrity: sha512-e4JZ/gmShpFaR3+32Y7okwfLBYM+C0hg7IsY8NocmLzCzY8+3/C7Tl2FD796Xppkg652PrZ9fYEB3g2mjP18Sg==
/verdaccio/5.0.0-alpha.5:
dependencies:
'@verdaccio/commons-api': 10.0.0
'@verdaccio/local-storage': 10.0.1
'@verdaccio/readme': 10.0.0
'@verdaccio/streams': 10.0.0
'@verdaccio/ui-theme': 3.0.0
JSONStream: 1.3.5
async: 3.2.0
body-parser: 1.19.0
clipanion: 3.0.0-rc.11
compression: 1.7.4
cookies: 0.8.0
cors: 2.8.5
dayjs: 1.10.4
debug: 4.3.1
envinfo: 7.7.4
express: 4.17.1
fast-safe-stringify: 2.0.7
handlebars: 4.7.7
http-errors: 1.8.0
js-yaml: 4.0.0
jsonwebtoken: 8.5.1
kleur: 4.1.4
lodash: 4.17.21
lru-cache: 6.0.0
lunr-mutable-indexes: 2.3.2
marked: 2.0.1
memoizee: 0.4.15
mime: 2.5.2
minimatch: 3.0.4
mkdirp: 1.0.4
mv: 2.1.1
pino: 6.11.2
pkginfo: 0.4.1
prettier-bytes: 1.0.4
pretty-ms: 5.1.0
request: 2.88.0
semver: 7.3.4
validator: 13.5.2
verdaccio-audit: 10.0.0
verdaccio-htpasswd: 10.0.0
'@verdaccio/cli': 5.0.0-alpha.4
'@verdaccio/hooks': 5.0.0-alpha.3
'@verdaccio/logger': 5.0.0-alpha.3
'@verdaccio/mock': 5.0.0-alpha.3
'@verdaccio/node-api': 5.0.0-alpha.4
'@verdaccio/ui-theme': 5.0.0-alpha.4
'@verdaccio/utils': 5.0.0-alpha.3
verdaccio-audit: 10.0.0-alpha.3
verdaccio-htpasswd: 10.0.0-alpha.4
dev: true
engines:
node: '>=12'
npm: '>=5'
node: '>=10'
npm: '>=6'
hasBin: true
resolution:
integrity: sha512-LJqZ3O4UejvUoUTEaJGjGXyKQxPSRyRaFVuGCRlAoYkXPUC5iofv0pX7E20RUs+pQny1WxPZ44XIK0jBGfoU7Q==
integrity: sha512-JdvMLaWJOJOvuSSHzVCNnmEzJ3qWbk/P/r0q/JK4e7bIAdo35N414GeDNByEES2naOXQWD2XWbGOIKVcVh/w1A==
/verror/1.10.0:
dependencies:
assert-plus: 1.0.0
@ -27826,7 +27884,6 @@ packages:
resolution:
integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
/wordwrap/0.0.3:
dev: false
engines:
node: '>=0.4.0'
resolution:
@ -28166,7 +28223,6 @@ packages:
property-expr: 2.0.4
synchronous-promise: 2.0.15
toposort: 2.0.2
dev: false
engines:
node: '>=10'
resolution:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,23 +0,0 @@
import buildDebug from 'debug';
export type Manifest = {
// goes on first place at the header
ico: string;
css: string[];
js: string[];
};
const debug = buildDebug('verdaccio');
export function getManifestValue(
manifestItems: string[],
manifest,
basePath: string = ''
): string[] {
return manifestItems?.map((item) => {
debug('resolve item %o', item);
const resolvedItem = `${basePath}${manifest[item]}`;
debug('resolved item %o', resolvedItem);
return resolvedItem;
});
}

View file

@ -1,95 +0,0 @@
import { URL } from 'url';
import buildDebug from 'debug';
import LRU from 'lru-cache';
import { HEADERS } from '@verdaccio/commons-api';
import { getPublicUrl } from '../../../lib/utils';
import { WEB_TITLE } from '../../../lib/constants';
import renderTemplate from './template';
const pkgJSON = require('../../../../package.json');
const DEFAULT_LANGUAGE = 'es-US';
const cache = new LRU({ max: 500, maxAge: 1000 * 60 * 60 });
const debug = buildDebug('verdaccio');
const defaultManifestFiles = {
js: ['runtime.js', 'vendors.js', 'main.js'],
ico: 'favicon.ico',
};
export function validatePrimaryColor(primaryColor) {
const isHex = /^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/i.test(primaryColor);
if (!isHex) {
debug('invalid primary color %o', primaryColor);
return;
}
return primaryColor;
}
export default function renderHTML(config, manifest, manifestFiles, req, res) {
const { url_prefix } = config;
const base = getPublicUrl(config?.url_prefix, req);
const basename = new URL(base).pathname;
const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;
const darkMode = config?.web?.darkMode ?? false;
const title = config?.web?.title ?? WEB_TITLE;
const scope = config?.web?.scope ?? '';
// FIXME: logo URI is incomplete
let logoURI = config?.web?.logo ?? '';
const version = pkgJSON.version;
const primaryColor = validatePrimaryColor(config?.web?.primary_color) ?? '#4b5e40';
const { scriptsBodyAfter, metaScripts, scriptsbodyBefore } = Object.assign(
{},
{
scriptsBodyAfter: [],
bodyBefore: [],
metaScripts: [],
},
config?.web
);
const options = {
darkMode,
url_prefix,
basename,
base,
primaryColor,
version,
logoURI,
title,
scope,
language,
};
let webPage;
try {
webPage = cache.get('template');
if (!webPage) {
debug('web options %o', options);
debug('web manifestFiles %o', manifestFiles);
webPage = renderTemplate(
{
manifest: manifestFiles ?? defaultManifestFiles,
options,
scriptsBodyAfter,
metaScripts,
scriptsbodyBefore,
},
manifest
);
debug('template :: %o', webPage);
cache.set('template', webPage);
debug('set template cache');
} else {
debug('reuse template cache');
}
} catch (error) {
throw new Error(`theme could not be load, stack ${error.stack}`);
}
res.setHeader('Content-Type', HEADERS.TEXT_HTML);
res.send(webPage);
debug('render web');
}

View file

@ -1,62 +0,0 @@
import buildDebug from 'debug';
import { getManifestValue, Manifest } from './manifest';
const debug = buildDebug('verdaccio');
export type TemplateUIOptions = {
title?: string;
uri?: string;
darkMode?: boolean;
protocol?: string;
host?: string;
url_prefix?: string;
base: string;
primaryColor?: string;
version?: string;
logoURI?: string;
scope?: string;
language?: string;
};
export type Template = {
manifest: Manifest;
options: TemplateUIOptions;
metaScripts?: string[];
scriptsBodyAfter?: string[];
scriptsbodyBefore?: string[];
};
// the outcome of the Webpack Manifest Plugin
export interface WebpackManifest {
[key: string]: string;
}
export default function renderTemplate(template: Template, manifest: WebpackManifest) {
debug('template %o', template);
debug('manifest %o', manifest);
return `
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<base href="${template?.options.base}">
<title>${template?.options?.title ?? ''}</title>
<link rel="icon" href="${template?.options.base}-/static/favicon.ico"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script>
window.__VERDACCIO_BASENAME_UI_OPTIONS=${JSON.stringify(template.options)}
</script>
${template?.metaScripts ? template.metaScripts.join('') : ''}
</head>
<body class="body">
${template?.scriptsbodyBefore ? template.scriptsbodyBefore.join('') : ''}
<div id="root"></div>
${getManifestValue(template.manifest.js, manifest, template?.options.base)
.map((item) => `<script defer="defer" src="${item}"></script>`)
.join('')}
${template?.scriptsBodyAfter ? template.scriptsBodyAfter.join('') : ''}
</body>
</html>
`;
}

View file

@ -1,33 +0,0 @@
import { Cli } from 'clipanion';
import { InfoCommand } from './commands/info';
import { InitCommand } from './commands/init';
import { isVersionValid, MIN_NODE_VERSION } from './utils';
import { VersionCommand } from './commands/version';
require('pkginfo')(module);
const pkgVersion = module.exports.version;
if (process.getuid && process.getuid() === 0) {
process.emitWarning(`Verdaccio doesn't need superuser privileges. don't run it under root`);
}
if (!isVersionValid(process.version)) {
throw new Error(
// eslint-disable-next-line max-len
`Verdaccio requires at least Node.js v${MIN_NODE_VERSION} or higher and you have installed ${process.version},
please upgrade your Node.js distribution`
);
}
const [node, app, ...args] = process.argv;
const cli = new Cli({
binaryLabel: `verdaccio`,
binaryName: `${node} ${app}`,
binaryVersion: pkgVersion,
});
cli.register(InfoCommand);
cli.register(InitCommand);
cli.register(VersionCommand);
cli.runExit(args, Cli.defaultContext);

View file

@ -1,20 +0,0 @@
import envinfo from 'envinfo';
import { Command } from 'clipanion';
export class InfoCommand extends Command {
static paths = [[`--info`], [`-i`]];
async execute() {
this.context.stdout.write('\nEnvironment Info:');
const data = await envinfo.run({
System: ['OS', 'CPU'],
Binaries: ['node', 'yarn', 'npm', 'pnpm'],
Virtualization: ['Docker'],
Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
npmGlobalPackages: ['verdaccio'],
});
this.context.stdout.write(data);
process.exit(0);
}
}

View file

@ -1,79 +0,0 @@
import path from 'path';
import { Command, Option } from 'clipanion';
import { startVerdaccio, listenDefaultCallback } from '../../bootstrap';
import findConfigFile from '../../config-path';
import { parseConfigFile } from '../../utils';
require('pkginfo')(module);
const pkgVersion = module.exports.version;
const pkgName = module.exports.name;
export const DEFAULT_PROCESS_NAME: string = 'verdaccio';
const logger = require('../../logger');
export class InitCommand extends Command {
static paths = [Command.Default];
listen = Option.String('-l,--listen', {
description: 'host:port number to listen on (default: localhost:4873)',
});
// eslint-disable-next-line
static usage = Command.Usage({
description: `launch the server`,
details: `
This start the registry in the default port.
When used without arguments, it:
- bootstrap the server at the port \`4873\`
The optional arguments are:
- \`--listen\` to switch the default server port,
- \`--config\` to define a different configuration path location,
`,
examples: [
[`Runs the server with the default configuration`, `verdaccio`],
[`Runs the server in the port 5000`, `verdaccio --listen 5000`],
[
`Runs the server by using a different absolute location of the configuration file`,
`verdaccio --config /home/user/verdaccio/config.yaml`,
],
],
});
config = Option.String('-c,--config', {
description: 'use this configuration file (default: ./config.yaml)',
});
async execute() {
try {
const configPathLocation = findConfigFile(this.config as string);
const verdaccioConfiguration = parseConfigFile(configPathLocation);
if (!verdaccioConfiguration.self_path) {
verdaccioConfiguration.self_path = path.resolve(configPathLocation);
}
if (!verdaccioConfiguration.https) {
verdaccioConfiguration.https = { enable: false };
}
logger.logger.warn({ file: configPathLocation }, 'config file - @{file}');
process.title =
(verdaccioConfiguration.web && verdaccioConfiguration.web.title) || 'verdaccio';
startVerdaccio(
verdaccioConfiguration,
this.listen as string,
configPathLocation,
pkgVersion,
pkgName,
listenDefaultCallback
);
} catch (err) {
process.exit(1);
}
}
}

View file

@ -1,12 +0,0 @@
import { Command } from 'clipanion';
require('pkginfo')(module);
const pkgVersion = module.exports.version;
export class VersionCommand extends Command {
static paths = [[`--version`], [`-v`]];
async execute() {
this.context.stdout.write(`v${pkgVersion}`);
process.exit(0);
}
}

View file

@ -1,17 +0,0 @@
import { printMessage, PrettyOptionsExtended } from './prettifier';
export type PrettyFactory = (param) => string;
/*
options eg:
{ messageKey: 'msg', levelFirst: true, prettyStamp: false }
*/
module.exports = function prettyFactory(options: PrettyOptionsExtended): PrettyFactory {
// the break line must happens in the prettify component
const breakLike = '\n';
return (inputData): string => {
// FIXME: review colors by default is true
return printMessage(inputData, options, true) + breakLike;
};
};

View file

@ -1,102 +0,0 @@
import { inspect } from 'util';
import { white, red, green } from 'kleur';
import _ from 'lodash';
import dayjs from 'dayjs';
import { PrettyOptions } from 'pino';
import { calculateLevel, LevelCode, levelsColors, subSystemLevels } from '../levels';
import { padLeft, padRight } from '../utils';
export const CUSTOM_PAD_LENGTH = 1;
export const FORMAT_DATE = 'YYYY-MM-DD HH:mm:ss';
export function isObject(obj: unknown): boolean {
return _.isObject(obj) && _.isNull(obj) === false && _.isArray(obj) === false;
}
export function formatLoggingDate(time: number, message): string {
const timeFormatted = dayjs(time).format(FORMAT_DATE);
return `[${timeFormatted}]${message}`;
}
export interface PrettyOptionsExtended extends PrettyOptions {
prettyStamp: boolean;
}
let LEVEL_VALUE_MAX = 0;
// eslint-disable-next-line guard-for-in
for (const l in levelsColors) {
LEVEL_VALUE_MAX = Math.max(LEVEL_VALUE_MAX, l.length);
}
const ERROR_FLAG = '!';
export interface ObjectTemplate {
level: LevelCode;
msg: string;
sub?: string;
[key: string]: string | number | object | null | void;
}
export function fillInMsgTemplate(msg, templateOptions: ObjectTemplate, colors): string {
const templateRegex = /@{(!?[$A-Za-z_][$0-9A-Za-z\._]*)}/g;
return msg.replace(templateRegex, (_, name): string => {
let str = templateOptions;
let isError;
if (name[0] === ERROR_FLAG) {
name = name.substr(1);
isError = true;
}
// object can be @{foo.bar.}
const listAccessors = name.split('.');
for (let property = 0; property < listAccessors.length; property++) {
const id = listAccessors[property];
if (isObject(str)) {
str = (str as object)[id];
}
}
if (typeof str === 'string') {
if (colors === false || (str as string).includes('\n')) {
return str;
} else if (isError) {
return red(str);
}
return green(str);
}
// object, showHidden, depth, colors
return inspect(str, undefined, null, colors);
});
}
function getMessage(debugLevel, msg, sub, templateObjects, hasColors) {
const finalMessage = fillInMsgTemplate(msg, templateObjects, hasColors);
const subSystemType = subSystemLevels.color[sub ?? 'default'];
if (hasColors) {
const logString = `${levelsColors[debugLevel](padRight(debugLevel, LEVEL_VALUE_MAX))}${white(
`${subSystemType} ${finalMessage}`
)}`;
return padLeft(logString);
}
const logString = `${padRight(debugLevel, LEVEL_VALUE_MAX)}${subSystemType} ${finalMessage}`;
return padRight(logString);
}
export function printMessage(
templateObjects: ObjectTemplate,
options: PrettyOptionsExtended,
hasColors = true
): string {
const { prettyStamp } = options;
const { level, msg, sub } = templateObjects;
const debugLevel = calculateLevel(level);
const logMessage = getMessage(debugLevel, msg, sub, templateObjects, hasColors);
return prettyStamp ? formatLoggingDate(templateObjects.time as number, logMessage) : logMessage;
}

View file

@ -1 +0,0 @@
export { setup, createLogger, logger } from './logger';

View file

@ -1,156 +0,0 @@
import pino from 'pino';
import _ from 'lodash';
import buildDebug from 'debug';
import { yellow } from 'kleur';
import { padLeft } from './utils';
function isProd() {
return process.env.NODE_ENV === 'production';
}
export let logger;
const debug = buildDebug('verdaccio:logger');
const DEFAULT_LOG_FORMAT = isProd() ? 'json' : 'pretty';
export type LogPlugin = {
dest: string;
options?: any[];
};
export type LogType = 'file' | 'stdout';
export type LogFormat = 'json' | 'pretty-timestamped' | 'pretty';
export function createLogger(
options = { level: 'http' },
destination = pino.destination(1),
format: LogFormat = DEFAULT_LOG_FORMAT,
prettyPrintOptions = {
// we hide warning since the prettifier should not be used in production
// https://getpino.io/#/docs/pretty?id=prettifier-api
suppressFlushSyncWarning: true,
}
) {
if (_.isNil(format)) {
format = DEFAULT_LOG_FORMAT;
}
let pinoConfig = {
customLevels: {
http: 25,
},
...options,
level: options.level,
serializers: {
err: pino.stdSerializers.err,
req: pino.stdSerializers.req,
res: pino.stdSerializers.res,
},
};
debug('has prettifier? %o', !isProd());
// pretty logs are not allowed in production for performance reasons
if ((format === DEFAULT_LOG_FORMAT || format !== 'json') && isProd() === false) {
pinoConfig = Object.assign({}, pinoConfig, {
// more info
// https://github.com/pinojs/pino-pretty/issues/37
prettyPrint: {
levelFirst: true,
prettyStamp: format === 'pretty-timestamped',
...prettyPrintOptions,
},
prettifier: require('./formatter'),
});
}
const logger = pino(pinoConfig, destination);
if (process.env.DEBUG) {
logger.on('level-change', (lvl, val, prevLvl, prevVal) => {
debug('%s (%d) was changed to %s (%d)', lvl, val, prevLvl, prevVal);
});
}
return logger;
}
export function getLogger() {
if (_.isNil(logger)) {
process.emitWarning('logger is not defined');
return;
}
return logger;
}
const DEFAULT_LOGGER_CONF: LoggerConfigItem = {
type: 'stdout',
format: 'pretty',
level: 'http',
};
export type LoggerConfigItem = {
type?: LogType;
plugin?: LogPlugin;
format?: LogFormat;
path?: string;
level?: string;
};
export type LoggerConfig = LoggerConfigItem[];
export function setup(options: LoggerConfig | LoggerConfigItem = [DEFAULT_LOGGER_CONF]) {
debug('setup logger');
const isLegacyConf = Array.isArray(options);
if (isLegacyConf) {
const deprecateMessage =
'deprecate: multiple logger configuration is deprecated, please check the migration guide.';
process.emitWarning(deprecateMessage);
}
// verdaccio 5 does not allow multiple logger configuration
// backward compatible, pick only the first option
// next major will thrown an error
let loggerConfig = isLegacyConf ? options[0] : options;
if (!loggerConfig?.level) {
loggerConfig = Object.assign(
{},
{
level: 'http',
},
loggerConfig
);
}
const pinoConfig = { level: loggerConfig.level };
if (loggerConfig.type === 'file') {
debug('logging file enabled');
logger = createLogger(pinoConfig, pino.destination(loggerConfig.path), loggerConfig.format);
} else if (loggerConfig.type === 'rotating-file') {
process.emitWarning(
'rotating-file type is not longer supported, consider use [logrotate] instead'
);
debug('logging stdout enabled');
logger = createLogger(pinoConfig, pino.destination(1), loggerConfig.format);
} else {
debug('logging stdout enabled');
logger = createLogger(pinoConfig, pino.destination(1), loggerConfig.format);
}
if (isProd()) {
// why only on prod? https://github.com/pinojs/pino/issues/920#issuecomment-710807667
const finalHandler = pino.final(logger, (err, finalLogger, event) => {
finalLogger.info(`${event} caught`);
if (err) {
finalLogger.error(err, 'error caused exit');
}
process.exit(err ? 1 : 0);
});
process.on('uncaughtException', (err) => finalHandler(err, 'uncaughtException'));
process.on('unhandledRejection', (err) => finalHandler(err as Error, 'unhandledRejection'));
process.on('beforeExit', () => finalHandler(null, 'beforeExit'));
process.on('exit', () => finalHandler(null, 'exit'));
process.on('uncaughtException', (err) => finalHandler(err, 'uncaughtException'));
process.on('SIGINT', () => finalHandler(null, 'SIGINT'));
process.on('SIGQUIT', () => finalHandler(null, 'SIGQUIT'));
process.on('SIGTERM', () => finalHandler(null, 'SIGTERM'));
}
}