refactor(plugin): ♻️ Move parts of OpenID logic to plugin

This commit is contained in:
Jesse Wierzbinski 2024-08-29 20:32:04 +02:00
parent 69d7d50239
commit d51bae52c6
No known key found for this signature in database
17 changed files with 494 additions and 395 deletions

View file

@ -122,7 +122,12 @@ export const configValidator = z.object({
}),
)
.default([]),
jwt_key: z.string().min(3).includes(";").default("").or(z.literal("")),
keys: z
.object({
public: z.string().min(1).optional(),
private: z.string().min(1).optional(),
})
.optional(),
}),
http: z.object({
base_url: z.string().min(1).default("http://versia.social"),

View file

@ -1,5 +1,6 @@
import { Plugin } from "./plugin";
import { Hooks } from "./hooks";
import { Plugin, PluginConfigManager } from "./plugin";
import type { Manifest } from "./schema";
export type { Manifest };
export { Plugin };
export { Plugin, PluginConfigManager, Hooks };

View file

@ -1,5 +1,5 @@
{
"name": "@versia-org/kit",
"name": "@versia/kit",
"module": "index.ts",
"type": "module",
"version": "0.0.0",

View file

@ -1,10 +1,23 @@
import { createMiddleware } from "@hono/hono/factory";
import type { OpenAPIHono } from "@hono/zod-openapi";
import type { z } from "zod";
import { type ZodError, fromZodError } from "zod-validation-error";
import type { HonoEnv } from "~/types/api";
import type { ServerHooks } from "./hooks";
import { type Manifest, manifestSchema } from "./schema";
export type HonoPluginEnv<ConfigType extends z.ZodTypeAny> = HonoEnv & {
Variables: {
pluginConfig: z.infer<ConfigType>;
};
};
export class Plugin<ConfigSchema extends z.ZodTypeAny> {
private handlers: Partial<ServerHooks> = {};
private routes: {
path: string;
fn: (app: OpenAPIHono<HonoPluginEnv<ConfigSchema>>) => void;
}[] = [];
constructor(
private manifest: Manifest,
@ -13,20 +26,49 @@ export class Plugin<ConfigSchema extends z.ZodTypeAny> {
this.validateManifest(manifest);
}
get middleware() {
// Middleware that adds the plugin's configuration to the request object
return createMiddleware<HonoPluginEnv<ConfigSchema>>(
async (context, next) => {
context.set("pluginConfig", this.configManager.getConfig());
await next();
},
);
}
public getManifest() {
return this.manifest;
}
public registerRoute(
path: string,
fn: (app: OpenAPIHono<HonoPluginEnv<ConfigSchema>>) => void,
) {
this.routes.push({
path,
fn,
});
}
/**
* Loads the plugin's configuration from the Versia Server configuration file.
* This will be called when the plugin is loaded.
* @param config Values the user has set in the configuration file.
*/
protected _loadConfig(config: z.infer<ConfigSchema>) {
protected _loadConfig(config: z.input<ConfigSchema>) {
// biome-ignore lint/complexity/useLiteralKeys: Private method
this.configManager["_load"](config);
}
protected _addToApp(app: OpenAPIHono<HonoEnv>) {
for (const route of this.routes) {
app.use(route.path, this.middleware);
route.fn(
app as unknown as OpenAPIHono<HonoPluginEnv<ConfigSchema>>,
);
}
}
public registerHandler<HookName extends keyof ServerHooks>(
hook: HookName,
handler: ServerHooks[HookName],
@ -56,6 +98,7 @@ export class Plugin<ConfigSchema extends z.ZodTypeAny> {
* Handles loading, defining, and managing the plugin's configuration.
* Plugins can define their own configuration schema, which is then used to
* load it from the user's configuration file.
* @param schema The Zod schema that defines the configuration.
*/
export class PluginConfigManager<Schema extends z.ZodTypeAny> {
private store: z.infer<Schema> | null;
@ -69,10 +112,10 @@ export class PluginConfigManager<Schema extends z.ZodTypeAny> {
* This will be called when the plugin is loaded.
* @param config Values the user has set in the configuration file.
*/
protected _load(config: z.infer<Schema>) {
protected async _load(config: z.infer<Schema>) {
// Check if the configuration is valid
try {
this.schema.parse(config);
this.store = await this.schema.parseAsync(config);
} catch (error) {
throw fromZodError(error as ZodError);
}
@ -82,6 +125,10 @@ export class PluginConfigManager<Schema extends z.ZodTypeAny> {
* Returns the internal configuration object.
*/
public getConfig() {
if (!this.store) {
throw new Error("Configuration has not been loaded yet.");
}
return this.store;
}
}