4import { Header } from "./components.tsx";
5import hemolog from "./frames/hemolog.tsx";
6import generateImageFromHtml from "./generateImageFromHtml.ts";
7
8export default async function(req: Request) {
9 const url = new URL(req.url);
10 const isImageRequest = url.searchParams.get("generate") === "image";
11 const isListRequest = url.searchParams.get("generate") === "list";
12 const frameId = url.searchParams.get("frame");
68 }
69
70 // get ?&generate=image&frame=S0mth1ingKrAzy
71 if (frameId && !frame_list.includes(frameId)) {
72 const html = renderToString(
84 const generateUrl = frames[frameId as keyof typeof frames];
85
86 // get ?&generate=image&frame=weather
87 if (isImageRequest) {
88 const width = 800;
89 const height = 480;
90
91 const imageResponse = await generateImageFromHtml(generateUrl, width, height);
92 return new Response(imageResponse.body, {
93 status: imageResponse.status,
94 headers: {
95 "Content-Type": "image/png",
96 },
97 });
2// API key required
3
4// TODO: Add caching of image
5export default async function generateImageFromHtml(
6 valUrl: string,
7 width: number = 800,
13 const apiKey = Deno.env.get("API_FLASH_KEY");
14 const generateUrl =
15 `https://api.apiflash.com/v1/urltoimage?access_key=${apiKey}&url=${valUrl}&width=${width}&height=${height}&format=png&fresh=true`;
16
17 try {
22 return response;
23 } catch (error) {
24 return new Response("Failed to generate image", { status: 500 });
25 }
26}
8 service_version: string;
9 title: string;
10 url: string; // image to display
11};
12
2import deleteCreation from "./deleteCreation";
3import getCreation from "./getCreation";
4import getCreationImage from "./getCreationImage";
5import getCreations from "./getCreations";
6import updateTable from "./updateTable";
14 case "/get-creation":
15 return getCreation(req);
16 case "/get-creation-image":
17 return getCreationImage(req);
18 case "/get-creations":
19 return getCreations(req);
12 // Iterate through each one and delete it's blob
13 for (const row of res.rows) {
14 blob.delete("pondiverse_image" + row.id);
15 }
16
53 // for (let creation of response.rows) {
54 // creation.url = `https://pondiverse.val.run/get-creation?id=${creation.id}`;
55 // creation.image = `https://pondiverse.val.run/get-creation-image?id=${creation.id}`;
56 // }
57
9 let response;
10 try {
11 response = await blob.get("pondiverse_image" + id);
12 } catch (e) {
13 return new Response(null, { status: 404 });
14 // This makes forking harder sorry
15 // creation.uri = `https://pondiverse.val.run/get-creation?id=${creation.id}`;
16 // creation.image = `https://pondiverse.val.run/get-creation-image?id=${creation.id}`;
17 return Response.json(creation);
18}
40
41 // Also delete the blob!
42 blob.delete("pondiverse_image" + id);
43
44 return Response.json({ ok: true });
3It's common to have code and types that are needed on both the frontend and the backend. It's important that you write this code in a particularly defensive way because it's limited by what both environments support:
4
5
6
7For example, you *cannot* use the `Deno` keyword. For imports, you can't use `npm:` specifiers, so we reccomend `https://esm.sh` because it works on the server & client. You *can* use TypeScript because that is transpiled in `/backend/index.ts` for the frontend. Most code that works on the frontend tends to work in Deno, because Deno is designed to support "web-standards", but there are definitely edge cases to look out for.
21## `favicon.svg`
22
23As of this writing Val Town only supports text files, which is why the favicon is an SVG and not an .ico or any other binary image format. If you need binary file storage, check out [Blob Storage](https://docs.val.town/std/blob/).
24
25## `components/`