diff --git a/.changeset/cool-seals-watch.md b/.changeset/cool-seals-watch.md new file mode 100644 index 000000000..3397d4aee --- /dev/null +++ b/.changeset/cool-seals-watch.md @@ -0,0 +1,6 @@ +--- +'@verdaccio/loaders': patch +'@verdaccio/config': patch +--- + +chore(loader): fix types for plugin options diff --git a/packages/config/src/config.ts b/packages/config/src/config.ts index 5df030538..d798e789c 100644 --- a/packages/config/src/config.ts +++ b/packages/config/src/config.ts @@ -52,6 +52,7 @@ class Config implements AppConfig { public packages: PackageList; public users: any; public auth: AuthConf; + public store: any; public server_id: string; public configPath: string; /** diff --git a/packages/loaders/src/plugin-async-loader.ts b/packages/loaders/src/plugin-async-loader.ts index 9ae214680..9f2b8adeb 100644 --- a/packages/loaders/src/plugin-async-loader.ts +++ b/packages/loaders/src/plugin-async-loader.ts @@ -3,7 +3,6 @@ import fs from 'fs'; import { dirname, isAbsolute, join, resolve } from 'path'; import { pluginUtils } from '@verdaccio/core'; -import { Config, Logger } from '@verdaccio/types'; import { PluginType, isES6, isValid, tryLoad } from './utils'; @@ -16,8 +15,6 @@ async function isDirectory(pathFolder: string) { return stat.isDirectory(); } -export type Params = { config: Config; logger: Logger }; - // type Plugins = // | pluginUtils.Auth // | pluginUtils.Storage @@ -40,24 +37,25 @@ export type Params = { config: Config; logger: Logger }; * The `params` is an object that contains the global configuration and the logger. * * @param {*} pluginConfigs the custom plugin section - * @param {*} params a set of params to initialize the plugin + * @param {*} pluginOptions a set of options to initialize the plugin * @param {*} sanityCheck callback that check the shape that should fulfill the plugin * @param {*} prefix by default is verdaccio but can be override with config.server.pluginPrefix + * @param {*} pluginCategory the category of the plugin, eg: auth, storage, middleware * @return {Array} list of plugins */ export async function asyncLoadPlugin>( pluginConfigs: any = {}, - params: Params, + pluginOptions: pluginUtils.PluginOptions, sanityCheck: (plugin: PluginType) => boolean, prefix: string = 'verdaccio', pluginCategory: string = '' ): Promise[]> { - const logger = params?.logger; + const logger = pluginOptions?.logger; const pluginsIds = Object.keys(pluginConfigs); - const { config } = params; + const { config } = pluginOptions; let plugins: PluginType[] = []; for (let pluginId of pluginsIds) { - debug('plugin %s', pluginId); + debug('looking for plugin %o', pluginId); if (typeof config.plugins === 'string') { let pluginsPath = config.plugins; debug('plugin path %s', pluginsPath); @@ -84,7 +82,7 @@ export async function asyncLoadPlugin>( logger.error(a, b); }); if (plugin && isValid(plugin)) { - plugin = executePlugin(plugin, pluginConfigs[pluginId], params); + plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions); if (!sanityCheck(plugin)) { logger.error( { content: externalFilePlugin }, @@ -109,14 +107,14 @@ export async function asyncLoadPlugin>( if (typeof pluginId === 'string') { const isScoped: boolean = pluginId.startsWith('@') && pluginId.includes('/'); - debug('is scoped plugin %s', isScoped); + debug('is scoped plugin: %s', isScoped); const pluginName = isScoped ? pluginId : `${prefix}-${pluginId}`; - debug('plugin pkg name %s', pluginName); + debug('plugin package name %s', pluginName); let plugin = tryLoad(pluginName, (a: any, b: any) => { logger.error(a, b); }); if (plugin && isValid(plugin)) { - plugin = executePlugin(plugin, pluginConfigs[pluginId], params); + plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions); if (!sanityCheck(plugin)) { logger.error({ content: pluginName }, "@{content} doesn't look like a valid plugin"); continue; @@ -136,23 +134,23 @@ export async function asyncLoadPlugin>( } } } - debug('plugin found %s', plugins.length); + debug('%s plugins found: %s', pluginCategory, plugins.length); return plugins; } export function executePlugin( plugin: PluginType, pluginConfig: unknown, - params: Params + pluginOptions: pluginUtils.PluginOptions ): PluginType { if (isES6(plugin)) { debug('plugin is ES6'); // @ts-expect-error no relevant for the code // eslint-disable-next-line new-cap - return new plugin.default(pluginConfig, params) as Plugin; + return new plugin.default(pluginConfig, pluginOptions) as Plugin; } else { debug('plugin is commonJS'); // @ts-expect-error improve this type - return plugin(pluginConfig, params) as PluginType; + return plugin(pluginConfig, pluginOptions) as PluginType; } } diff --git a/packages/loaders/test/partials/config/valid-plugin-store.yaml b/packages/loaders/test/partials/config/valid-plugin-store.yaml new file mode 100644 index 000000000..688318d5c --- /dev/null +++ b/packages/loaders/test/partials/config/valid-plugin-store.yaml @@ -0,0 +1,3 @@ +store: + plugin-store: + enabled: true diff --git a/packages/loaders/test/partials/test-plugin-storage/verdaccio-plugin-store/index.js b/packages/loaders/test/partials/test-plugin-storage/verdaccio-plugin-store/index.js new file mode 100644 index 000000000..9143fd69b --- /dev/null +++ b/packages/loaders/test/partials/test-plugin-storage/verdaccio-plugin-store/index.js @@ -0,0 +1,7 @@ +function ValidVerdaccioPlugin() { + return { + getPackageStorage: function () {}, + }; +} + +module.exports = ValidVerdaccioPlugin; diff --git a/packages/loaders/test/partials/test-plugin-storage/verdaccio-plugin-store/package.json b/packages/loaders/test/partials/test-plugin-storage/verdaccio-plugin-store/package.json new file mode 100644 index 000000000..56dc78d45 --- /dev/null +++ b/packages/loaders/test/partials/test-plugin-storage/verdaccio-plugin-store/package.json @@ -0,0 +1,11 @@ +{ + "name": "verdaccio-plugin", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/packages/loaders/test/plugin_loader_async.spec.ts b/packages/loaders/test/plugin_loader_async.spec.ts index aaa40f4e1..af246beff 100644 --- a/packages/loaders/test/plugin_loader_async.spec.ts +++ b/packages/loaders/test/plugin_loader_async.spec.ts @@ -15,6 +15,9 @@ function getConfig(file: string) { const authSanitize = function (plugin) { return plugin.authenticate || plugin.allow_access || plugin.allow_publish; }; +const storeSanitize = function (plugin) { + return typeof plugin.getPackageStorage !== 'undefined'; +}; const pluginsPartialsFolder = path.join(__dirname, './partials/test-plugin-storage'); @@ -31,13 +34,17 @@ describe('plugin loader', () => { expect(plugins).toHaveLength(1); }); + test('testing storage valid plugin loader', async () => { + const config = getConfig('valid-plugin-store.yaml'); + config.plugins = pluginsPartialsFolder; + const plugins = await asyncLoadPlugin(config.store, { config, logger }, storeSanitize); + + expect(plugins).toHaveLength(1); + }); + test('should handle does not exist plugin folder', async () => { const config = getConfig('plugins-folder-fake.yaml'); - const plugins = await asyncLoadPlugin( - config.auth, - { logger: logger, config: config }, - authSanitize - ); + const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize); expect(plugins).toHaveLength(0); }); @@ -59,11 +66,7 @@ describe('plugin loader', () => { const config = getConfig('plugins-folder-fake.yaml'); // force file instead a folder. config.plugins = path.join(__dirname, 'just-a-file.js'); - const plugins = await asyncLoadPlugin( - config.auth, - { logger: logger, config: config }, - authSanitize - ); + const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize); expect(plugins).toHaveLength(0); }); @@ -72,11 +75,7 @@ describe('plugin loader', () => { test('should resolve plugin based on relative path', async () => { const config = getConfig('relative-plugins.yaml'); // force file instead a folder. - const plugins = await asyncLoadPlugin( - config.auth, - { logger: logger, config: config }, - authSanitize - ); + const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize); expect(plugins).toHaveLength(1); }); @@ -88,11 +87,7 @@ describe('plugin loader', () => { // @ts-expect-error config.config_path = undefined; // force file instead a folder. - const plugins = await asyncLoadPlugin( - config.auth, - { logger: logger, config: config }, - authSanitize - ); + const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize); expect(plugins).toHaveLength(0); }); @@ -103,11 +98,7 @@ describe('plugin loader', () => { // @ts-expect-error config.configPath = undefined; // force file instead a folder. - const plugins = await asyncLoadPlugin( - config.auth, - { logger: logger, config: config }, - authSanitize - ); + const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize); expect(plugins).toHaveLength(0); });