@verdaccio/loaders 8.0.0-next-8.3 → 8.0.0-next-8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @verdaccio/loaders
2
2
 
3
+ ## 8.0.0-next-8.4
4
+
5
+ ### Patch Changes
6
+
7
+ - ba71932: chore(loader): fix types for plugin options
8
+
3
9
  ## 8.0.0-next-8.3
4
10
 
5
11
  ### Minor Changes
@@ -1,10 +1,5 @@
1
1
  import { pluginUtils } from '@verdaccio/core';
2
- import { Config, Logger } from '@verdaccio/types';
3
2
  import { PluginType } from './utils';
4
- export type Params = {
5
- config: Config;
6
- logger: Logger;
7
- };
8
3
  /**
9
4
  * The plugin loader find recursively plugins, if one plugin fails is ignored and report the error to the logger.
10
5
  *
@@ -22,10 +17,11 @@ export type Params = {
22
17
  * The `params` is an object that contains the global configuration and the logger.
23
18
  *
24
19
  * @param {*} pluginConfigs the custom plugin section
25
- * @param {*} params a set of params to initialize the plugin
20
+ * @param {*} pluginOptions a set of options to initialize the plugin
26
21
  * @param {*} sanityCheck callback that check the shape that should fulfill the plugin
27
22
  * @param {*} prefix by default is verdaccio but can be override with config.server.pluginPrefix
23
+ * @param {*} pluginCategory the category of the plugin, eg: auth, storage, middleware
28
24
  * @return {Array} list of plugins
29
25
  */
30
- export declare function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(pluginConfigs: any, params: Params, sanityCheck: (plugin: PluginType<T>) => boolean, prefix?: string, pluginCategory?: string): Promise<PluginType<T>[]>;
31
- export declare function executePlugin<T>(plugin: PluginType<T>, pluginConfig: unknown, params: Params): PluginType<T>;
26
+ export declare function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(pluginConfigs: any, pluginOptions: pluginUtils.PluginOptions, sanityCheck: (plugin: PluginType<T>) => boolean, prefix?: string, pluginCategory?: string): Promise<PluginType<T>[]>;
27
+ export declare function executePlugin<T>(plugin: PluginType<T>, pluginConfig: unknown, pluginOptions: pluginUtils.PluginOptions): PluginType<T>;
@@ -18,6 +18,7 @@ async function isDirectory(pathFolder) {
18
18
  const stat = await lstat(pathFolder);
19
19
  return stat.isDirectory();
20
20
  }
21
+
21
22
  // type Plugins<T> =
22
23
  // | pluginUtils.Auth<T>
23
24
  // | pluginUtils.Storage<T>
