mirror of
https://github.com/outline/outline.git
synced 2025-12-23 03:29:59 -06:00
PluginManager refactor (#6677)
* fix: refactor plugin manager * fix: make id optional * fix: allow add to accept single object * fix: getHooks * fix: tsc * fix: remove id
This commit is contained in:
@@ -1,9 +1,14 @@
|
|||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { Hook, PluginManager } from "@server/utils/PluginManager";
|
||||||
import config from "../plugin.json";
|
import config from "../plugin.json";
|
||||||
import router from "./auth/azure";
|
import router from "./auth/azure";
|
||||||
import env from "./env";
|
import env from "./env";
|
||||||
|
|
||||||
PluginManager.register(PluginType.AuthProvider, router, {
|
const enabled = !!env.AZURE_CLIENT_ID && !!env.AZURE_CLIENT_SECRET;
|
||||||
...config,
|
|
||||||
enabled: !!env.AZURE_CLIENT_ID && !!env.AZURE_CLIENT_SECRET,
|
if (enabled) {
|
||||||
});
|
PluginManager.add({
|
||||||
|
...config,
|
||||||
|
type: Hook.AuthProvider,
|
||||||
|
value: { router, id: config.id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "email",
|
"id": "email",
|
||||||
"name": "Email",
|
"name": "Email",
|
||||||
|
"priority": 200,
|
||||||
"description": "Adds an email magic link authentication provider."
|
"description": "Adds an email magic link authentication provider."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import env from "@server/env";
|
import env from "@server/env";
|
||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { Hook, PluginManager } from "@server/utils/PluginManager";
|
||||||
import config from "../plugin.json";
|
import config from "../plugin.json";
|
||||||
import router from "./auth/email";
|
import router from "./auth/email";
|
||||||
|
|
||||||
PluginManager.register(PluginType.AuthProvider, router, {
|
const enabled = (!!env.SMTP_HOST && !!env.SMTP_USERNAME) || env.isDevelopment;
|
||||||
...config,
|
|
||||||
enabled: (!!env.SMTP_HOST && !!env.SMTP_USERNAME) || env.isDevelopment,
|
if (enabled) {
|
||||||
});
|
PluginManager.add({
|
||||||
|
...config,
|
||||||
|
type: Hook.AuthProvider,
|
||||||
|
value: { router, id: config.id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { PluginManager, Hook } from "@server/utils/PluginManager";
|
||||||
import config from "../plugin.json";
|
import config from "../plugin.json";
|
||||||
import router from "./auth/google";
|
import router from "./auth/google";
|
||||||
import env from "./env";
|
import env from "./env";
|
||||||
|
|
||||||
PluginManager.register(PluginType.AuthProvider, router, {
|
const enabled = !!env.GOOGLE_CLIENT_ID && !!env.GOOGLE_CLIENT_SECRET;
|
||||||
...config,
|
|
||||||
enabled: !!env.GOOGLE_CLIENT_ID && !!env.GOOGLE_CLIENT_SECRET,
|
if (enabled) {
|
||||||
});
|
PluginManager.add({
|
||||||
|
...config,
|
||||||
|
type: Hook.AuthProvider,
|
||||||
|
value: { router, id: config.id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
import {
|
import {
|
||||||
PluginManager,
|
PluginManager,
|
||||||
PluginPriority,
|
PluginPriority,
|
||||||
PluginType,
|
Hook,
|
||||||
} from "@server/utils/PluginManager";
|
} from "@server/utils/PluginManager";
|
||||||
import env from "./env";
|
import env from "./env";
|
||||||
import Iframely from "./iframely";
|
import Iframely from "./iframely";
|
||||||
|
|
||||||
PluginManager.register(PluginType.UnfurlProvider, Iframely.get, {
|
const enabled = !!env.IFRAMELY_API_KEY && !!env.IFRAMELY_URL;
|
||||||
id: "iframely",
|
|
||||||
enabled: !!env.IFRAMELY_API_KEY && !!env.IFRAMELY_URL,
|
|
||||||
|
|
||||||
// Make sure this is last in the stack to be evaluated after all other unfurl providers
|
if (enabled) {
|
||||||
priority: PluginPriority.VeryLow,
|
PluginManager.add([
|
||||||
});
|
{
|
||||||
|
type: Hook.UnfurlProvider,
|
||||||
|
value: Iframely.get,
|
||||||
|
|
||||||
|
// Make sure this is last in the stack to be evaluated after all other unfurl providers
|
||||||
|
priority: PluginPriority.VeryLow,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { PluginManager, Hook } from "@server/utils/PluginManager";
|
||||||
import config from "../plugin.json";
|
import config from "../plugin.json";
|
||||||
import router from "./auth/oidc";
|
import router from "./auth/oidc";
|
||||||
import env from "./env";
|
import env from "./env";
|
||||||
|
|
||||||
PluginManager.register(PluginType.AuthProvider, router, {
|
const enabled = !!(
|
||||||
...config,
|
env.OIDC_CLIENT_ID &&
|
||||||
name: env.OIDC_DISPLAY_NAME || config.name,
|
env.OIDC_CLIENT_SECRET &&
|
||||||
enabled: !!(
|
env.OIDC_AUTH_URI &&
|
||||||
env.OIDC_CLIENT_ID &&
|
env.OIDC_TOKEN_URI &&
|
||||||
env.OIDC_CLIENT_SECRET &&
|
env.OIDC_USERINFO_URI
|
||||||
env.OIDC_AUTH_URI &&
|
);
|
||||||
env.OIDC_TOKEN_URI &&
|
|
||||||
env.OIDC_USERINFO_URI
|
if (enabled) {
|
||||||
),
|
PluginManager.add({
|
||||||
});
|
...config,
|
||||||
|
type: Hook.AuthProvider,
|
||||||
|
value: { router, id: config.id },
|
||||||
|
name: env.OIDC_DISPLAY_NAME || config.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { PluginManager, Hook } from "@server/utils/PluginManager";
|
||||||
import config from "../plugin.json";
|
import config from "../plugin.json";
|
||||||
import hooks from "./api/hooks";
|
import hooks from "./api/hooks";
|
||||||
import router from "./auth/slack";
|
import router from "./auth/slack";
|
||||||
@@ -7,14 +7,21 @@ import SlackProcessor from "./processors/SlackProcessor";
|
|||||||
|
|
||||||
const enabled = !!env.SLACK_CLIENT_ID && !!env.SLACK_CLIENT_SECRET;
|
const enabled = !!env.SLACK_CLIENT_ID && !!env.SLACK_CLIENT_SECRET;
|
||||||
|
|
||||||
PluginManager.register(PluginType.AuthProvider, router, {
|
if (enabled) {
|
||||||
...config,
|
PluginManager.add([
|
||||||
enabled,
|
{
|
||||||
});
|
...config,
|
||||||
|
type: Hook.AuthProvider,
|
||||||
PluginManager.register(PluginType.API, hooks, {
|
value: { router, id: config.id },
|
||||||
...config,
|
},
|
||||||
enabled,
|
{
|
||||||
});
|
...config,
|
||||||
|
type: Hook.API,
|
||||||
PluginManager.registerProcessor(SlackProcessor, { enabled });
|
value: hooks,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: Hook.Processor,
|
||||||
|
value: SlackProcessor,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { existsSync, mkdirSync } from "fs";
|
import { existsSync, mkdirSync } from "fs";
|
||||||
import env from "@server/env";
|
import env from "@server/env";
|
||||||
import Logger from "@server/logging/Logger";
|
import Logger from "@server/logging/Logger";
|
||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import {
|
||||||
|
PluginManager,
|
||||||
|
PluginPriority,
|
||||||
|
Hook,
|
||||||
|
} from "@server/utils/PluginManager";
|
||||||
import router from "./api/files";
|
import router from "./api/files";
|
||||||
|
|
||||||
if (env.FILE_STORAGE === "local") {
|
if (env.FILE_STORAGE === "local") {
|
||||||
@@ -19,13 +23,20 @@ if (env.FILE_STORAGE === "local") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginManager.register(PluginType.API, router, {
|
const enabled = !!(
|
||||||
id: "files",
|
env.FILE_STORAGE_UPLOAD_MAX_SIZE &&
|
||||||
name: "Local file storage",
|
env.FILE_STORAGE_LOCAL_ROOT_DIR &&
|
||||||
description: "Plugin for storing files on the local file system",
|
env.FILE_STORAGE === "local"
|
||||||
enabled: !!(
|
);
|
||||||
env.FILE_STORAGE_UPLOAD_MAX_SIZE &&
|
|
||||||
env.FILE_STORAGE_LOCAL_ROOT_DIR &&
|
if (enabled) {
|
||||||
env.FILE_STORAGE === "local"
|
PluginManager.add([
|
||||||
),
|
{
|
||||||
});
|
name: "Local file storage",
|
||||||
|
description: "Plugin for storing files on the local file system",
|
||||||
|
type: Hook.API,
|
||||||
|
value: router,
|
||||||
|
priority: PluginPriority.Normal,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "webhooks",
|
"id": "webhooks",
|
||||||
"name": "Webhooks",
|
"name": "Webhooks",
|
||||||
|
"priority": 200,
|
||||||
"description": "Adds HTTP webhooks for various events."
|
"description": "Adds HTTP webhooks for various events."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,26 @@
|
|||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { PluginManager, Hook } from "@server/utils/PluginManager";
|
||||||
import config from "../plugin.json";
|
import config from "../plugin.json";
|
||||||
import webhookSubscriptions from "./api/webhookSubscriptions";
|
import webhookSubscriptions from "./api/webhookSubscriptions";
|
||||||
import WebhookProcessor from "./processors/WebhookProcessor";
|
import WebhookProcessor from "./processors/WebhookProcessor";
|
||||||
import CleanupWebhookDeliveriesTask from "./tasks/CleanupWebhookDeliveriesTask";
|
import CleanupWebhookDeliveriesTask from "./tasks/CleanupWebhookDeliveriesTask";
|
||||||
import DeliverWebhookTask from "./tasks/DeliverWebhookTask";
|
import DeliverWebhookTask from "./tasks/DeliverWebhookTask";
|
||||||
|
|
||||||
PluginManager.register(PluginType.API, webhookSubscriptions, config)
|
PluginManager.add([
|
||||||
.registerProcessor(WebhookProcessor)
|
{
|
||||||
.registerTask(DeliverWebhookTask)
|
...config,
|
||||||
.registerTask(CleanupWebhookDeliveriesTask);
|
type: Hook.API,
|
||||||
|
value: webhookSubscriptions,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: Hook.Processor,
|
||||||
|
value: WebhookProcessor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: Hook.Task,
|
||||||
|
value: DeliverWebhookTask,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: Hook.Task,
|
||||||
|
value: CleanupWebhookDeliveriesTask,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { Hook, PluginManager } from "@server/utils/PluginManager";
|
||||||
import { requireDirectory } from "@server/utils/fs";
|
import { requireDirectory } from "@server/utils/fs";
|
||||||
import BaseEmail from "./BaseEmail";
|
import BaseEmail from "./BaseEmail";
|
||||||
|
|
||||||
@@ -14,8 +14,8 @@ requireDirectory<{ default: BaseEmail<any> }>(__dirname).forEach(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
PluginManager.getEnabledPlugins(PluginType.EmailTemplate).forEach((plugin) => {
|
PluginManager.getHooks(Hook.EmailTemplate).forEach((hook) => {
|
||||||
emails[plugin.id] = plugin.value;
|
emails[hook.value.name] = hook.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default emails;
|
export default emails;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import find from "lodash/find";
|
import find from "lodash/find";
|
||||||
import env from "@server/env";
|
import env from "@server/env";
|
||||||
import Team from "@server/models/Team";
|
import Team from "@server/models/Team";
|
||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { Hook, PluginManager } from "@server/utils/PluginManager";
|
||||||
|
|
||||||
export default class AuthenticationHelper {
|
export default class AuthenticationHelper {
|
||||||
/**
|
/**
|
||||||
@@ -12,7 +12,7 @@ export default class AuthenticationHelper {
|
|||||||
* @returns A list of authentication providers
|
* @returns A list of authentication providers
|
||||||
*/
|
*/
|
||||||
public static get providers() {
|
public static get providers() {
|
||||||
return PluginManager.getEnabledPlugins(PluginType.AuthProvider);
|
return PluginManager.getHooks(Hook.AuthProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,11 +26,11 @@ export default class AuthenticationHelper {
|
|||||||
const isCloudHosted = env.isCloudHosted;
|
const isCloudHosted = env.isCloudHosted;
|
||||||
|
|
||||||
return AuthenticationHelper.providers
|
return AuthenticationHelper.providers
|
||||||
.sort((plugin) => (plugin.id === "email" ? 1 : -1))
|
.sort((hook) => (hook.value.id === "email" ? 1 : -1))
|
||||||
.filter((plugin) => {
|
.filter((hook) => {
|
||||||
// Email sign-in is an exception as it does not have an authentication
|
// Email sign-in is an exception as it does not have an authentication
|
||||||
// provider using passport, instead it exists as a boolean option.
|
// provider using passport, instead it exists as a boolean option.
|
||||||
if (plugin.id === "email") {
|
if (hook.value.id === "email") {
|
||||||
return team?.emailSigninEnabled;
|
return team?.emailSigninEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ export default class AuthenticationHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const authProvider = find(team.authenticationProviders, {
|
const authProvider = find(team.authenticationProviders, {
|
||||||
name: plugin.id,
|
name: hook.value.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
// If cloud hosted then the auth provider must be enabled for the team,
|
// If cloud hosted then the auth provider must be enabled for the team,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { signin } from "@shared/utils/routeHelpers";
|
import { signin } from "@shared/utils/routeHelpers";
|
||||||
import { Plugin, PluginType } from "@server/utils/PluginManager";
|
import { Plugin, Hook } from "@server/utils/PluginManager";
|
||||||
|
|
||||||
export default function presentProviderConfig(
|
export default function presentProviderConfig(
|
||||||
config: Plugin<PluginType.AuthProvider>
|
config: Plugin<Hook.AuthProvider>
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
id: config.id,
|
id: config.value.id,
|
||||||
name: config.name,
|
name: config.name,
|
||||||
authUrl: signin(config.id),
|
authUrl: signin(config.value.id),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { Hook, PluginManager } from "@server/utils/PluginManager";
|
||||||
import { requireDirectory } from "@server/utils/fs";
|
import { requireDirectory } from "@server/utils/fs";
|
||||||
import BaseProcessor from "./BaseProcessor";
|
import BaseProcessor from "./BaseProcessor";
|
||||||
|
|
||||||
@@ -13,8 +13,8 @@ requireDirectory<{ default: BaseProcessor }>(__dirname).forEach(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
PluginManager.getEnabledPlugins(PluginType.Processor).forEach((plugin) => {
|
PluginManager.getHooks(Hook.Processor).forEach((hook) => {
|
||||||
processors[plugin.id] = plugin.value;
|
processors[hook.value.name] = hook.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default processors;
|
export default processors;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { Hook, PluginManager } from "@server/utils/PluginManager";
|
||||||
import { requireDirectory } from "@server/utils/fs";
|
import { requireDirectory } from "@server/utils/fs";
|
||||||
import BaseTask from "./BaseTask";
|
import BaseTask from "./BaseTask";
|
||||||
|
|
||||||
@@ -13,8 +13,8 @@ requireDirectory<{ default: BaseTask<any> }>(__dirname).forEach(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
PluginManager.getEnabledPlugins(PluginType.Task).forEach((plugin) => {
|
PluginManager.getHooks(Hook.Task).forEach((hook) => {
|
||||||
tasks[plugin.id] = plugin.value;
|
tasks[hook.value.name] = hook.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default tasks;
|
export default tasks;
|
||||||
|
|||||||
@@ -89,13 +89,15 @@ router.post(
|
|||||||
)) as AuthenticationProvider[];
|
)) as AuthenticationProvider[];
|
||||||
|
|
||||||
const data = AuthenticationHelper.providers
|
const data = AuthenticationHelper.providers
|
||||||
.filter((p) => p.id !== "email")
|
.filter((p) => p.value.id !== "email")
|
||||||
.map((p) => {
|
.map((p) => {
|
||||||
const row = teamAuthenticationProviders.find((t) => t.name === p.id);
|
const row = teamAuthenticationProviders.find(
|
||||||
|
(t) => t.name === p.value.id
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: p.id,
|
id: p.value.id,
|
||||||
name: p.id,
|
name: p.value.id,
|
||||||
displayName: p.name,
|
displayName: p.name,
|
||||||
isEnabled: false,
|
isEnabled: false,
|
||||||
isConnected: false,
|
isConnected: false,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import env from "@server/env";
|
|||||||
import { NotFoundError } from "@server/errors";
|
import { NotFoundError } from "@server/errors";
|
||||||
import coalesceBody from "@server/middlewares/coaleseBody";
|
import coalesceBody from "@server/middlewares/coaleseBody";
|
||||||
import { AppState, AppContext } from "@server/types";
|
import { AppState, AppContext } from "@server/types";
|
||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { Hook, PluginManager } from "@server/utils/PluginManager";
|
||||||
import apiKeys from "./apiKeys";
|
import apiKeys from "./apiKeys";
|
||||||
import attachments from "./attachments";
|
import attachments from "./attachments";
|
||||||
import auth from "./auth";
|
import auth from "./auth";
|
||||||
@@ -59,8 +59,8 @@ api.use(apiResponse());
|
|||||||
api.use(editor());
|
api.use(editor());
|
||||||
|
|
||||||
// Register plugin API routes before others to allow for overrides
|
// Register plugin API routes before others to allow for overrides
|
||||||
PluginManager.getEnabledPlugins(PluginType.API).forEach((plugin) =>
|
PluginManager.getHooks(Hook.API).forEach((hook) =>
|
||||||
router.use("/", plugin.value.routes())
|
router.use("/", hook.value.routes())
|
||||||
);
|
);
|
||||||
|
|
||||||
// routes
|
// routes
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import { authorize } from "@server/policies";
|
|||||||
import { presentDocument, presentMention } from "@server/presenters/unfurls";
|
import { presentDocument, presentMention } from "@server/presenters/unfurls";
|
||||||
import presentUnfurl from "@server/presenters/unfurls/unfurl";
|
import presentUnfurl from "@server/presenters/unfurls/unfurl";
|
||||||
import { APIContext } from "@server/types";
|
import { APIContext } from "@server/types";
|
||||||
import { PluginManager, PluginType } from "@server/utils/PluginManager";
|
import { Hook, PluginManager } from "@server/utils/PluginManager";
|
||||||
import { RateLimiterStrategy } from "@server/utils/RateLimiter";
|
import { RateLimiterStrategy } from "@server/utils/RateLimiter";
|
||||||
import * as T from "./schema";
|
import * as T from "./schema";
|
||||||
|
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
const plugins = PluginManager.getEnabledPlugins(PluginType.UnfurlProvider);
|
const plugins = PluginManager.getHooks(Hook.UnfurlProvider);
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"urls.unfurl",
|
"urls.unfurl",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ router.use(passport.initialize());
|
|||||||
|
|
||||||
// dynamically load available authentication provider routes
|
// dynamically load available authentication provider routes
|
||||||
AuthenticationHelper.providers.forEach((provider) => {
|
AuthenticationHelper.providers.forEach((provider) => {
|
||||||
router.use("/", provider.value.routes());
|
router.use("/", provider.value.router.routes());
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/redirect", auth(), async (ctx: APIContext) => {
|
router.get("/redirect", auth(), async (ctx: APIContext) => {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { glob } from "glob";
|
import { glob } from "glob";
|
||||||
import type Router from "koa-router";
|
import type Router from "koa-router";
|
||||||
|
import isArray from "lodash/isArray";
|
||||||
import sortBy from "lodash/sortBy";
|
import sortBy from "lodash/sortBy";
|
||||||
import { v4 as uuid } from "uuid";
|
|
||||||
import { UnfurlSignature } from "@shared/types";
|
import { UnfurlSignature } from "@shared/types";
|
||||||
import type BaseEmail from "@server/emails/templates/BaseEmail";
|
import type BaseEmail from "@server/emails/templates/BaseEmail";
|
||||||
import env from "@server/env";
|
import env from "@server/env";
|
||||||
@@ -21,7 +21,7 @@ export enum PluginPriority {
|
|||||||
/**
|
/**
|
||||||
* The different types of server plugins that can be registered.
|
* The different types of server plugins that can be registered.
|
||||||
*/
|
*/
|
||||||
export enum PluginType {
|
export enum Hook {
|
||||||
API = "api",
|
API = "api",
|
||||||
AuthProvider = "authProvider",
|
AuthProvider = "authProvider",
|
||||||
EmailTemplate = "emailTemplate",
|
EmailTemplate = "emailTemplate",
|
||||||
@@ -35,100 +35,56 @@ export enum PluginType {
|
|||||||
* Router. Registering an API plugin causes the router to be mounted.
|
* Router. Registering an API plugin causes the router to be mounted.
|
||||||
*/
|
*/
|
||||||
type PluginValueMap = {
|
type PluginValueMap = {
|
||||||
[PluginType.API]: Router;
|
[Hook.API]: Router;
|
||||||
[PluginType.AuthProvider]: Router;
|
[Hook.AuthProvider]: { router: Router; id: string };
|
||||||
[PluginType.EmailTemplate]: typeof BaseEmail;
|
[Hook.EmailTemplate]: typeof BaseEmail;
|
||||||
[PluginType.Processor]: typeof BaseProcessor;
|
[Hook.Processor]: typeof BaseProcessor;
|
||||||
[PluginType.Task]: typeof BaseTask<any>;
|
[Hook.Task]: typeof BaseTask<any>;
|
||||||
[PluginType.UnfurlProvider]: UnfurlSignature;
|
[Hook.UnfurlProvider]: UnfurlSignature;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Plugin<T extends PluginType> = {
|
export type Plugin<T extends Hook> = {
|
||||||
/** A unique ID for the plugin */
|
/** Plugin type */
|
||||||
id: string;
|
type: T;
|
||||||
/** The plugin's display name */
|
/** The plugin's display name */
|
||||||
name?: string;
|
name?: string;
|
||||||
/** A brief description of the plugin */
|
/** A brief description of the plugin */
|
||||||
description?: string;
|
description?: string;
|
||||||
/** The plugin content */
|
/** The plugin content */
|
||||||
value: PluginValueMap[T];
|
value: PluginValueMap[T];
|
||||||
/** An optional priority, will affect order in menus and execution. Lower is earlier. */
|
/** Priority will affect order in menus and execution. Lower is earlier. */
|
||||||
priority?: number;
|
priority?: number;
|
||||||
/** Whether the plugin is enabled (default: true) */
|
|
||||||
enabled?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export class PluginManager {
|
export class PluginManager {
|
||||||
private static plugins = new Map<PluginType, Plugin<PluginType>[]>();
|
private static plugins = new Map<Hook, Plugin<Hook>[]>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a plugin of a given type.
|
* Add plugins
|
||||||
*
|
* @param plugins
|
||||||
* @param type The plugin type
|
|
||||||
* @param value The plugin value
|
|
||||||
* @param options Additional options, including whether the plugin is enabled and it's priority.
|
|
||||||
* @returns The PluginManager instance, for chaining.
|
|
||||||
*/
|
*/
|
||||||
public static register<T extends PluginType>(
|
public static add(plugins: Array<Plugin<Hook>> | Plugin<Hook>) {
|
||||||
type: T,
|
if (isArray(plugins)) {
|
||||||
value: PluginValueMap[T],
|
return plugins.forEach((plugin) => this.register(plugin));
|
||||||
options: Omit<Plugin<T>, "value"> = {
|
|
||||||
id: uuid(),
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
if (!this.plugins.has(type)) {
|
|
||||||
this.plugins.set(type, []);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugin = {
|
this.register(plugins);
|
||||||
value,
|
}
|
||||||
priority: PluginPriority.Normal,
|
|
||||||
...options,
|
private static register<T extends Hook>(plugin: Plugin<T>) {
|
||||||
};
|
if (!this.plugins.has(plugin.type)) {
|
||||||
|
this.plugins.set(plugin.type, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.plugins
|
||||||
|
.get(plugin.type)!
|
||||||
|
.push({ ...plugin, priority: plugin.priority ?? PluginPriority.Normal });
|
||||||
|
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
"plugins",
|
"plugins",
|
||||||
`Plugin ${options.enabled === false ? "disabled" : "enabled"} "${
|
`Plugin(type=${plugin.type}) registered ${
|
||||||
options.id
|
"name" in plugin.value ? plugin.value.name : ""
|
||||||
}" ${options.description ? `(${options.description})` : ""}`
|
} ${plugin.description ? `(${plugin.description})` : ""}`
|
||||||
);
|
);
|
||||||
|
|
||||||
this.plugins.get(type)!.push(plugin);
|
|
||||||
|
|
||||||
// allow chaining
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Syntactic sugar for registering a background Task.
|
|
||||||
*
|
|
||||||
* @param value The task class
|
|
||||||
* @param options Additional options
|
|
||||||
*/
|
|
||||||
public static registerTask(
|
|
||||||
value: PluginValueMap[PluginType.Task],
|
|
||||||
options?: Omit<Plugin<PluginType.Task>, "id" | "value">
|
|
||||||
) {
|
|
||||||
return this.register(PluginType.Task, value, {
|
|
||||||
id: value.name,
|
|
||||||
...options,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Syntactic sugar for registering a background Processor.
|
|
||||||
*
|
|
||||||
* @param value The processor class
|
|
||||||
* @param options Additional options
|
|
||||||
*/
|
|
||||||
public static registerProcessor(
|
|
||||||
value: PluginValueMap[PluginType.Processor],
|
|
||||||
options?: Omit<Plugin<PluginType.Processor>, "id" | "value">
|
|
||||||
) {
|
|
||||||
return this.register(PluginType.Processor, value, {
|
|
||||||
id: value.name,
|
|
||||||
...options,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,21 +93,11 @@ export class PluginManager {
|
|||||||
* @param type The type of plugin to filter by
|
* @param type The type of plugin to filter by
|
||||||
* @returns A list of plugins
|
* @returns A list of plugins
|
||||||
*/
|
*/
|
||||||
public static getPlugins<T extends PluginType>(type: T) {
|
public static getHooks<T extends Hook>(type: T) {
|
||||||
this.loadPlugins();
|
this.loadPlugins();
|
||||||
return sortBy(this.plugins.get(type) || [], "priority") as Plugin<T>[];
|
return sortBy(this.plugins.get(type) || [], "priority") as Plugin<T>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all the enabled plugins of a given type in order of priority.
|
|
||||||
*
|
|
||||||
* @param type The type of plugin to filter by
|
|
||||||
* @returns A list of plugins
|
|
||||||
*/
|
|
||||||
public static getEnabledPlugins<T extends PluginType>(type: T) {
|
|
||||||
return this.getPlugins(type).filter((plugin) => plugin.enabled !== false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load plugin server components (anything in the `/server/` directory of a plugin will be loaded)
|
* Load plugin server components (anything in the `/server/` directory of a plugin will be loaded)
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user