mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 05:49:16 +01:00
refactor: 🔥 Remove plugin functionality, move OpenID plugin to core
This commit is contained in:
parent
278bf960cb
commit
b5e9e35427
45 changed files with 1502 additions and 2304 deletions
|
|
@ -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;
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
export enum Hooks {
|
||||
Request = "request",
|
||||
Response = "response",
|
||||
}
|
||||
|
||||
export type ServerHooks = {
|
||||
[Hooks.Request]: (request: Request) => Request;
|
||||
[Hooks.Response]: (response: Response) => Response;
|
||||
};
|
||||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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`);
|
||||
|
|
@ -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#"
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>>>();
|
||||
Loading…
Add table
Add a link
Reference in a new issue