import z from "zod"; function route(opts: { route: `/${string}`; output: z.ZodType; method: "GET"; input: z.ZodType; }): (data: I) => Promise; function route(opts: { route: `/${string}`; output: z.ZodType; method: "POST"; input: z.ZodType; }): (data: I) => Promise; function route(opts: { route: `/${string}`; output: z.ZodType; method: "GET"; }): () => Promise; function route(opts: { route: `/${string}`; output: z.ZodType; method: "POST"; }): () => Promise; function route({ route, output, method, input, }: { route: `/${string}`; output: z.ZodType; method: "GET" | "POST"; input?: z.ZodType; }): ((data: I) => Promise) | (() => Promise) { const stringify = method == "GET" ? (obj: I) => new URLSearchParams( Object.fromEntries( Object.entries(obj as Object).map(([k, v]) => [k, "" + v]), ), ).toString() : (obj: I) => JSON.stringify(obj); const then = (req: Response) => req.json().then(output.parseAsync); return input ? method == "GET" ? (data: I) => fetch(route + "?" + stringify(data), { method }).then(then) : (data: I) => fetch(route, { method, body: stringify(data), headers: { "Content-Type": "application/json" }, }).then(then) : () => fetch(route, { method }).then(then); } const u8 = z.int().min(0).max(255); const colour = z.tuple([u8, u8, u8]); const Api = { config: route({ route: "/config", method: "GET", output: z.object({ binding: z.string(), theme: z.object({ background: colour, background_main: colour, background_server: colour, background_button: colour, text: colour, text_secondary: colour, accent_success: colour, accent_fail: colour, link: colour, link_visited: colour, highlight: colour, highlight_opacity: u8, fonts: z.array(z.string()), }), info: z.object({ title: z.string(), links: z.array(z.tuple([z.string(), z.string()])), icon: z.string(), }), pinned: z.array(z.string()), targets: z.record( z.string(), z.object({ mac: z.string(), ip: z.string().nullable(), // should be a url but we allow any string in rust url: z.string().nullable(), }), ), }), }), wake: route({ route: "/wake", method: "POST", input: z.object({ mac: z.string(), }), output: z.boolean(), }), ping: route({ route: "/ping", method: "GET", input: z.object({ ip: z.string(), }), output: z.boolean(), }), } as const; export const config = await Api.config(); export default Api;