feat(plugin): Add override settings to plugin loading

This commit is contained in:
Jesse Wierzbinski 2024-10-06 15:55:15 +02:00
parent c0805ff125
commit f26ab0f0e6
No known key found for this signature in database
7 changed files with 705 additions and 548 deletions

View file

@ -287,6 +287,6 @@ max_coeff = 1.0
[plugins] [plugins]
[plugins."@versia/openid".keys] [plugins.config."@versia/openid".keys]
private = "MC4CAQAwBQYDK2VwBCIEID+H5n9PY3zVKZQcq4jrnE1IiRd2EWWr8ApuHUXmuOzl" private = "MC4CAQAwBQYDK2VwBCIEID+H5n9PY3zVKZQcq4jrnE1IiRd2EWWr8ApuHUXmuOzl"
public = "MCowBQYDK2VwAyEAzenliNkgpXYsh3gXTnAoUWzlCPjIOppmAVx2DBlLsC8=" public = "MCowBQYDK2VwAyEAzenliNkgpXYsh3gXTnAoUWzlCPjIOppmAVx2DBlLsC8="

11
app.ts
View file

@ -119,19 +119,24 @@ export const appFactory = async () => {
const loader = new PluginLoader(); const loader = new PluginLoader();
const plugins = await loader.loadPlugins(join(process.cwd(), "plugins")); const plugins = await loader.loadPlugins(
join(process.cwd(), "plugins"),
config.plugins?.autoload,
config.plugins?.overrides.enabled,
config.plugins?.overrides.disabled,
);
for (const data of plugins) { for (const data of plugins) {
serverLogger.info`Loading plugin ${chalk.blueBright(data.manifest.name)} ${chalk.blueBright(data.manifest.version)} ${chalk.gray(`[${plugins.indexOf(data) + 1}/${plugins.length}]`)}`; serverLogger.info`Loading plugin ${chalk.blueBright(data.manifest.name)} ${chalk.blueBright(data.manifest.version)} ${chalk.gray(`[${plugins.indexOf(data) + 1}/${plugins.length}]`)}`;
try { try {
// biome-ignore lint/complexity/useLiteralKeys: loadConfig is a private method // biome-ignore lint/complexity/useLiteralKeys: loadConfig is a private method
await data.plugin["_loadConfig"]( await data.plugin["_loadConfig"](
config.plugins?.[data.manifest.name], config.plugins?.config?.[data.manifest.name],
); );
} catch (e) { } catch (e) {
serverLogger.fatal`Plugin configuration is invalid: ${chalk.redBright(e as ValidationError)}`; serverLogger.fatal`Plugin configuration is invalid: ${chalk.redBright(e as ValidationError)}`;
serverLogger.fatal`Put your configuration at ${chalk.blueBright( serverLogger.fatal`Put your configuration at ${chalk.blueBright(
"plugins.<plugin-name>", "plugins.config.<plugin-name>",
)}`; )}`;
throw new Error("Plugin configuration is invalid"); throw new Error("Plugin configuration is invalid");
} }

View file

@ -201,7 +201,7 @@ describe("PluginLoader", () => {
default: mockPlugin, default: mockPlugin,
})); }));
const plugins = await pluginLoader.loadPlugins("/some/path"); const plugins = await pluginLoader.loadPlugins("/some/path", true);
expect(plugins).toEqual([ expect(plugins).toEqual([
{ {
manifest: manifestContent, manifest: manifestContent,

View file

@ -162,12 +162,42 @@ export class PluginLoader {
*/ */
public async loadPlugins( public async loadPlugins(
dir: string, dir: string,
autoload: boolean,
enabled?: string[],
disabled?: string[],
): Promise<{ manifest: Manifest; plugin: Plugin<ZodTypeAny> }[]> { ): Promise<{ manifest: Manifest; plugin: Plugin<ZodTypeAny> }[]> {
const plugins = await PluginLoader.findPlugins(dir); const plugins = await PluginLoader.findPlugins(dir);
const enabledOn = (enabled?.length ?? 0) > 0;
const disabledOn = (disabled?.length ?? 0) > 0;
if (enabledOn && disabledOn) {
this.logger
.fatal`Both enabled and disabled lists are specified. Only one of them can be used.`;
throw new Error("Invalid configuration");
}
return Promise.all( return Promise.all(
plugins.map(async (plugin) => { plugins.map(async (plugin) => {
const manifest = await this.parseManifest(dir, plugin); const manifest = await this.parseManifest(dir, plugin);
// If autoload is disabled, only load plugins explicitly enabled
if (
!(autoload || enabledOn || enabled?.includes(manifest.name))
) {
return null;
}
// If enabled is specified, only load plugins in the enabled list
// If disabled is specified, only load plugins not in the disabled list
if (enabledOn && !enabled?.includes(manifest.name)) {
return null;
}
if (disabled?.includes(manifest.name)) {
return null;
}
const pluginInstance = await this.loadPlugin( const pluginInstance = await this.loadPlugin(
dir, dir,
`${plugin}/index`, `${plugin}/index`,
@ -175,6 +205,6 @@ export class PluginLoader {
return { manifest, plugin: pluginInstance }; return { manifest, plugin: pluginInstance };
}), }),
); ).then((data) => data.filter((d) => d !== null));
} }
} }

View file

@ -4007,7 +4007,41 @@
}, },
"plugins": { "plugins": {
"type": "object", "type": "object",
"additionalProperties": {} "properties": {
"autoload": {
"type": "boolean",
"default": true
},
"overrides": {
"type": "object",
"properties": {
"enabled": {
"type": "array",
"items": {
"type": "string"
},
"default": []
},
"disabled": {
"type": "array",
"items": {
"type": "string"
},
"default": []
}
},
"additionalProperties": false,
"default": {
"enabled": [],
"disabled": []
}
},
"config": {
"type": "object",
"additionalProperties": {}
}
},
"additionalProperties": false
} }
}, },
"required": [ "required": [
@ -4019,7 +4053,8 @@
"http", "http",
"smtp", "smtp",
"filters", "filters",
"ratelimits" "ratelimits",
"plugins"
], ],
"additionalProperties": false, "additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#" "$schema": "http://json-schema.org/draft-07/schema#"

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,10 @@ const scope = "openid profile email";
const secret = "test-secret"; const secret = "test-secret";
const privateKey = await crypto.subtle.importKey( const privateKey = await crypto.subtle.importKey(
"pkcs8", "pkcs8",
Buffer.from(config.plugins?.["@versia/openid"].keys.private, "base64"), Buffer.from(
config.plugins?.config?.["@versia/openid"].keys.private,
"base64",
),
"Ed25519", "Ed25519",
false, false,
["sign"], ["sign"],