50 try {
51 setLoading(true);
52 const response = await fetch('/api/vals');
53 const result = await response.json();
54
109
110 if (error) {
111 const isTokenError = error.includes('API token not configured');
112 return h('div', { className: 'flex items-center justify-center min-h-screen' },
113 h('div', { className: 'text-center max-w-lg mx-auto p-6' },
114 h('div', { className: 'text-red-500 text-6xl mb-4' }, isTokenError ? '🔑' : '⚠️'),
115 h('h2', { className: 'text-xl font-semibold text-gray-900 mb-2' },
116 isTokenError ? 'API Token Required' : 'Error Loading Vals'
117 ),
118 h('p', { className: 'text-gray-600 mb-4' }, error),
121 h('ol', { className: 'text-sm text-blue-800 space-y-1 list-decimal list-inside' },
122 h('li', null, 'Go to ', h('a', {
123 href: 'https://www.val.town/settings/api',
124 target: '_blank',
125 className: 'underline hover:text-blue-600'
126 }, 'Val Town API Settings')),
127 h('li', null, 'Create a new API token'),
128 h('li', null, 'Set VALTOWN_API_TOKEN environment variable'),
129 h('li', null, 'Refresh this page')
130 )
12## Structure
13
14- `backend/index.ts` - Main Hono server with API routes
15- `frontend/index.html` - Main web interface
16- `frontend/index.tsx` - React frontend application
19## Setup
20
211. **Get your Val Town API token:**
22 - Go to [Val Town Settings](https://www.val.town/settings/api)
23 - Create a new API token
24 - Copy the token
25
262. **Set the environment variable:**
27 - In your Val Town environment, set `VALTOWN_API_TOKEN` to your API token
28 - The app will automatically fetch and display your vals
29
11 /* 1 ▸ Crypto with 7-day sparkline ------------------------------- */
12 const ids = crypto.join(",");
13 const url = `https://api.coingecko.com/api/v3/coins/markets`
14 + `?vs_currency=aud&ids=${ids}&sparkline=true`;
15 const coins = await fetch(url, { headers: { "x-cg-demo-api-key": CG } }).then(r => r.json());
16
17 coins.forEach((c: any) => {
46app.post("/mcp", async (c) => {
47 try {
48 // Extract API token from headers
49 const apiToken = c.req.header("X-Val-Town-Token") ||
50 c.req.header("Authorization")?.replace("Bearer ", "")
51
52 if (!apiToken) {
53 return c.json({
54 jsonrpc: "2.0",
55 error: {code: -32000, message: "Missing API token in X-Val-Town-Token header or Authorization header"},
56 id: null
57 }, 401)
60 // Load remote configuration
61 const config = await loadConfig(true)
62 config.apiToken = apiToken
63
64 console.log({apiToken})
65 // Convert Hono request to Node.js-style req/res
66 const {req, res} = toReqRes(c.req.raw)
104- For AI-generated images, use: `https://maxm-imggenurl.web.val.run/the-description-of-your-image`
105- **Storage:** DO NOT use the Deno KV module for storage
106- **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods
107- **Weather Data:** Use open-meteo for weather data (doesn't require API keys) unless otherwise specified
108- **View Source:** Add a view source link with `import.meta.url.replace("esm.town", "val.town")` and include `target="_top"` attribute
109- **Error Debugging:** Add `<script src="https://esm.town/v/std/catch"></script>` to HTML to capture client-side errors
110- **Error Handling:** Only use try...catch when there's a clear local resolution; avoid catches that merely log or return 500s - let errors bubble up with full context
111- **Environment Variables:** Use `Deno.env.get('keyname')` and minimize their use - prefer APIs without keys
112- **Imports:** Use JSR.io, NPM and ESM imports in that order to ensure the latest and stable versions are available to use from official providers.
113- **Storage Strategy:** Only use backend storage if explicitly required; prefer simple static client-side sites
194
195### Backend (Hono) Best Practices
196- Hono is the recommended API framework (similar to Express, Flask, or Sinatra)
197- Main entry point should be `backend/index.ts`
198- **Static asset serving:** Use the utility functions to read and serve project files:
215 });
216 ```
217- Create RESTful API routes for CRUD operations
218- Be careful with error handling as Hono tends to swallow errors
219- Consider re-throwing errors to see full stack traces:
232- Use React 18.2.0 consistently in all imports and the `@jsxImportSource` pragma
233- Follow the React component pattern from the example project
234- Handle API calls properly with proper error catching
235
236### Database Patterns
263 - For files in the project, use `readFile` helpers
264
2655. **API Design:**
266 - `fetch` handler is the entry point for HTTP vals
267 - Run the Hono app with `export default app.fetch // This is the entry point for HTTP vals`