3This is a lightweight Blob Admin interface to view and debug your Blob data.
4
5
6
7To use this, fork it to your account.
61 const { ValTown } = await import("npm:@valtown/sdk");
62 const vt = new ValTown();
63 const { email: authorEmail, profileImageUrl, username } = await vt.me.profile.retrieve();
64 // const authorEmail = me.email;
65
129
130 c.set("email", email);
131 c.set("profile", { profileImageUrl, username });
132 await next();
133};
437 {profile && (
438 <div className="flex items-center space-x-4">
439 <img src={profile.profileImageUrl} alt="Profile" className="w-8 h-8 rounded-full" />
440 <span>{profile.username}</span>
441 <a href="/auth/logout" className="text-blue-400 hover:text-blue-300">Logout</a>
580 alt="Blob content"
581 className="max-w-full h-auto"
582 onError={() => console.error("Error loading image")}
583 />
584 </div>
630 <li>Create public shareable links for blobs</li>
631 <li>View and manage public folder</li>
632 <li>Preview images directly in the interface</li>
633 </ul>
634 </div>
3 <source media="(prefers-color-scheme: dark)" srcset="https://mintlify.s3.us-west-1.amazonaws.com/autoblocks/logo/dark.png">
4 <source media="(prefers-color-scheme: light)" srcset="https://mintlify.s3.us-west-1.amazonaws.com/autoblocks/logo/light.png">
5 <img alt="Autoblocks Logo" width="300px" src="https://app.autoblocks.ai/images/logo-black.png">
6 </picture>
7</p>
3 <source media="(prefers-color-scheme: dark)" srcset="https://mintlify.s3.us-west-1.amazonaws.com/autoblocks/logo/dark.png">
4 <source media="(prefers-color-scheme: light)" srcset="https://mintlify.s3.us-west-1.amazonaws.com/autoblocks/logo/light.png">
5 <img alt="Autoblocks Logo" width="300px" src="https://app.autoblocks.ai/images/logo-black.png">
6 </picture>
7</p>
4import faviconRoute from "./routes/favicon.ts";
5import homeRoutes from "./routes/home.ts";
6import ogImageRoute from "./routes/og-image.ts";
7import proxyRoutes from "./routes/proxy.ts";
8import rssRoute from "./routes/rss.ts";
28app.route("/rss.xml", rssRoute);
29app.route("/favicon.svg", faviconRoute);
30app.route("/og-image.png", ogImageRoute);
31app.route("/", blogRoutes);
32
5Here's one of the examples, which uses val.town to update database pages with favicons from the web:
6
7
8
9Read up on it and try the examples:
18Every minute, this project has a cron that resets all the state, so that the next visitor to the Notion page has a clean experience. That cron uses the subdomain as the prefix for all the blob storage.
19
20
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/`
73});
74
75// --- Blob Image Serving Routes ---
76
77// GET /api/images/:filename - Serve images from blob storage
78app.get("/api/images/:filename", async (c) => {
79 const filename = c.req.param("filename");
80
81 try {
82 // Get image data from blob storage
83 const imageData = await blob.get(filename);
84
85 if (!imageData) {
86 return c.json({ error: "Image not found" }, 404);
87 }
88
90 let contentType = "application/octet-stream"; // Default
91 if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) {
92 contentType = "image/jpeg";
93 } else if (filename.endsWith(".png")) {
94 contentType = "image/png";
95 } else if (filename.endsWith(".gif")) {
96 contentType = "image/gif";
97 } else if (filename.endsWith(".svg")) {
98 contentType = "image/svg+xml";
99 }
100
101 // Return the image with appropriate headers
102 return new Response(imageData, {
103 headers: {
104 "Content-Type": contentType,
107 });
108 } catch (error) {
109 console.error(`Error serving image ${filename}:`, error);
110 return c.json(
111 { error: "Failed to load image", details: error.message },
112 500,
113 );