A vibe coded tangled fork which supports pijul.
1import { cardPayloadSchema } from "./validation";
2import { renderCard } from "./lib/render";
3import { RepositoryCard } from "./components/cards/repository";
4import { IssueCard } from "./components/cards/issue";
5import { PullRequestCard } from "./components/cards/pull-request";
6import { z } from "zod";
7
8declare global {
9 interface CacheStorage {
10 default: Cache;
11 }
12}
13
14interface Env {
15 ENVIRONMENT: string;
16}
17
18export default {
19 async fetch(request: Request, env: Env): Promise<Response> {
20 if (request.method !== "POST") {
21 return new Response("Method not allowed", { status: 405 });
22 }
23
24 const url = new URL(request.url);
25 const cardType = url.pathname.split("/").pop();
26
27 try {
28 const body = await request.json();
29 const payload = cardPayloadSchema.parse(body);
30
31 let component;
32 switch (payload.type) {
33 case "repository":
34 component = <RepositoryCard {...payload} />;
35 break;
36 case "issue":
37 component = <IssueCard {...payload} />;
38 break;
39 case "pullRequest":
40 component = <PullRequestCard {...payload} />;
41 break;
42 default:
43 return new Response("Unknown card type", { status: 400 });
44 }
45
46 const cacheKeyUrl = new URL(request.url);
47 cacheKeyUrl.searchParams.set("payload", JSON.stringify(payload));
48 const cacheKey = new Request(cacheKeyUrl.toString(), { method: "GET" });
49 const cache = caches.default;
50 const cached = await cache.match(cacheKey);
51
52 if (cached) {
53 return cached;
54 }
55
56 const { png: pngBuffer } = await renderCard(component);
57
58 const response = new Response(pngBuffer as any, {
59 headers: {
60 "Content-Type": "image/png",
61 "Cache-Control": "public, max-age=3600",
62 },
63 });
64
65 await cache.put(cacheKey, response.clone());
66
67 return response;
68 } catch (error) {
69 if (error instanceof z.ZodError) {
70 return new Response(
71 JSON.stringify({ errors: (error as z.ZodError).issues }),
72 {
73 status: 400,
74 headers: { "Content-Type": "application/json" },
75 },
76 );
77 }
78
79 console.error("Error generating card:", error);
80 const errorMessage =
81 error instanceof Error ? error.message : String(error);
82 const errorStack = error instanceof Error ? error.stack : "";
83 console.error("Error stack:", errorStack);
84 return new Response(
85 JSON.stringify({
86 error: errorMessage,
87 stack: errorStack,
88 }),
89 {
90 status: 500,
91 headers: { "Content-Type": "application/json" },
92 },
93 );
94 }
95 },
96};