4 const uuid = params.get("uuid");
5 console.log(uuid);
6 // call API
7 const api_response = await fetch(`https://api.hypixel.net/v2/player?uuid=${uuid}`, {
8 headers: {
9 "API-Key": `${key}`,
10 },
11 });
12
13 const response = await api_response.json();
14 // return new Response(JSON.stringify(response.player.packageRank), { status: 200 });
15 // timeout test
244
245 try {
246 const response = await fetch(`/api/project?url=${encodeURIComponent(projectUrl)}`);
247 const data = await response.json();
248
8app.get("/public/*", c => serveFile(c.req.path.replace("/public", "/frontend"), import.meta.url));
9
10// API endpoint to get project tree data
11app.get("/api/project", async c => {
12 const url = c.req.query("url");
13
23## Project Structure
24
25- `/backend` - Server-side code for the API
26- `/frontend` - Client-side UI components and styles
27- `/shared` - Shared utilities used by both frontend and backend
35To modify this project:
36
371. Edit the backend API in `/backend/index.ts`
382. Modify the tree generation logic in `/shared/projectTree.ts`
393. Update the UI components in the `/frontend` directory
6
7### Prerequisites
8- [Val Town API key](https://www.val.town/settings/api) with project read/write permissions
6
7### Prerequisites
8- [Val Town API key](https://www.val.town/settings/api) with project read/write permissions
223app.get("/frontend/**/*", c => serveFile(c.req.path, import.meta.url));
224
225// Add your API routes here
226// app.get("/api/data", c => c.json({ hello: "world" }));
227
228// Unwrap and rethrow Hono errors as the original error
4export function App() {
5 const [projectUrl, setProjectUrl] = useState("");
6 const [apiToken, setApiToken] = useState("");
7 const [loading, setLoading] = useState(false);
8 const [message, setMessage] = useState("");
21 }
22
23 if (!apiToken.trim()) {
24 throw new Error("API Token is required");
25 }
26
28 method: "POST",
29 headers: {
30 "Authorization": `Bearer ${apiToken}`,
31 "Content-Type": "application/json",
32 },
63 value={projectUrl}
64 onChange={(e) => setProjectUrl(e.target.value)}
65 placeholder="https://api.val.town/v1/projects/..."
66 className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-purple-500"
67 />
69
70 <div>
71 <label htmlFor="apiToken" className="block text-sm font-medium text-gray-700 mb-1">
72 Val Town API Token (project read + write permissions)
73 </label>
74 <input
75 id="apiToken"
76 type="password"
77 value={apiToken}
78 onChange={(e) => setApiToken(e.target.value)}
79 placeholder="Enter your API token"
80 className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-purple-500"
81 />
8## Hono
9
10This app uses [Hono](https://hono.dev/) as the API framework. You can think of Hono as a replacement for [ExpressJS](https://expressjs.com/) that works in serverless environments like Val Town or Cloudflare Workers. If you come from Python or Ruby, Hono is also a lot like [Flask](https://github.com/pallets/flask) or [Sinatra](https://github.com/sinatra/sinatra), respectively.
11
12## Serving assets to the frontend
20### `index.html`
21
22The most complicated part of this backend API is serving index.html. In this app (like most apps) we serve it at the root, ie `GET /`.
23
24We *bootstrap* `index.html` with some initial data from the server, so that it gets dynamically injected JSON data without having to make another round-trip request to the server to get that data on the frontend. This is a common pattern for client-side rendered apps.
25
26## CRUD API Routes
27
28This app has two CRUD API routes: for reading and inserting into the messages table. They both speak JSON, which is standard. They import their functions from `/backend/database/queries.ts`. These routes are called from the React app to refresh and update data.
29
30## Errors
31
32Hono and other API frameworks have a habit of swallowing up Errors. We turn off this default behavior by re-throwing errors, because we think most of the time you'll want to see the full stack trace instead of merely "Internal Server Error". You can customize how you want errors to appear.
3import React, { useEffect, useState } from "https://esm.sh/react@18.2.0";
4
5// API Documentation
6/**
7 * @typedef {Object} ProjectState
67 setError(null);
68 try {
69 const response = await fetch("/api/state");
70 if (!response.ok) throw new Error("Failed to fetch state");
71 const data = await response.json();
86 setError(null);
87 try {
88 const response = await fetch("/api/state", {
89 method: "POST",
90 headers: { "Content-Type": "application/json" },
563
564 try {
565 if (req.method === "GET" && req.url.endsWith("/api/state")) {
566 const state = await getState();
567 return Response.json(
574 },
575 );
576 } else if (req.method === "POST" && req.url.endsWith("/api/state")) {
577 const update = await req.json();
578 validateInput(update);