mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
106 lines
3.1 KiB
TypeScript
106 lines
3.1 KiB
TypeScript
import * as v from "valibot";
|
|
import type { Group, Route } from "../types";
|
|
import { log } from "../lib/log";
|
|
import { explainFilterNode } from "../events/filter-ast";
|
|
|
|
export const CONFIG_SCHEMA_VERSION = 1;
|
|
|
|
export const filterSchema = v.object({
|
|
type: v.picklist(["event", "repo", "actor", "action", "branch", "keyword"]),
|
|
match: v.union([v.string(), v.array(v.string())]),
|
|
exclude: v.optional(v.boolean()),
|
|
});
|
|
|
|
export const routeTargetSchema = v.object({
|
|
platform: v.optional(v.picklist(["discord", "telegram"])),
|
|
channelId: v.optional(v.string()),
|
|
threadId: v.optional(v.string()),
|
|
chatId: v.optional(v.string()),
|
|
topicId: v.optional(v.string()),
|
|
});
|
|
|
|
export const filterNodeSchema = v.lazy(() =>
|
|
v.union([
|
|
filterSchema,
|
|
v.object({ all: v.array(filterNodeSchema) }),
|
|
v.object({ any: v.array(filterNodeSchema) }),
|
|
v.object({ not: filterNodeSchema }),
|
|
]),
|
|
);
|
|
|
|
export const routeSchema = v.object({
|
|
id: v.string(),
|
|
name: v.string(),
|
|
enabled: v.boolean(),
|
|
filters: v.array(filterSchema),
|
|
targets: v.array(routeTargetSchema),
|
|
groupId: v.optional(v.string()),
|
|
fallback: v.optional(v.boolean()),
|
|
stop: v.optional(v.boolean()),
|
|
discordRoleIds: v.optional(v.array(v.string())),
|
|
ast: v.optional(filterNodeSchema),
|
|
});
|
|
|
|
export const groupMemberSchema = v.object({
|
|
login: v.string(),
|
|
role: v.picklist(["owner", "admin", "viewer"]),
|
|
});
|
|
|
|
export const forgeSourceSchema = v.object({
|
|
host: v.string(),
|
|
type: v.picklist(["github", "gitea"]),
|
|
name: v.optional(v.string()),
|
|
});
|
|
|
|
export const groupSchema = v.object({
|
|
id: v.string(),
|
|
name: v.string(),
|
|
adminIds: v.array(v.string()),
|
|
members: v.optional(v.array(groupMemberSchema)),
|
|
owners: v.optional(v.array(v.string())),
|
|
providers: v.optional(v.array(v.picklist(["github", "gitea", "gitlab", "custom"]))),
|
|
installationId: v.optional(v.number()),
|
|
emoji: v.optional(v.boolean()),
|
|
forgeSources: v.optional(v.array(forgeSourceSchema)),
|
|
lang: v.optional(v.string()),
|
|
logTarget: v.optional(routeTargetSchema),
|
|
});
|
|
|
|
export function migrateRoutes(routes: Route[]): Route[] {
|
|
return routes.map((r) => {
|
|
if (r.targets && r.targets.length > 0) return r;
|
|
const legacy = (r as Route & { target?: Route["targets"][number] }).target;
|
|
if (!legacy) return r;
|
|
const { target: _target, ...rest } = r as Route & { target?: Route["targets"][number] };
|
|
return { ...rest, targets: [legacy] };
|
|
});
|
|
}
|
|
|
|
export function migrateGroups(groups: Group[]): Group[] {
|
|
return groups;
|
|
}
|
|
|
|
export function validateRoutes(routes: Route[]): Route[] {
|
|
for (const r of routes) {
|
|
const result = v.safeParse(routeSchema, r);
|
|
if (!result.success) {
|
|
log.warn({ id: r?.id, issues: result.issues }, "Invalid route config");
|
|
}
|
|
}
|
|
return routes;
|
|
}
|
|
|
|
export function validateGroups(groups: Group[]): Group[] {
|
|
for (const g of groups) {
|
|
const result = v.safeParse(groupSchema, g);
|
|
if (!result.success) {
|
|
log.warn({ id: g?.id, issues: result.issues }, "Invalid group config");
|
|
}
|
|
}
|
|
return groups;
|
|
}
|
|
|
|
export function explainRoute(route: Route): string {
|
|
const node = route.ast ?? { all: route.filters };
|
|
return `${route.name}: ${explainFilterNode(node)}`;
|
|
}
|