@@ -40,20 +41,21 @@ async function isDirectory(pathFolder) {
40
41
  * The `params` is an object that contains the global configuration and the logger.
41
42
  *
42
43
  * @param {*} pluginConfigs the custom plugin section
43
- * @param {*} params a set of params to initialize the plugin
44
+ * @param {*} pluginOptions a set of options to initialize the plugin
44
45
  * @param {*} sanityCheck callback that check the shape that should fulfill the plugin
45
46
  * @param {*} prefix by default is verdaccio but can be override with config.server.pluginPrefix
47
+ * @param {*} pluginCategory the category of the plugin, eg: auth, storage, middleware
46
48
  * @return {Array} list of plugins
47
49
  */
48
- async function asyncLoadPlugin(pluginConfigs = {}, params, sanityCheck, prefix = 'verdaccio', pluginCategory = '') {
49
- const logger = params?.logger;
50
+ async function asyncLoadPlugin(pluginConfigs = {}, pluginOptions, sanityCheck, prefix = 'verdaccio', pluginCategory = '') {
51
+ const logger = pluginOptions?.logger;
50
52
  const pluginsIds = Object.keys(pluginConfigs);
51
53
  const {
52
54
  config
53
- } = params;
55
+ } = pluginOptions;
54
56
  let plugins = [];
55
57
  for (let pluginId of pluginsIds) {
56
- debug('plugin %s', pluginId);
58
+ debug('looking for plugin %o', pluginId);
57
59
  if (typeof config.plugins === 'string') {
58
60
  let pluginsPath = config.plugins;
59
61
  debug('plugin path %s', pluginsPath);
@@ -79,7 +81,7 @@ async function asyncLoadPlugin(pluginConfigs = {}, params, sanityCheck, prefix =
79
81
  logger.error(a, b);
80
82
  });
81
83
  if (plugin && (0, _utils.isValid)(plugin)) {
82
- plugin = executePlugin(plugin, pluginConfigs[pluginId], params);
84
+ plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);
83
85
  if (!sanityCheck(plugin)) {
84
86
  logger.error({
85
87
  content: externalFilePlugin
@@ -104,14 +106,14 @@ async function asyncLoadPlugin(pluginConfigs = {}, params, sanityCheck, prefix =
104
106
  }
105
107
  if (typeof pluginId === 'string') {
106
108
  const isScoped = pluginId.startsWith('@') && pluginId.includes('/');
107
- debug('is scoped plugin %s', isScoped);
109
+ debug('is scoped plugin: %s', isScoped);
108
110
  const pluginName = isScoped ? pluginId : `${prefix}-${pluginId}`;
109
- debug('plugin pkg name %s', pluginName);
111
+ debug('plugin package name %s', pluginName);
110
112
  let plugin = (0, _utils.tryLoad)(pluginName, (a, b) => {
111
113
  logger.error(a, b);
112
114
  });
113
115
  if (plugin && (0, _utils.isValid)(plugin)) {
114
- plugin = executePlugin(plugin, pluginConfigs[pluginId], params);
116
+ plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);
115
117
  if (!sanityCheck(plugin)) {
116
118
  logger.error({
117
119
  content: pluginName
@@ -133,19 +135,19 @@ async function asyncLoadPlugin(pluginConfigs = {}, params, sanityCheck, prefix =
133
135
  }
134
136
  }
135
137
  }
136
- debug('plugin found %s', plugins.length);
138
+ debug('%s plugins found: %s', pluginCategory, plugins.length);
137
139
  return plugins;
138
140
  }
139
- function executePlugin(plugin, pluginConfig, params) {
141
+ function executePlugin(plugin, pluginConfig, pluginOptions) {
140
142
  if ((0, _utils.isES6)(plugin)) {
141
143
  debug('plugin is ES6');
142
144
  // @ts-expect-error no relevant for the code
143
145
  // eslint-disable-next-line new-cap
144
- return new plugin.default(pluginConfig, params);
146
+ return new plugin.default(pluginConfig, pluginOptions);
145
147
  } else {
146
148
  debug('plugin is commonJS');
147
149
  // @ts-expect-error improve this type
148
- return plugin(pluginConfig, params);
150
+ return plugin(pluginConfig, pluginOptions);
149
151
  }
150
152
  }
151
153
  //# sourceMappingURL=plugin-async-loader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-async-loader.js","names":["_debug","_interopRequireDefault","require","_fs","_path","_utils","e","__esModule","default","debug","buildDebug","lstat","fs","promises","isDirectory","pathFolder","stat","asyncLoadPlugin","pluginConfigs","params","sanityCheck","prefix","pluginCategory","logger","pluginsIds","Object","keys","config","plugins","pluginId","pluginsPath","isAbsolute","config_path","configPath","error","resolve","join","dirname","path","pluginDir","externalFilePlugin","plugin","tryLoad","a","b","isValid","executePlugin","content","push","info","err","warn","message","isScoped","startsWith","includes","pluginName","length","pluginConfig","isES6"],"sources":["../src/plugin-async-loader.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport fs from 'fs';\nimport { dirname, isAbsolute, join, resolve } from 'path';\n\nimport { pluginUtils } from '@verdaccio/core';\nimport { Config, Logger } from '@verdaccio/types';\n\nimport { PluginType, isES6, isValid, tryLoad } from './utils';\n\nconst debug = buildDebug('verdaccio:plugin:loader:async');\n\nconst { lstat } = fs.promises ? fs.promises : require('fs/promises');\n\nasync function isDirectory(pathFolder: string) {\n const stat = await lstat(pathFolder);\n return stat.isDirectory();\n}\n\nexport type Params = { config: Config; logger: Logger };\n\n// type Plugins<T> =\n// | pluginUtils.Auth<T>\n// | pluginUtils.Storage<T>\n// | pluginUtils.ExpressMiddleware<T, unknown, unknown>;\n\n/**\n * The plugin loader find recursively plugins, if one plugin fails is ignored and report the error to the logger.\n *\n * The loader follows the order:\n * - If the at the `config.yaml` file the `plugins: ./plugins` is defined\n * - If is absolute will use the provided path\n * - If is relative, will use the base path of the config file. eg: /root/config.yaml the plugins folder should be\n * hosted at /root/plugins\n * - The next step is find at the node_modules or global based on the `require` native algorithm.\n * - If the package is scoped eg: @scope/foo, try to load the package `@scope/foo`\n * - If the package is not scoped, will use the default prefix: verdaccio-foo.\n * - If a custom prefix is provided, the verdaccio- is replaced by the config.server.pluginPrefix.\n *\n * The `sanityCheck` is the validation for the required methods to load the plugin, if the validation fails the plugin won't be loaded.\n * The `params` is an object that contains the global configuration and the logger.\n *\n * @param {*} pluginConfigs the custom plugin section\n * @param {*} params a set of params to initialize the plugin\n * @param {*} sanityCheck callback that check the shape that should fulfill the plugin\n * @param {*} prefix by default is verdaccio but can be override with config.server.pluginPrefix\n * @return {Array} list of plugins\n */\nexport async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(\n pluginConfigs: any = {},\n params: Params,\n sanityCheck: (plugin: PluginType<T>) => boolean,\n prefix: string = 'verdaccio',\n pluginCategory: string = ''\n): Promise<PluginType<T>[]> {\n const logger = params?.logger;\n const pluginsIds = Object.keys(pluginConfigs);\n const { config } = params;\n let plugins: PluginType<T>[] = [];\n for (let pluginId of pluginsIds) {\n debug('plugin %s', pluginId);\n if (typeof config.plugins === 'string') {\n let pluginsPath = config.plugins;\n debug('plugin path %s', pluginsPath);\n if (!isAbsolute(pluginsPath)) {\n if (typeof config.config_path === 'string' && !config.configPath) {\n logger.error(\n 'configPath is missing and the legacy config.config_path is not available for loading plugins'\n );\n }\n\n if (!config.configPath) {\n logger.error('config path property is required for loading plugins');\n continue;\n }\n pluginsPath = resolve(join(dirname(config.configPath), pluginsPath));\n }\n logger.debug({ path: pluginsPath }, 'plugins folder defined, loading plugins from @{path} ');\n // throws if is not a directory\n try {\n await isDirectory(pluginsPath);\n const pluginDir = pluginsPath;\n const externalFilePlugin = resolve(pluginDir, `${prefix}-${pluginId}`);\n let plugin = tryLoad<T>(externalFilePlugin, (a: any, b: any) => {\n logger.error(a, b);\n });\n if (plugin && isValid(plugin)) {\n plugin = executePlugin(plugin, pluginConfigs[pluginId], params);\n if (!sanityCheck(plugin)) {\n logger.error(\n { content: externalFilePlugin },\n \"@{content} doesn't look like a valid plugin\"\n );\n continue;\n }\n plugins.push(plugin);\n logger.info(\n { prefix, pluginId, pluginCategory },\n 'plugin @{prefix}-@{pluginId} successfully loaded (@{pluginCategory})'\n );\n continue;\n }\n } catch (err: any) {\n logger.warn(\n { err: err.message, pluginsPath, pluginId },\n '@{err} on loading plugins at @{pluginsPath} for @{pluginId}'\n );\n }\n }\n\n if (typeof pluginId === 'string') {\n const isScoped: boolean = pluginId.startsWith('@') && pluginId.includes('/');\n debug('is scoped plugin %s', isScoped);\n const pluginName = isScoped ? pluginId : `${prefix}-${pluginId}`;\n debug('plugin pkg name %s', pluginName);\n let plugin = tryLoad<T>(pluginName, (a: any, b: any) => {\n logger.error(a, b);\n });\n if (plugin && isValid(plugin)) {\n plugin = executePlugin(plugin, pluginConfigs[pluginId], params);\n if (!sanityCheck(plugin)) {\n logger.error({ content: pluginName }, \"@{content} doesn't look like a valid plugin\");\n continue;\n }\n plugins.push(plugin);\n logger.info(\n { prefix, pluginId, pluginCategory },\n 'plugin @{prefix}-@{pluginId} successfully loaded (@{pluginCategory})'\n );\n continue;\n } else {\n logger.error(\n { pluginName },\n 'package not found, try to install @{pluginName} with a package manager'\n );\n continue;\n }\n }\n }\n debug('plugin found %s', plugins.length);\n return plugins;\n}\n\nexport function executePlugin<T>(\n plugin: PluginType<T>,\n pluginConfig: unknown,\n params: Params\n): PluginType<T> {\n if (isES6(plugin)) {\n debug('plugin is ES6');\n // @ts-expect-error no relevant for the code\n // eslint-disable-next-line new-cap\n return new plugin.default(pluginConfig, params) as Plugin;\n } else {\n debug('plugin is commonJS');\n // @ts-expect-error improve this type\n return plugin(pluginConfig, params) as PluginType<T>;\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"plugin-async-loader.js","names":["_debug","_interopRequireDefault","require","_fs","_path","_utils","e","__esModule","default","debug","buildDebug","lstat","fs","promises","isDirectory","pathFolder","stat","asyncLoadPlugin","pluginConfigs","pluginOptions","sanityCheck","prefix","pluginCategory","logger","pluginsIds","Object","keys","config","plugins","pluginId","pluginsPath","isAbsolute","config_path","configPath","error","resolve","join","dirname","path","pluginDir","externalFilePlugin","plugin","tryLoad","a","b","isValid","executePlugin","content","push","info","err","warn","message","isScoped","startsWith","includes","pluginName","length","pluginConfig","isES6"],"sources":["../src/plugin-async-loader.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport fs from 'fs';\nimport { dirname, isAbsolute, join, resolve } from 'path';\n\nimport { pluginUtils } from '@verdaccio/core';\n\nimport { PluginType, isES6, isValid, tryLoad } from './utils';\n\nconst debug = buildDebug('verdaccio:plugin:loader:async');\n\nconst { lstat } = fs.promises ? fs.promises : require('fs/promises');\n\nasync function isDirectory(pathFolder: string) {\n const stat = await lstat(pathFolder);\n return stat.isDirectory();\n}\n\n// type Plugins<T> =\n// | pluginUtils.Auth<T>\n// | pluginUtils.Storage<T>\n// | pluginUtils.ExpressMiddleware<T, unknown, unknown>;\n\n/**\n * The plugin loader find recursively plugins, if one plugin fails is ignored and report the error to the logger.\n *\n * The loader follows the order:\n * - If the at the `config.yaml` file the `plugins: ./plugins` is defined\n * - If is absolute will use the provided path\n * - If is relative, will use the base path of the config file. eg: /root/config.yaml the plugins folder should be\n * hosted at /root/plugins\n * - The next step is find at the node_modules or global based on the `require` native algorithm.\n * - If the package is scoped eg: @scope/foo, try to load the package `@scope/foo`\n * - If the package is not scoped, will use the default prefix: verdaccio-foo.\n * - If a custom prefix is provided, the verdaccio- is replaced by the config.server.pluginPrefix.\n *\n * The `sanityCheck` is the validation for the required methods to load the plugin, if the validation fails the plugin won't be loaded.\n * The `params` is an object that contains the global configuration and the logger.\n *\n * @param {*} pluginConfigs the custom plugin section\n * @param {*} pluginOptions a set of options to initialize the plugin\n * @param {*} sanityCheck callback that check the shape that should fulfill the plugin\n * @param {*} prefix by default is verdaccio but can be override with config.server.pluginPrefix\n * @param {*} pluginCategory the category of the plugin, eg: auth, storage, middleware\n * @return {Array} list of plugins\n */\nexport async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(\n pluginConfigs: any = {},\n pluginOptions: pluginUtils.PluginOptions,\n sanityCheck: (plugin: PluginType<T>) => boolean,\n prefix: string = 'verdaccio',\n pluginCategory: string = ''\n): Promise<PluginType<T>[]> {\n const logger = pluginOptions?.logger;\n const pluginsIds = Object.keys(pluginConfigs);\n const { config } = pluginOptions;\n let plugins: PluginType<T>[] = [];\n for (let pluginId of pluginsIds) {\n debug('looking for plugin %o', pluginId);\n if (typeof config.plugins === 'string') {\n let pluginsPath = config.plugins;\n debug('plugin path %s', pluginsPath);\n if (!isAbsolute(pluginsPath)) {\n if (typeof config.config_path === 'string' && !config.configPath) {\n logger.error(\n 'configPath is missing and the legacy config.config_path is not available for loading plugins'\n );\n }\n\n if (!config.configPath) {\n logger.error('config path property is required for loading plugins');\n continue;\n }\n pluginsPath = resolve(join(dirname(config.configPath), pluginsPath));\n }\n logger.debug({ path: pluginsPath }, 'plugins folder defined, loading plugins from @{path} ');\n // throws if is not a directory\n try {\n await isDirectory(pluginsPath);\n const pluginDir = pluginsPath;\n const externalFilePlugin = resolve(pluginDir, `${prefix}-${pluginId}`);\n let plugin = tryLoad<T>(externalFilePlugin, (a: any, b: any) => {\n logger.error(a, b);\n });\n if (plugin && isValid(plugin)) {\n plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);\n if (!sanityCheck(plugin)) {\n logger.error(\n { content: externalFilePlugin },\n \"@{content} doesn't look like a valid plugin\"\n );\n continue;\n }\n plugins.push(plugin);\n logger.info(\n { prefix, pluginId, pluginCategory },\n 'plugin @{prefix}-@{pluginId} successfully loaded (@{pluginCategory})'\n );\n continue;\n }\n } catch (err: any) {\n logger.warn(\n { err: err.message, pluginsPath, pluginId },\n '@{err} on loading plugins at @{pluginsPath} for @{pluginId}'\n );\n }\n }\n\n if (typeof pluginId === 'string') {\n const isScoped: boolean = pluginId.startsWith('@') && pluginId.includes('/');\n debug('is scoped plugin: %s', isScoped);\n const pluginName = isScoped ? pluginId : `${prefix}-${pluginId}`;\n debug('plugin package name %s', pluginName);\n let plugin = tryLoad<T>(pluginName, (a: any, b: any) => {\n logger.error(a, b);\n });\n if (plugin && isValid(plugin)) {\n plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);\n if (!sanityCheck(plugin)) {\n logger.error({ content: pluginName }, \"@{content} doesn't look like a valid plugin\");\n continue;\n }\n plugins.push(plugin);\n logger.info(\n { prefix, pluginId, pluginCategory },\n 'plugin @{prefix}-@{pluginId} successfully loaded (@{pluginCategory})'\n );\n continue;\n } else {\n logger.error(\n { pluginName },\n 'package not found, try to install @{pluginName} with a package manager'\n );\n continue;\n }\n }\n }\n debug('%s plugins found: %s', pluginCategory, plugins.length);\n return plugins;\n}\n\nexport function executePlugin<T>(\n plugin: PluginType<T>,\n pluginConfig: unknown,\n pluginOptions: pluginUtils.PluginOptions\n): PluginType<T> {\n if (isES6(plugin)) {\n debug('plugin is ES6');\n // @ts-expect-error no relevant for the code\n // eslint-disable-next-line new-cap\n return new plugin.default(pluginConfig, pluginOptions) as Plugin;\n } else {\n debug('plugin is commonJS');\n // @ts-expect-error improve this type\n return plugin(pluginConfig, pluginOptions) as PluginType<T>;\n }\n}\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/loaders",
3
- "version": "8.0.0-next-8.3",
3
+ "version": "8.0.0-next-8.4",
4
4
  "description": "loaders logic",
5
5
  "main": "./build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -17,13 +17,13 @@
17
17
  "lodash": "4.17.21"
18
18
  },
19
19
  "devDependencies": {
20
- "@verdaccio/logger": "8.0.0-next-8.3",
21
- "@verdaccio/core": "8.0.0-next-8.3",
22
- "@verdaccio/config": "8.0.0-next-8.3",
23
- "@verdaccio/types": "13.0.0-next-8.1",
20
+ "@verdaccio/logger": "8.0.0-next-8.5",
21
+ "@verdaccio/core": "8.0.0-next-8.5",
22
+ "@verdaccio/config": "8.0.0-next-8.5",
23
+ "@verdaccio/types": "13.0.0-next-8.2",
24
24
  "@verdaccio-scope/verdaccio-auth-foo": "0.0.2",
25
25
  "customprefix-auth": "2.0.0",
26
- "verdaccio-auth-memory": "13.0.0-next-8.3"
26
+ "verdaccio-auth-memory": "13.0.0-next-8.5"
27
27
  },
28
28
  "homepage": "https://verdaccio.org",
29
29
  "keywords": [
@@ -3,7 +3,6 @@ import fs from 'fs';
3
3
  import { dirname, isAbsolute, join, resolve } from 'path';
4
4
 
5
5
  import { pluginUtils } from '@verdaccio/core';
6
- import { Config, Logger } from '@verdaccio/types';
7
6
 
8
7
  import { PluginType, isES6, isValid, tryLoad } from './utils';
9
8
 
@@ -16,8 +15,6 @@ async function isDirectory(pathFolder: string) {
16
15
  return stat.isDirectory();
17
16
  }
18
17
 
19
- export type Params = { config: Config; logger: Logger };
20
-
21
18
  // type Plugins<T> =
22
19
  // | pluginUtils.Auth<T>
23
20
  // | pluginUtils.Storage<T>
@@ -40,24 +37,25 @@ export type Params = { config: Config; logger: Logger };
40
37
  * The `params` is an object that contains the global configuration and the logger.
41
38
  *
42
39
  * @param {*} pluginConfigs the custom plugin section
43
- * @param {*} params a set of params to initialize the plugin
40
+ * @param {*} pluginOptions a set of options to initialize the plugin
44
41
  * @param {*} sanityCheck callback that check the shape that should fulfill the plugin
45
42
  * @param {*} prefix by default is verdaccio but can be override with config.server.pluginPrefix
43
+ * @param {*} pluginCategory the category of the plugin, eg: auth, storage, middleware
46
44
  * @return {Array} list of plugins
47
45
  */
48
46
  export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
49
47
  pluginConfigs: any = {},
50
- params: Params,
48
+ pluginOptions: pluginUtils.PluginOptions,
51
49
  sanityCheck: (plugin: PluginType<T>) => boolean,
52
50
  prefix: string = 'verdaccio',
53
51
  pluginCategory: string = ''
54
52
  ): Promise<PluginType<T>[]> {
55
- const logger = params?.logger;
53
+ const logger = pluginOptions?.logger;
56
54
  const pluginsIds = Object.keys(pluginConfigs);
57
- const { config } = params;
55
+ const { config } = pluginOptions;
58
56
  let plugins: PluginType<T>[] = [];
59
57
  for (let pluginId of pluginsIds) {
60
- debug('plugin %s', pluginId);
58
+ debug('looking for plugin %o', pluginId);
61
59
  if (typeof config.plugins === 'string') {
62
60
  let pluginsPath = config.plugins;
63
61
  debug('plugin path %s', pluginsPath);
@@ -84,7 +82,7 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
84
82
  logger.error(a, b);
85
83
  });
86
84
  if (plugin && isValid(plugin)) {
87
- plugin = executePlugin(plugin, pluginConfigs[pluginId], params);
85
+ plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);
88
86
  if (!sanityCheck(plugin)) {
89
87
  logger.error(
90
88
  { content: externalFilePlugin },
@@ -109,14 +107,14 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
109
107
 
110
108
  if (typeof pluginId === 'string') {
111
109
  const isScoped: boolean = pluginId.startsWith('@') && pluginId.includes('/');
112
- debug('is scoped plugin %s', isScoped);
110
+ debug('is scoped plugin: %s', isScoped);
113
111
  const pluginName = isScoped ? pluginId : `${prefix}-${pluginId}`;
114
- debug('plugin pkg name %s', pluginName);
112
+ debug('plugin package name %s', pluginName);
115
113
  let plugin = tryLoad<T>(pluginName, (a: any, b: any) => {
116
114
  logger.error(a, b);
117
115
  });
118
116
  if (plugin && isValid(plugin)) {
119
- plugin = executePlugin(plugin, pluginConfigs[pluginId], params);
117
+ plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);
120
118
  if (!sanityCheck(plugin)) {
121
119
  logger.error({ content: pluginName }, "@{content} doesn't look like a valid plugin");
122
120
  continue;
@@ -136,23 +134,23 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
136
134
  }
137
135
  }
138
136
  }
139
- debug('plugin found %s', plugins.length);
137
+ debug('%s plugins found: %s', pluginCategory, plugins.length);
140
138
  return plugins;
141
139
  }
142
140
 
143
141
  export function executePlugin<T>(
144
142
  plugin: PluginType<T>,
145
143
  pluginConfig: unknown,
146
- params: Params
144
+ pluginOptions: pluginUtils.PluginOptions
147
145
  ): PluginType<T> {
148
146
  if (isES6(plugin)) {
149
147
  debug('plugin is ES6');
150
148
  // @ts-expect-error no relevant for the code
151
149
  // eslint-disable-next-line new-cap
152
- return new plugin.default(pluginConfig, params) as Plugin;
150
+ return new plugin.default(pluginConfig, pluginOptions) as Plugin;
153
151
  } else {
154
152
  debug('plugin is commonJS');
155
153
  // @ts-expect-error improve this type
156
- return plugin(pluginConfig, params) as PluginType<T>;
154
+ return plugin(pluginConfig, pluginOptions) as PluginType<T>;
157
155
  }
158
156
  }
@@ -0,0 +1,3 @@
1
+ store:
2
+ plugin-store:
3
+ enabled: true
@@ -0,0 +1,7 @@
1
+ function ValidVerdaccioPlugin() {
2
+ return {
3
+ getPackageStorage: function () {},
4
+ };
5
+ }
6
+
7
+ module.exports = ValidVerdaccioPlugin;
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "verdaccio-plugin",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "author": "",
10
+ "license": "ISC"
11
+ }
@@ -15,6 +15,9 @@ function getConfig(file: string) {
15
15
  const authSanitize = function (plugin) {
16
16
  return plugin.authenticate || plugin.allow_access || plugin.allow_publish;
17
17
  };
18
+ const storeSanitize = function (plugin) {
19
+ return typeof plugin.getPackageStorage !== 'undefined';
20
+ };
18
21
 
19
22
  const pluginsPartialsFolder = path.join(__dirname, './partials/test-plugin-storage');
20
23
 
@@ -31,13 +34,17 @@ describe('plugin loader', () => {
31
34
  expect(plugins).toHaveLength(1);
32
35
  });
33
36
 
37
+ test('testing storage valid plugin loader', async () => {
38
+ const config = getConfig('valid-plugin-store.yaml');
39
+ config.plugins = pluginsPartialsFolder;
40
+ const plugins = await asyncLoadPlugin(config.store, { config, logger }, storeSanitize);
41
+
42
+ expect(plugins).toHaveLength(1);
43
+ });
44
+
34
45
  test('should handle does not exist plugin folder', async () => {
35
46
  const config = getConfig('plugins-folder-fake.yaml');
36
- const plugins = await asyncLoadPlugin(
37
- config.auth,
38
- { logger: logger, config: config },
39
- authSanitize
40
- );
47
+ const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
41
48
 
42
49
  expect(plugins).toHaveLength(0);
43
50
  });
@@ -59,11 +66,7 @@ describe('plugin loader', () => {
59
66
  const config = getConfig('plugins-folder-fake.yaml');
60
67
  // force file instead a folder.
61
68
  config.plugins = path.join(__dirname, 'just-a-file.js');
62
- const plugins = await asyncLoadPlugin(
63
- config.auth,
64
- { logger: logger, config: config },
65
- authSanitize
66
- );
69
+ const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
67
70
 
68
71
  expect(plugins).toHaveLength(0);
69
72
  });
@@ -72,11 +75,7 @@ describe('plugin loader', () => {
72
75
  test('should resolve plugin based on relative path', async () => {
73
76
  const config = getConfig('relative-plugins.yaml');
74
77
  // force file instead a folder.
75
- const plugins = await asyncLoadPlugin(
76
- config.auth,
77
- { logger: logger, config: config },
78
- authSanitize
79
- );
78
+ const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
80
79
 
81
80
  expect(plugins).toHaveLength(1);
82
81
  });
@@ -88,11 +87,7 @@ describe('plugin loader', () => {
88
87
  // @ts-expect-error
89
88
  config.config_path = undefined;
90
89
  // force file instead a folder.
91
- const plugins = await asyncLoadPlugin(
92
- config.auth,
93
- { logger: logger, config: config },
94
- authSanitize
95
- );
90
+ const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
96
91
 
97
92
  expect(plugins).toHaveLength(0);
98
93
  });
@@ -103,11 +98,7 @@ describe('plugin loader', () => {
103
98
  // @ts-expect-error
104
99
  config.configPath = undefined;
105
100
  // force file instead a folder.
106
- const plugins = await asyncLoadPlugin(
107
- config.auth,
108
- { logger: logger, config: config },
109
- authSanitize
110
- );
101
+ const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
111
102
 
112
103
  expect(plugins).toHaveLength(0);
113
104
  });