2025-03-29 03:30:06 +01:00
|
|
|
import type { Hono, MiddlewareHandler } from "hono";
|
2024-12-18 20:42:40 +01:00
|
|
|
import { createMiddleware } from "hono/factory";
|
2024-06-22 06:22:53 +02:00
|
|
|
import type { z } from "zod";
|
2025-04-10 19:15:31 +02:00
|
|
|
import { fromZodError, type ZodError } from "zod-validation-error";
|
2024-08-29 20:32:04 +02:00
|
|
|
import type { HonoEnv } from "~/types/api";
|
2024-10-04 15:22:48 +02:00
|
|
|
import type { ServerHooks } from "./hooks.ts";
|
2024-06-22 06:22:53 +02:00
|
|
|
|
2024-08-29 20:32:04 +02:00
|
|
|
export type HonoPluginEnv<ConfigType extends z.ZodTypeAny> = HonoEnv & {
|
|
|
|
|
Variables: {
|
|
|
|
|
pluginConfig: z.infer<ConfigType>;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-22 06:22:53 +02:00
|
|
|
export class Plugin<ConfigSchema extends z.ZodTypeAny> {
|
|
|
|
|
private handlers: Partial<ServerHooks> = {};
|
2024-09-25 12:31:35 +02:00
|
|
|
private store: z.infer<ConfigSchema> | null = null;
|
2024-08-29 20:32:04 +02:00
|
|
|
private routes: {
|
|
|
|
|
path: string;
|
2025-03-29 03:30:06 +01:00
|
|
|
fn: (app: Hono<HonoPluginEnv<ConfigSchema>>) => void;
|
2024-08-29 20:32:04 +02:00
|
|
|
}[] = [];
|
2024-06-22 06:22:53 +02:00
|
|
|
|
2024-11-01 21:20:12 +01:00
|
|
|
public constructor(private configSchema: ConfigSchema) {}
|
2024-06-22 06:22:53 +02:00
|
|
|
|
2024-12-30 18:20:22 +01:00
|
|
|
public get middleware(): MiddlewareHandler<HonoPluginEnv<ConfigSchema>> {
|
2024-08-29 20:32:04 +02:00
|
|
|
// Middleware that adds the plugin's configuration to the request object
|
|
|
|
|
return createMiddleware<HonoPluginEnv<ConfigSchema>>(
|
|
|
|
|
async (context, next) => {
|
2024-09-25 12:31:35 +02:00
|
|
|
context.set("pluginConfig", this.getConfig());
|
2024-08-29 20:32:04 +02:00
|
|
|
await next();
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public registerRoute(
|
|
|
|
|
path: string,
|
2025-03-29 03:30:06 +01:00
|
|
|
fn: (app: Hono<HonoPluginEnv<ConfigSchema>>) => void,
|
2024-11-02 00:43:33 +01:00
|
|
|
): void {
|
2024-08-29 20:32:04 +02:00
|
|
|
this.routes.push({
|
|
|
|
|
path,
|
|
|
|
|
fn,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-22 06:22:53 +02:00
|
|
|
/**
|
2024-08-19 15:16:01 +02:00
|
|
|
* Loads the plugin's configuration from the Versia Server configuration file.
|
2024-06-22 06:22:53 +02:00
|
|
|
* This will be called when the plugin is loaded.
|
|
|
|
|
* @param config Values the user has set in the configuration file.
|
|
|
|
|
*/
|
2024-09-25 12:31:35 +02:00
|
|
|
protected async _loadConfig(config: z.input<ConfigSchema>): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
this.store = await this.configSchema.parseAsync(config);
|
|
|
|
|
} catch (error) {
|
2025-02-15 02:47:29 +01:00
|
|
|
throw fromZodError(error as ZodError);
|
2024-09-25 12:31:35 +02:00
|
|
|
}
|
2024-06-22 06:22:53 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-29 03:30:06 +01:00
|
|
|
protected _addToApp(app: Hono<HonoEnv>): void {
|
2024-08-29 20:32:04 +02:00
|
|
|
for (const route of this.routes) {
|
|
|
|
|
app.use(route.path, this.middleware);
|
2025-03-29 03:30:06 +01:00
|
|
|
route.fn(app as unknown as Hono<HonoPluginEnv<ConfigSchema>>);
|
2024-08-29 20:32:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-22 06:22:53 +02:00
|
|
|
public registerHandler<HookName extends keyof ServerHooks>(
|
|
|
|
|
hook: HookName,
|
|
|
|
|
handler: ServerHooks[HookName],
|
2024-11-02 00:43:33 +01:00
|
|
|
): void {
|
2024-06-22 06:22:53 +02:00
|
|
|
this.handlers[hook] = handler;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-01 21:20:12 +01:00
|
|
|
public static [Symbol.hasInstance](instance: unknown): boolean {
|
2024-06-22 06:22:53 +02:00
|
|
|
return (
|
|
|
|
|
typeof instance === "object" &&
|
|
|
|
|
instance !== null &&
|
|
|
|
|
"registerHandler" in instance
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the internal configuration object.
|
|
|
|
|
*/
|
2024-11-02 00:43:33 +01:00
|
|
|
private getConfig(): z.infer<ConfigSchema> {
|
2024-08-29 20:32:04 +02:00
|
|
|
if (!this.store) {
|
|
|
|
|
throw new Error("Configuration has not been loaded yet.");
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-22 06:22:53 +02:00
|
|
|
return this.store;
|
|
|
|
|
}
|
|
|
|
|
}
|