refactor: 🔥 Remove plugin functionality, move OpenID plugin to core

This commit is contained in:
Jesse Wierzbinski 2025-07-07 05:52:11 +02:00
parent 278bf960cb
commit b5e9e35427
No known key found for this signature in database
45 changed files with 1502 additions and 2304 deletions

View file

@ -1,16 +0,0 @@
import { z } from "zod/v4";
import { Hooks } from "./hooks.ts";
import { Plugin } from "./plugin.ts";
const myPlugin = new Plugin(
z.object({
apiKey: z.string(),
}),
);
myPlugin.registerHandler(Hooks.Response, (req) => {
console.info("Request received:", req);
return req;
});
export default myPlugin;

View file

@ -1,9 +0,0 @@
export enum Hooks {
Request = "request",
Response = "response",
}
export type ServerHooks = {
[Hooks.Request]: (request: Request) => Request;
[Hooks.Response]: (response: Response) => Response;
};

View file

@ -1,4 +1 @@
export { ApiError } from "./api-error.ts";
export { Hooks } from "./hooks.ts";
export { Plugin } from "./plugin.ts";
export { type Manifest, manifestSchema } from "./schema.ts";

View file

@ -1,6 +0,0 @@
import * as z from "zod/v4";
import { manifestSchema } from "./schema.ts";
const jsonSchema = z.toJSONSchema(manifestSchema);
console.write(`${JSON.stringify(jsonSchema, null, 4)}\n`);

View file

@ -1,84 +0,0 @@
{
"type": "object",
"properties": {
"$schema": {
"type": "string"
},
"name": {
"type": "string",
"minLength": 3,
"maxLength": 100
},
"version": {
"type": "string",
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"
},
"description": {
"type": "string",
"minLength": 1,
"maxLength": 4096
},
"authors": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"email": {
"type": "string",
"format": "email"
},
"url": {
"type": "string",
"format": "uri"
}
},
"required": ["name"],
"additionalProperties": false
}
},
"repository": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"git",
"svn",
"mercurial",
"bzr",
"darcs",
"mtn",
"cvs",
"fossil",
"bazaar",
"arch",
"tla",
"archie",
"monotone",
"perforce",
"sourcevault",
"plastic",
"clearcase",
"accurev",
"surroundscm",
"bitkeeper",
"other"
]
},
"url": {
"type": "string",
"format": "uri"
}
},
"additionalProperties": false
}
},
"required": ["name", "version", "description"],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -1,90 +0,0 @@
import type { Hono, MiddlewareHandler } from "hono";
import { createMiddleware } from "hono/factory";
import type { z } from "zod/v4";
import { fromZodError, type ZodError } from "zod-validation-error";
import type { HonoEnv } from "~/types/api";
import type { ServerHooks } from "./hooks.ts";
export type HonoPluginEnv<ConfigType extends z.ZodTypeAny> = HonoEnv & {
Variables: {
pluginConfig: z.infer<ConfigType>;
};
};
export class Plugin<ConfigSchema extends z.ZodTypeAny> {
private readonly handlers: Partial<ServerHooks> = {};
// biome-ignore lint/nursery/useReadonlyClassProperties: biome is wrong lol
private store: z.infer<ConfigSchema> | null = null;
private readonly routes: {
path: string;
fn: (app: Hono<HonoPluginEnv<ConfigSchema>>) => void;
}[] = [];
public constructor(private readonly configSchema: ConfigSchema) {}
public get middleware(): MiddlewareHandler<HonoPluginEnv<ConfigSchema>> {
// Middleware that adds the plugin's configuration to the request object
return createMiddleware<HonoPluginEnv<ConfigSchema>>(
async (context, next) => {
context.set("pluginConfig", this.getConfig());
await next();
},
);
}
public registerRoute(
path: string,
fn: (app: Hono<HonoPluginEnv<ConfigSchema>>) => void,
): 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 async _loadConfig(config: z.input<ConfigSchema>): Promise<void> {
try {
this.store = await this.configSchema.parseAsync(config);
} catch (error) {
throw fromZodError(error as ZodError);
}
}
protected _addToApp(app: Hono<HonoEnv>): void {
for (const route of this.routes) {
app.use(route.path, this.middleware);
route.fn(app as unknown as Hono<HonoPluginEnv<ConfigSchema>>);
}
}
public registerHandler<HookName extends keyof ServerHooks>(
hook: HookName,
handler: ServerHooks[HookName],
): void {
this.handlers[hook] = handler;
}
public static [Symbol.hasInstance](instance: unknown): boolean {
return (
typeof instance === "object" &&
instance !== null &&
"registerHandler" in instance
);
}
/**
* Returns the internal configuration object.
*/
private getConfig(): z.infer<ConfigSchema> {
if (!this.store) {
throw new Error("Configuration has not been loaded yet.");
}
return this.store;
}
}

View file

@ -1,101 +0,0 @@
import { z } from "zod/v4";
export const manifestSchema = z.object({
// biome-ignore lint/style/useNamingConvention: JSON schema requires this to be $schema
$schema: z.string().optional(),
name: z.string().min(3).max(100),
version: z
.string()
.regex(
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/gm,
"Version must be valid SemVer string",
),
description: z.string().min(1).max(4096),
authors: z
.array(
z.object({
name: z.string().min(1).max(100),
email: z.email().optional(),
url: z.url().optional(),
}),
)
.optional(),
repository: z
.object({
type: z
.enum([
"git",
"svn",
"mercurial",
"bzr",
"darcs",
"mtn",
"cvs",
"fossil",
"bazaar",
"arch",
"tla",
"archie",
"monotone",
"perforce",
"sourcevault",
"plastic",
"clearcase",
"accurev",
"surroundscm",
"bitkeeper",
"other",
])
.optional(),
url: z.url().optional(),
})
.optional(),
});
export type Manifest = {
name: string;
version: string;
description: string;
authors?:
| {
name: string;
email?: string | undefined;
url?: string | undefined;
}[]
| undefined;
repository?:
| {
type?:
| "git"
| "svn"
| "mercurial"
| "bzr"
| "darcs"
| "mtn"
| "cvs"
| "fossil"
| "bazaar"
| "arch"
| "tla"
| "archie"
| "monotone"
| "perforce"
| "sourcevault"
| "plastic"
| "clearcase"
| "accurev"
| "surroundscm"
| "bitkeeper"
| "other"
| undefined;
url?: string | undefined;
}
| undefined;
};
// This is a type guard to ensure that the schema and the type are in sync
function assert<_T extends never>() {
// ...
}
type TypeEqualityGuard<A, B> = Exclude<A, B> | Exclude<B, A>;
assert<TypeEqualityGuard<Manifest, z.infer<typeof manifestSchema>>>();