diff --git a/docs/development/core/public/kibana-plugin-public.plugin.md b/docs/development/core/public/kibana-plugin-public.plugin.md
index 7a47ca7b97f6..51d44cd8cf14 100644
--- a/docs/development/core/public/kibana-plugin-public.plugin.md
+++ b/docs/development/core/public/kibana-plugin-public.plugin.md
@@ -7,13 +7,13 @@ The interface that should be returned by a `PluginInitializer`.
Signature:
```typescript
-export interface Plugin =
+export interface Plugin =
```
## Properties
| Property | Type | Description |
| --- | --- | --- |
-| [setup](./kibana-plugin-public.plugin.setup.md) | (core: PluginSetupContext, dependencies: TDependencies) => TSetup | Promise<TSetup>
| |
+| [setup](./kibana-plugin-public.plugin.setup.md) | (core: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise<TSetup>
| |
| [stop](./kibana-plugin-public.plugin.stop.md) | () => void
| |
diff --git a/docs/development/core/public/kibana-plugin-public.plugin.setup.md b/docs/development/core/public/kibana-plugin-public.plugin.setup.md
index b2ebc4ca4f94..b011bc3ba010 100644
--- a/docs/development/core/public/kibana-plugin-public.plugin.setup.md
+++ b/docs/development/core/public/kibana-plugin-public.plugin.setup.md
@@ -5,5 +5,5 @@
Signature:
```typescript
-setup: (core: PluginSetupContext, dependencies: TDependencies) => TSetup | Promise;
+setup: (core: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise;
```
diff --git a/docs/development/core/public/kibana-plugin-public.plugininitializer.md b/docs/development/core/public/kibana-plugin-public.plugininitializer.md
index 3f288746ce31..6e3edf8d053e 100644
--- a/docs/development/core/public/kibana-plugin-public.plugininitializer.md
+++ b/docs/development/core/public/kibana-plugin-public.plugininitializer.md
@@ -7,5 +7,5 @@ The `plugin` export at the root of a plugin's `public` directory should conform
Signature:
```typescript
-export declare type PluginInitializer = {}> = (core: PluginInitializerContext) => Plugin;
+export declare type PluginInitializer = {}> = (core: PluginInitializerContext) => Plugin;
```
diff --git a/docs/development/core/server/kibana-plugin-server.md b/docs/development/core/server/kibana-plugin-server.md
index 960ad262d163..1071b039c080 100644
--- a/docs/development/core/server/kibana-plugin-server.md
+++ b/docs/development/core/server/kibana-plugin-server.md
@@ -20,6 +20,7 @@
| [Logger](./kibana-plugin-server.logger.md) | Logger exposes all the necessary methods to log any type of information and this is the interface used by the logging consumers including plugins. |
| [LoggerFactory](./kibana-plugin-server.loggerfactory.md) | The single purpose of LoggerFactory
interface is to define a way to retrieve a context-based logger instance. |
| [LogMeta](./kibana-plugin-server.logmeta.md) | Contextual metadata |
+| [Plugin](./kibana-plugin-server.plugin.md) | The interface that should be returned by a PluginInitializer
. |
| [PluginInitializerContext](./kibana-plugin-server.plugininitializercontext.md) | Context that's available to plugins during initialization stage. |
| [PluginSetupContext](./kibana-plugin-server.pluginsetupcontext.md) | Context passed to the plugins setup
method. |
@@ -30,5 +31,6 @@
| [APICaller](./kibana-plugin-server.apicaller.md) | |
| [ElasticsearchClientConfig](./kibana-plugin-server.elasticsearchclientconfig.md) | |
| [Headers](./kibana-plugin-server.headers.md) | |
+| [PluginInitializer](./kibana-plugin-server.plugininitializer.md) | The plugin
export at the root of a plugin's server
directory should conform to this interface. |
| [PluginName](./kibana-plugin-server.pluginname.md) | Dedicated type for plugin name/id that is supposed to make Map/Set/Arrays that use it as a key or value more obvious. |
diff --git a/docs/development/core/server/kibana-plugin-server.plugin.md b/docs/development/core/server/kibana-plugin-server.plugin.md
new file mode 100644
index 000000000000..b538f0e7926c
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.plugin.md
@@ -0,0 +1,19 @@
+[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [Plugin](./kibana-plugin-server.plugin.md)
+
+## Plugin interface
+
+The interface that should be returned by a `PluginInitializer`.
+
+Signature:
+
+```typescript
+export interface Plugin =
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [setup](./kibana-plugin-server.plugin.setup.md) | (pluginSetupContext: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise<TSetup>
| |
+| [stop](./kibana-plugin-server.plugin.stop.md) | () => void
| |
+
diff --git a/docs/development/core/server/kibana-plugin-server.plugin.setup.md b/docs/development/core/server/kibana-plugin-server.plugin.setup.md
new file mode 100644
index 000000000000..b732df204afb
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.plugin.setup.md
@@ -0,0 +1,9 @@
+[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [Plugin](./kibana-plugin-server.plugin.md) > [setup](./kibana-plugin-server.plugin.setup.md)
+
+## Plugin.setup property
+
+Signature:
+
+```typescript
+setup: (pluginSetupContext: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.plugin.stop.md b/docs/development/core/server/kibana-plugin-server.plugin.stop.md
new file mode 100644
index 000000000000..e2c51b2fc147
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.plugin.stop.md
@@ -0,0 +1,9 @@
+[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [Plugin](./kibana-plugin-server.plugin.md) > [stop](./kibana-plugin-server.plugin.stop.md)
+
+## Plugin.stop property
+
+Signature:
+
+```typescript
+stop?: () => void;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.plugininitializer.md b/docs/development/core/server/kibana-plugin-server.plugininitializer.md
new file mode 100644
index 000000000000..78ff0dea3391
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.plugininitializer.md
@@ -0,0 +1,11 @@
+[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [PluginInitializer](./kibana-plugin-server.plugininitializer.md)
+
+## PluginInitializer type
+
+The `plugin` export at the root of a plugin's `server` directory should conform to this interface.
+
+Signature:
+
+```typescript
+export declare type PluginInitializer = {}> = (coreContext: PluginInitializerContext) => Plugin;
+```
diff --git a/src/core/public/kibana.api.md b/src/core/public/kibana.api.md
index ae9ca480ed45..9dca4df6a0c5 100644
--- a/src/core/public/kibana.api.md
+++ b/src/core/public/kibana.api.md
@@ -176,15 +176,15 @@ export interface OverlaySetup {
}
// @public
-export interface Plugin = {}> {
+export interface Plugin = {}> {
// (undocumented)
- setup: (core: PluginSetupContext, dependencies: TDependencies) => TSetup | Promise;
+ setup: (core: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise;
// (undocumented)
stop?: () => void;
}
// @public
-export type PluginInitializer = {}> = (core: PluginInitializerContext) => Plugin;
+export type PluginInitializer = {}> = (core: PluginInitializerContext) => Plugin;
// @public
export interface PluginInitializerContext {
diff --git a/src/core/public/plugins/plugin.ts b/src/core/public/plugins/plugin.ts
index 54e54457c110..9b9a3f19dc00 100644
--- a/src/core/public/plugins/plugin.ts
+++ b/src/core/public/plugins/plugin.ts
@@ -26,8 +26,8 @@ import { loadPluginBundle } from './plugin_loader';
*
* @public
*/
-export interface Plugin = {}> {
- setup: (core: PluginSetupContext, dependencies: TDependencies) => TSetup | Promise;
+export interface Plugin = {}> {
+ setup: (core: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise;
stop?: () => void;
}
@@ -37,9 +37,9 @@ export interface Plugin =
*
* @public
*/
-export type PluginInitializer = {}> = (
+export type PluginInitializer = {}> = (
core: PluginInitializerContext
-) => Plugin;
+) => Plugin;
/**
* Lightweight wrapper around discovered plugin that is responsible for instantiating
@@ -49,14 +49,14 @@ export type PluginInitializer = Record
+ TPluginsSetup extends Record = Record
> {
public readonly name: DiscoveredPlugin['id'];
public readonly configPath: DiscoveredPlugin['configPath'];
- public readonly requiredDependencies: DiscoveredPlugin['requiredPlugins'];
- public readonly optionalDependencies: DiscoveredPlugin['optionalPlugins'];
- private initializer?: PluginInitializer;
- private instance?: Plugin;
+ public readonly requiredPlugins: DiscoveredPlugin['requiredPlugins'];
+ public readonly optionalPlugins: DiscoveredPlugin['optionalPlugins'];
+ private initializer?: PluginInitializer;
+ private instance?: Plugin;
constructor(
readonly discoveredPlugin: DiscoveredPlugin,
@@ -64,8 +64,8 @@ export class PluginWrapper<
) {
this.name = discoveredPlugin.id;
this.configPath = discoveredPlugin.configPath;
- this.requiredDependencies = discoveredPlugin.requiredPlugins;
- this.optionalDependencies = discoveredPlugin.optionalPlugins;
+ this.requiredPlugins = discoveredPlugin.requiredPlugins;
+ this.optionalPlugins = discoveredPlugin.optionalPlugins;
}
/**
@@ -74,20 +74,20 @@ export class PluginWrapper<
* @param addBasePath Function that adds the base path to a string for plugin bundle path.
*/
public async load(addBasePath: (path: string) => string) {
- this.initializer = await loadPluginBundle(addBasePath, this.name);
+ this.initializer = await loadPluginBundle(addBasePath, this.name);
}
/**
* Instantiates plugin and calls `setup` function exposed by the plugin initializer.
* @param setupContext Context that consists of various core services tailored specifically
* for the `setup` lifecycle event.
- * @param dependencies The dictionary where the key is the dependency name and the value
+ * @param plugins The dictionary where the key is the dependency name and the value
* is the contract returned by the dependency's `setup` function.
*/
- public async setup(setupContext: PluginSetupContext, dependencies: TDependenciesSetup) {
+ public async setup(setupContext: PluginSetupContext, plugins: TPluginsSetup) {
this.instance = await this.createPluginInstance();
- return await this.instance.setup(setupContext, dependencies);
+ return await this.instance.setup(setupContext, plugins);
}
/**
diff --git a/src/core/public/plugins/plugins_service.ts b/src/core/public/plugins/plugins_service.ts
index 544739cff2c7..0a157067aef5 100644
--- a/src/core/public/plugins/plugins_service.ts
+++ b/src/core/public/plugins/plugins_service.ts
@@ -62,34 +62,35 @@ export class PluginsService implements CoreService {
// Load plugin bundles
await this.loadPluginBundles(deps.basePath.addToPath);
- // Setup each plugin with correct dependencies
+ // Setup each plugin with required and optional plugin contracts
const contracts = new Map();
for (const [pluginName, plugin] of this.plugins.entries()) {
- const dependencies = new Set([
- ...plugin.requiredDependencies,
- ...plugin.optionalDependencies.filter(optPlugin => this.plugins.get(optPlugin)),
+ const pluginDeps = new Set([
+ ...plugin.requiredPlugins,
+ ...plugin.optionalPlugins.filter(optPlugin => this.plugins.get(optPlugin)),
]);
- const dependencyContracts = [...dependencies.keys()].reduce(
- (depContracts, dependency) => {
+ const pluginDepContracts = [...pluginDeps.keys()].reduce(
+ (depContracts, dependencyName) => {
// Only set if present. Could be absent if plugin does not have client-side code or is a
- // missing optional dependency.
- if (contracts.get(dependency) !== undefined) {
- depContracts[dependency] = contracts.get(dependency);
+ // missing optional plugin.
+ if (contracts.has(dependencyName)) {
+ depContracts[dependencyName] = contracts.get(dependencyName);
}
return depContracts;
},
- {} as { [dep: string]: unknown }
+ {} as Record
);
contracts.set(
pluginName,
await plugin.setup(
createPluginSetupContext(this.coreContext, deps, plugin),
- dependencyContracts
+ pluginDepContracts
)
);
+
this.satupPlugins.push(pluginName);
}
@@ -98,7 +99,7 @@ export class PluginsService implements CoreService {
}
public async stop() {
- // Stop plugins in reverse dependency order.
+ // Stop plugins in reverse topological order.
for (const pluginName of this.satupPlugins.reverse()) {
this.plugins.get(pluginName)!.stop();
}
diff --git a/src/core/server/index.ts b/src/core/server/index.ts
index ef42f6abe5f0..a1beb6114e72 100644
--- a/src/core/server/index.ts
+++ b/src/core/server/index.ts
@@ -31,8 +31,11 @@ export {
APICaller,
} from './elasticsearch';
export { Logger, LoggerFactory, LogMeta, LogRecord, LogLevel } from './logging';
+
export {
DiscoveredPlugin,
+ Plugin,
+ PluginInitializer,
PluginInitializerContext,
PluginName,
PluginSetupContext,
diff --git a/src/core/server/kibana.api.md b/src/core/server/kibana.api.md
index ebc1a1532391..54053c1e8436 100644
--- a/src/core/server/kibana.api.md
+++ b/src/core/server/kibana.api.md
@@ -187,6 +187,17 @@ export interface LogRecord {
timestamp: Date;
}
+// @public
+export interface Plugin = {}> {
+ // (undocumented)
+ setup: (pluginSetupContext: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise;
+ // (undocumented)
+ stop?: () => void;
+}
+
+// @public
+export type PluginInitializer = {}> = (coreContext: PluginInitializerContext) => Plugin;
+
// @public
export interface PluginInitializerContext {
// (undocumented)
diff --git a/src/core/server/plugins/discovery/plugin_discovery.test.ts b/src/core/server/plugins/discovery/plugin_discovery.test.ts
index 2e3ba501feb1..f897fe1527aa 100644
--- a/src/core/server/plugins/discovery/plugin_discovery.test.ts
+++ b/src/core/server/plugins/discovery/plugin_discovery.test.ts
@@ -25,7 +25,7 @@ import { first, map, toArray } from 'rxjs/operators';
import { Config, ConfigService, Env, ObjectToConfigAdapter } from '../../config';
import { getEnvOptions } from '../../config/__mocks__/env';
import { loggingServiceMock } from '../../logging/logging_service.mock';
-import { Plugin } from '../plugin';
+import { PluginWrapper } from '../plugin';
import { PluginsConfig } from '../plugins_config';
import { discover } from './plugins_discovery';
@@ -142,10 +142,10 @@ test('properly iterates through plugin search locations', async () => {
TEST_EXTRA_PLUGIN_PATH,
]) {
const discoveredPlugin = plugins.find(plugin => plugin.path === path)!;
- expect(discoveredPlugin).toBeInstanceOf(Plugin);
+ expect(discoveredPlugin).toBeInstanceOf(PluginWrapper);
expect(discoveredPlugin.configPath).toEqual(['core', 'config']);
- expect(discoveredPlugin.requiredDependencies).toEqual(['a', 'b']);
- expect(discoveredPlugin.optionalDependencies).toEqual(['c', 'd']);
+ expect(discoveredPlugin.requiredPlugins).toEqual(['a', 'b']);
+ expect(discoveredPlugin.optionalPlugins).toEqual(['c', 'd']);
}
await expect(
diff --git a/src/core/server/plugins/discovery/plugins_discovery.ts b/src/core/server/plugins/discovery/plugins_discovery.ts
index 8bf28eeb2d50..f9ab37913bcc 100644
--- a/src/core/server/plugins/discovery/plugins_discovery.ts
+++ b/src/core/server/plugins/discovery/plugins_discovery.ts
@@ -23,7 +23,7 @@ import { bindNodeCallback, from, merge } from 'rxjs';
import { catchError, filter, map, mergeMap, shareReplay } from 'rxjs/operators';
import { CoreContext } from '../../core_context';
import { Logger } from '../../logging';
-import { Plugin } from '../plugin';
+import { PluginWrapper } from '../plugin';
import { createPluginInitializerContext } from '../plugin_context';
import { PluginsConfig } from '../plugins_config';
import { PluginDiscoveryError } from './plugin_discovery_error';
@@ -67,9 +67,11 @@ export function discover(config: PluginsConfig, coreContext: CoreContext) {
);
return {
- plugin$: discoveryResults$.pipe(filter((entry): entry is Plugin => entry instanceof Plugin)),
+ plugin$: discoveryResults$.pipe(
+ filter((entry): entry is PluginWrapper => entry instanceof PluginWrapper)
+ ),
error$: discoveryResults$.pipe(
- filter((entry): entry is PluginDiscoveryError => !(entry instanceof Plugin))
+ filter((entry): entry is PluginDiscoveryError => !(entry instanceof PluginWrapper))
),
};
}
@@ -115,7 +117,11 @@ function createPlugin$(path: string, log: Logger, coreContext: CoreContext) {
return from(parseManifest(path, coreContext.env.packageInfo)).pipe(
map(manifest => {
log.debug(`Successfully discovered plugin "${manifest.id}" at "${path}"`);
- return new Plugin(path, manifest, createPluginInitializerContext(coreContext, manifest));
+ return new PluginWrapper(
+ path,
+ manifest,
+ createPluginInitializerContext(coreContext, manifest)
+ );
}),
catchError(err => [err])
);
diff --git a/src/core/server/plugins/index.ts b/src/core/server/plugins/index.ts
index 036fd20c7993..8469e21783f0 100644
--- a/src/core/server/plugins/index.ts
+++ b/src/core/server/plugins/index.ts
@@ -22,5 +22,11 @@ export { PluginsService, PluginsServiceSetup } from './plugins_service';
/** @internal */
export { isNewPlatformPlugin } from './discovery';
/** @internal */
-export { DiscoveredPlugin, DiscoveredPluginInternal, PluginName } from './plugin';
+export {
+ DiscoveredPlugin,
+ DiscoveredPluginInternal,
+ Plugin,
+ PluginInitializer,
+ PluginName,
+} from './plugin';
export { PluginInitializerContext, PluginSetupContext } from './plugin_context';
diff --git a/src/core/server/plugins/plugin.test.ts b/src/core/server/plugins/plugin.test.ts
index 2f2a73668a59..7acc0d2e76a4 100644
--- a/src/core/server/plugins/plugin.test.ts
+++ b/src/core/server/plugins/plugin.test.ts
@@ -25,7 +25,7 @@ import { CoreContext } from '../core_context';
import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
import { loggingServiceMock } from '../logging/logging_service.mock';
-import { Plugin, PluginManifest } from './plugin';
+import { PluginWrapper, PluginManifest } from './plugin';
import { createPluginInitializerContext, createPluginSetupContext } from './plugin_context';
const mockPluginInitializer = jest.fn();
@@ -78,7 +78,7 @@ afterEach(() => {
test('`constructor` correctly initializes plugin instance', () => {
const manifest = createPluginManifest();
- const plugin = new Plugin(
+ const plugin = new PluginWrapper(
'some-plugin-path',
manifest,
createPluginInitializerContext(coreContext, manifest)
@@ -87,13 +87,13 @@ test('`constructor` correctly initializes plugin instance', () => {
expect(plugin.name).toBe('some-plugin-id');
expect(plugin.configPath).toBe('path');
expect(plugin.path).toBe('some-plugin-path');
- expect(plugin.requiredDependencies).toEqual(['some-required-dep']);
- expect(plugin.optionalDependencies).toEqual(['some-optional-dep']);
+ expect(plugin.requiredPlugins).toEqual(['some-required-dep']);
+ expect(plugin.optionalPlugins).toEqual(['some-optional-dep']);
});
test('`setup` fails if `plugin` initializer is not exported', async () => {
const manifest = createPluginManifest();
- const plugin = new Plugin(
+ const plugin = new PluginWrapper(
'plugin-without-initializer-path',
manifest,
createPluginInitializerContext(coreContext, manifest)
@@ -108,7 +108,7 @@ test('`setup` fails if `plugin` initializer is not exported', async () => {
test('`setup` fails if plugin initializer is not a function', async () => {
const manifest = createPluginManifest();
- const plugin = new Plugin(
+ const plugin = new PluginWrapper(
'plugin-with-wrong-initializer-path',
manifest,
createPluginInitializerContext(coreContext, manifest)
@@ -123,7 +123,7 @@ test('`setup` fails if plugin initializer is not a function', async () => {
test('`setup` fails if initializer does not return object', async () => {
const manifest = createPluginManifest();
- const plugin = new Plugin(
+ const plugin = new PluginWrapper(
'plugin-with-initializer-path',
manifest,
createPluginInitializerContext(coreContext, manifest)
@@ -140,7 +140,7 @@ test('`setup` fails if initializer does not return object', async () => {
test('`setup` fails if object returned from initializer does not define `setup` function', async () => {
const manifest = createPluginManifest();
- const plugin = new Plugin(
+ const plugin = new PluginWrapper(
'plugin-with-initializer-path',
manifest,
createPluginInitializerContext(coreContext, manifest)
@@ -159,7 +159,7 @@ test('`setup` fails if object returned from initializer does not define `setup`
test('`setup` initializes plugin and calls appropriate lifecycle hook', async () => {
const manifest = createPluginManifest();
const initializerContext = createPluginInitializerContext(coreContext, manifest);
- const plugin = new Plugin('plugin-with-initializer-path', manifest, initializerContext);
+ const plugin = new PluginWrapper('plugin-with-initializer-path', manifest, initializerContext);
const mockPluginInstance = { setup: jest.fn().mockResolvedValue({ contract: 'yes' }) };
mockPluginInitializer.mockReturnValue(mockPluginInstance);
@@ -177,7 +177,7 @@ test('`setup` initializes plugin and calls appropriate lifecycle hook', async ()
test('`stop` fails if plugin is not set up', async () => {
const manifest = createPluginManifest();
- const plugin = new Plugin(
+ const plugin = new PluginWrapper(
'plugin-with-initializer-path',
manifest,
createPluginInitializerContext(coreContext, manifest)
@@ -194,7 +194,7 @@ test('`stop` fails if plugin is not set up', async () => {
test('`stop` does nothing if plugin does not define `stop` function', async () => {
const manifest = createPluginManifest();
- const plugin = new Plugin(
+ const plugin = new PluginWrapper(
'plugin-with-initializer-path',
manifest,
createPluginInitializerContext(coreContext, manifest)
@@ -208,7 +208,7 @@ test('`stop` does nothing if plugin does not define `stop` function', async () =
test('`stop` calls `stop` defined by the plugin instance', async () => {
const manifest = createPluginManifest();
- const plugin = new Plugin(
+ const plugin = new PluginWrapper(
'plugin-with-initializer-path',
manifest,
createPluginInitializerContext(coreContext, manifest)
diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts
index 8669f8353b71..5e23fb3b8b30 100644
--- a/src/core/server/plugins/plugin.ts
+++ b/src/core/server/plugins/plugin.ts
@@ -124,15 +124,28 @@ export interface DiscoveredPluginInternal extends DiscoveredPlugin {
readonly path: string;
}
-type PluginInitializer> = (
- coreContext: PluginInitializerContext
-) => {
+/**
+ * The interface that should be returned by a `PluginInitializer`.
+ *
+ * @public
+ */
+export interface Plugin = {}> {
setup: (
pluginSetupContext: PluginSetupContext,
- dependencies: TDependenciesSetup
- ) => TExposedSetup;
+ plugins: TPluginsSetup
+ ) => TSetup | Promise;
stop?: () => void;
-};
+}
+
+/**
+ * The `plugin` export at the root of a plugin's `server` directory should conform
+ * to this interface.
+ *
+ * @public
+ */
+export type PluginInitializer = {}> = (
+ coreContext: PluginInitializerContext
+) => Plugin;
/**
* Lightweight wrapper around discovered plugin that is responsible for instantiating
@@ -140,20 +153,20 @@ type PluginInitializer = Record
+ TPluginsSetup extends Record = Record
> {
public readonly name: PluginManifest['id'];
public readonly configPath: PluginManifest['configPath'];
- public readonly requiredDependencies: PluginManifest['requiredPlugins'];
- public readonly optionalDependencies: PluginManifest['optionalPlugins'];
+ public readonly requiredPlugins: PluginManifest['requiredPlugins'];
+ public readonly optionalPlugins: PluginManifest['optionalPlugins'];
public readonly includesServerPlugin: PluginManifest['server'];
public readonly includesUiPlugin: PluginManifest['ui'];
private readonly log: Logger;
- private instance?: ReturnType>;
+ private instance?: Plugin;
constructor(
public readonly path: string,
@@ -163,8 +176,8 @@ export class Plugin<
this.log = initializerContext.logger.get();
this.name = manifest.id;
this.configPath = manifest.configPath;
- this.requiredDependencies = manifest.requiredPlugins;
- this.optionalDependencies = manifest.optionalPlugins;
+ this.requiredPlugins = manifest.requiredPlugins;
+ this.optionalPlugins = manifest.optionalPlugins;
this.includesServerPlugin = manifest.server;
this.includesUiPlugin = manifest.ui;
}
@@ -173,15 +186,15 @@ export class Plugin<
* Instantiates plugin and calls `setup` function exposed by the plugin initializer.
* @param setupContext Context that consists of various core services tailored specifically
* for the `setup` lifecycle event.
- * @param dependencies The dictionary where the key is the dependency name and the value
+ * @param plugins The dictionary where the key is the dependency name and the value
* is the contract returned by the dependency's `setup` function.
*/
- public async setup(setupContext: PluginSetupContext, dependencies: TDependenciesSetup) {
+ public async setup(setupContext: PluginSetupContext, plugins: TPluginsSetup) {
this.instance = this.createPluginInstance();
this.log.info('Setting up plugin');
- return await this.instance.setup(setupContext, dependencies);
+ return await this.instance.setup(setupContext, plugins);
}
/**
@@ -211,7 +224,7 @@ export class Plugin<
}
const { plugin: initializer } = pluginDefinition as {
- plugin: PluginInitializer;
+ plugin: PluginInitializer;
};
if (!initializer || typeof initializer !== 'function') {
throw new Error(`Definition of plugin "${this.name}" should be a function (${this.path}).`);
diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts
index 4571966af5bb..af438ff3759d 100644
--- a/src/core/server/plugins/plugin_context.ts
+++ b/src/core/server/plugins/plugin_context.ts
@@ -23,7 +23,7 @@ import { ConfigWithSchema, EnvironmentMode } from '../config';
import { CoreContext } from '../core_context';
import { ClusterClient } from '../elasticsearch';
import { LoggerFactory } from '../logging';
-import { Plugin, PluginManifest } from './plugin';
+import { PluginWrapper, PluginManifest } from './plugin';
import { PluginsServiceSetupDeps } from './plugins_service';
/**
@@ -126,7 +126,7 @@ export function createPluginInitializerContext(
export function createPluginSetupContext(
coreContext: CoreContext,
deps: PluginsServiceSetupDeps,
- plugin: Plugin
+ plugin: PluginWrapper
): PluginSetupContext {
return {
elasticsearch: {
diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts
index a7dc8bd5e003..305d75a5dcc7 100644
--- a/src/core/server/plugins/plugins_service.test.ts
+++ b/src/core/server/plugins/plugins_service.test.ts
@@ -27,7 +27,7 @@ import { getEnvOptions } from '../config/__mocks__/env';
import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
import { loggingServiceMock } from '../logging/logging_service.mock';
import { PluginDiscoveryError } from './discovery';
-import { Plugin } from './plugin';
+import { PluginWrapper } from './plugin';
import { PluginsService } from './plugins_service';
import { PluginsSystem } from './plugins_system';
@@ -110,7 +110,7 @@ test('`setup` throws if discovered plugins with conflicting names', async () =>
mockDiscover.mockReturnValue({
error$: from([]),
plugin$: from([
- new Plugin(
+ new PluginWrapper(
'path-4',
{
id: 'conflicting-id',
@@ -124,7 +124,7 @@ test('`setup` throws if discovered plugins with conflicting names', async () =>
},
{ logger } as any
),
- new Plugin(
+ new PluginWrapper(
'path-5',
{
id: 'conflicting-id',
@@ -160,7 +160,7 @@ test('`setup` properly detects plugins that should be disabled.', async () => {
mockDiscover.mockReturnValue({
error$: from([]),
plugin$: from([
- new Plugin(
+ new PluginWrapper(
'path-1',
{
id: 'explicitly-disabled-plugin',
@@ -174,7 +174,7 @@ test('`setup` properly detects plugins that should be disabled.', async () => {
},
{ logger } as any
),
- new Plugin(
+ new PluginWrapper(
'path-2',
{
id: 'plugin-with-missing-required-deps',
@@ -188,7 +188,7 @@ test('`setup` properly detects plugins that should be disabled.', async () => {
},
{ logger } as any
),
- new Plugin(
+ new PluginWrapper(
'path-3',
{
id: 'plugin-with-disabled-transitive-dep',
@@ -202,7 +202,7 @@ test('`setup` properly detects plugins that should be disabled.', async () => {
},
{ logger } as any
),
- new Plugin(
+ new PluginWrapper(
'path-4',
{
id: 'another-explicitly-disabled-plugin',
@@ -247,7 +247,7 @@ Array [
});
test('`setup` properly invokes `discover` and ignores non-critical errors.', async () => {
- const firstPlugin = new Plugin(
+ const firstPlugin = new PluginWrapper(
'path-1',
{
id: 'some-id',
@@ -262,7 +262,7 @@ test('`setup` properly invokes `discover` and ignores non-critical errors.', asy
{ logger } as any
);
- const secondPlugin = new Plugin(
+ const secondPlugin = new PluginWrapper(
'path-2',
{
id: 'some-other-id',
diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts
index 9b31ee77333c..dcea3bdf1508 100644
--- a/src/core/server/plugins/plugins_service.ts
+++ b/src/core/server/plugins/plugins_service.ts
@@ -24,7 +24,7 @@ import { CoreContext } from '../core_context';
import { ElasticsearchServiceSetup } from '../elasticsearch/elasticsearch_service';
import { Logger } from '../logging';
import { discover, PluginDiscoveryError, PluginDiscoveryErrorType } from './discovery';
-import { DiscoveredPlugin, DiscoveredPluginInternal, Plugin, PluginName } from './plugin';
+import { DiscoveredPlugin, DiscoveredPluginInternal, PluginWrapper, PluginName } from './plugin';
import { PluginsConfig } from './plugins_config';
import { PluginsSystem } from './plugins_system';
@@ -106,8 +106,11 @@ export class PluginsService implements CoreService {
}
}
- private async handleDiscoveredPlugins(plugin$: Observable) {
- const pluginEnableStatuses = new Map();
+ private async handleDiscoveredPlugins(plugin$: Observable) {
+ const pluginEnableStatuses = new Map<
+ PluginName,
+ { plugin: PluginWrapper; isEnabled: boolean }
+ >();
await plugin$
.pipe(
mergeMap(async plugin => {
@@ -139,13 +142,13 @@ export class PluginsService implements CoreService {
private shouldEnablePlugin(
pluginName: PluginName,
- pluginEnableStatuses: Map
+ pluginEnableStatuses: Map
): boolean {
const pluginInfo = pluginEnableStatuses.get(pluginName);
return (
pluginInfo !== undefined &&
pluginInfo.isEnabled &&
- pluginInfo.plugin.requiredDependencies.every(dependencyName =>
+ pluginInfo.plugin.requiredPlugins.every(dependencyName =>
this.shouldEnablePlugin(dependencyName, pluginEnableStatuses)
)
);
diff --git a/src/core/server/plugins/plugins_system.test.ts b/src/core/server/plugins/plugins_system.test.ts
index 3202a7697bd6..3965e9a8d21b 100644
--- a/src/core/server/plugins/plugins_system.test.ts
+++ b/src/core/server/plugins/plugins_system.test.ts
@@ -25,7 +25,7 @@ import { getEnvOptions } from '../config/__mocks__/env';
import { CoreContext } from '../core_context';
import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
import { loggingServiceMock } from '../logging/logging_service.mock';
-import { Plugin, PluginName } from './plugin';
+import { PluginWrapper, PluginName } from './plugin';
import { PluginsSystem } from './plugins_system';
const logger = loggingServiceMock.create();
@@ -37,7 +37,7 @@ function createPlugin(
server = true,
}: { required?: string[]; optional?: string[]; server?: boolean } = {}
) {
- return new Plugin(
+ return new PluginWrapper(
'some-path',
{
id,
@@ -140,7 +140,7 @@ test('`setupPlugins` correctly orders plugins and returns exposed values', async
createPlugin('order-3', { required: ['order-2'], optional: ['missing-dep'] }),
{ 'order-2': 'added-as-2' },
],
- ] as Array<[Plugin, Record]>);
+ ] as Array<[PluginWrapper, Record]>);
const setupContextMap = new Map();
@@ -251,7 +251,7 @@ test('`uiPlugins` returns ordered Maps of all plugin manifests', async () => {
createPlugin('order-3', { required: ['order-2'], optional: ['missing-dep'] }),
{ 'order-2': 'added-as-2' },
],
- ] as Array<[Plugin, Record]>);
+ ] as Array<[PluginWrapper, Record]>);
[...plugins.keys()].forEach(plugin => {
pluginsSystem.addPlugin(plugin);
diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts
index e58497e4473a..eeb3da0a8386 100644
--- a/src/core/server/plugins/plugins_system.ts
+++ b/src/core/server/plugins/plugins_system.ts
@@ -21,13 +21,13 @@ import { pick } from 'lodash';
import { CoreContext } from '../core_context';
import { Logger } from '../logging';
-import { DiscoveredPlugin, DiscoveredPluginInternal, Plugin, PluginName } from './plugin';
+import { DiscoveredPlugin, DiscoveredPluginInternal, PluginWrapper, PluginName } from './plugin';
import { createPluginSetupContext } from './plugin_context';
import { PluginsServiceSetupDeps } from './plugins_service';
/** @internal */
export class PluginsSystem {
- private readonly plugins = new Map();
+ private readonly plugins = new Map();
private readonly log: Logger;
// `satup`, the past-tense version of the noun `setup`.
private readonly satupPlugins: PluginName[] = [];
@@ -36,14 +36,14 @@ export class PluginsSystem {
this.log = coreContext.logger.get('plugins-system');
}
- public addPlugin(plugin: Plugin) {
+ public addPlugin(plugin: PluginWrapper) {
this.plugins.set(plugin.name, plugin);
}
public async setupPlugins(deps: PluginsServiceSetupDeps) {
- const exposedValues = new Map();
+ const contracts = new Map();
if (this.plugins.size === 0) {
- return exposedValues;
+ return contracts;
}
const sortedPlugins = this.getTopologicallySortedPluginNames();
@@ -57,29 +57,31 @@ export class PluginsSystem {
this.log.debug(`Setting up plugin "${pluginName}"...`);
- const exposedDependencyValues = [
- ...plugin.requiredDependencies,
- ...plugin.optionalDependencies,
- ].reduce(
- (dependencies, dependencyName) => {
- dependencies[dependencyName] = exposedValues.get(dependencyName);
- return dependencies;
+ const pluginDepContracts = [...plugin.requiredPlugins, ...plugin.optionalPlugins].reduce(
+ (depContracts, dependencyName) => {
+ // Only set if present. Could be absent if plugin does not have server-side code or is a
+ // missing optional dependency.
+ if (contracts.has(dependencyName)) {
+ depContracts[dependencyName] = contracts.get(dependencyName);
+ }
+
+ return depContracts;
},
{} as Record
);
- exposedValues.set(
+ contracts.set(
pluginName,
await plugin.setup(
createPluginSetupContext(this.coreContext, deps, plugin),
- exposedDependencyValues
+ pluginDepContracts
)
);
this.satupPlugins.push(pluginName);
}
- return exposedValues;
+ return contracts;
}
public async stopPlugins() {
@@ -151,8 +153,8 @@ export class PluginsSystem {
return [
pluginName,
new Set([
- ...plugin.requiredDependencies,
- ...plugin.optionalDependencies.filter(dependency => this.plugins.has(dependency)),
+ ...plugin.requiredPlugins,
+ ...plugin.optionalPlugins.filter(dependency => this.plugins.has(dependency)),
]),
] as [PluginName, Set];
})