static site frontend for mapped.at mapped.at
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add val town backend config

+328 -6
+1
.gitignore
··· 1 + .vt 1 2 .superpowers 2 3 docs 3 4 public/data/service.json
+2 -2
val/backend.test.ts val/mapped-at-backend/main.test.ts
··· 1 - import { assertEquals } from "jsr:@std/assert"; 2 - import { handler } from "./backend.ts"; 1 + import { assertEquals } from "jsr:@std/assert@1.0.19"; 2 + import { handler } from "./main.ts"; 3 3 4 4 // ── Routing ─────────────────────────────────────────────────────────────────── 5 5
-4
val/backend.ts val/mapped-at-backend/main.ts
··· 15 15 export function handler(req: Request) { 16 16 const url = new URL(req.url); 17 17 18 - if (req.method === "GET") { 19 - return Response.json({ ok: true }); 20 - } 21 - 22 18 if (req.method !== "POST") { 23 19 return Response.json({ error: "Method not allowed" }, { status: 405 }); 24 20 }
+6
val/mapped-at-backend/.vtignore
··· 1 + .git 2 + .vscode 3 + .cursorrules 4 + .DS_Store 5 + node_modules 6 + vendor
+290
val/mapped-at-backend/AGENTS.md
··· 1 + You are an advanced assistant specialized in generating Val Town code. 2 + 3 + ## Core Guidelines 4 + 5 + - Ask clarifying questions when requirements are ambiguous 6 + - Provide complete, functional solutions rather than skeleton implementations 7 + - Test your logic against edge cases before presenting the final solution 8 + - Ensure all code follows Val Town's specific platform requirements 9 + - If a section of code that you're working on is getting too complex, consider refactoring it into subcomponents 10 + 11 + ## Code Standards 12 + 13 + - Generate code in TypeScript or TSX 14 + - Add appropriate TypeScript types and interfaces for all data structures 15 + - Prefer official SDKs or libraries than writing API calls directly 16 + - Ask the user to supply API or library documentation if you are at all unsure about it 17 + - **Never bake in secrets into the code** - always use environment variables 18 + - Include comments explaining complex logic (avoid commenting obvious operations) 19 + - Follow modern ES6+ conventions and functional programming practices if possible 20 + 21 + ## Types of triggers 22 + 23 + ### 1. HTTP Trigger 24 + 25 + - Create web APIs and endpoints 26 + - Handle HTTP requests and responses 27 + - Example structure: 28 + 29 + ```ts 30 + export default async function (req: Request) { 31 + return new Response("Hello World"); 32 + } 33 + ``` 34 + 35 + Files that are HTTP triggers have http in their name like `foobar.http.tsx` 36 + 37 + ### 2. Cron Triggers 38 + 39 + - Run on a schedule 40 + - Use cron expressions for timing 41 + - Example structure: 42 + 43 + ```ts 44 + export default async function () { 45 + // Scheduled task code 46 + } 47 + ``` 48 + 49 + Files that are Cron triggers have cron in their name like `foobar.cron.tsx` 50 + 51 + ### 3. Email Triggers 52 + 53 + - Process incoming emails 54 + - Handle email-based workflows 55 + - Example structure: 56 + 57 + ```ts 58 + export default async function (email: Email) { 59 + // Process email 60 + } 61 + ``` 62 + 63 + Files that are Email triggers have email in their name like `foobar.email.tsx` 64 + 65 + 66 + ## Val Town Standard Libraries 67 + 68 + Val Town provides several hosted services and utility functions. 69 + 70 + ### Blob Storage 71 + 72 + ```ts 73 + import { blob } from "https://esm.town/v/std/blob"; 74 + await blob.setJSON("myKey", { hello: "world" }); 75 + let blobDemo = await blob.getJSON("myKey"); 76 + let appKeys = await blob.list("app_"); 77 + await blob.delete("myKey"); 78 + ``` 79 + 80 + ### SQLite 81 + 82 + ```ts 83 + import { sqlite } from "https://esm.town/v/stevekrouse/sqlite"; 84 + const TABLE_NAME = 'todo_app_users_2'; 85 + // Create table - do this before usage and change table name when modifying schema 86 + await sqlite.execute(`CREATE TABLE IF NOT EXISTS ${TABLE_NAME} ( 87 + id INTEGER PRIMARY KEY AUTOINCREMENT, 88 + name TEXT NOT NULL 89 + )`); 90 + // Query data 91 + const result = await sqlite.execute(`SELECT * FROM ${TABLE_NAME} WHERE id = ?`, [1]); 92 + ``` 93 + 94 + Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table. 95 + 96 + ### OpenAI 97 + 98 + ```ts 99 + import { OpenAI } from "https://esm.town/v/std/openai"; 100 + const openai = new OpenAI(); 101 + const completion = await openai.chat.completions.create({ 102 + messages: [ 103 + { role: "user", content: "Say hello in a creative way" }, 104 + ], 105 + model: "gpt-4o-mini", 106 + max_tokens: 30, 107 + }); 108 + ``` 109 + 110 + ### Email 111 + 112 + ```ts 113 + import { email } from "https://esm.town/v/std/email"; 114 + // By default emails the owner of the val 115 + await email({ 116 + subject: "Hi", 117 + text: "Hi", 118 + html: "<h1>Hi</h1>" 119 + }); 120 + ``` 121 + 122 + ## Val Town Utility Functions 123 + 124 + Val Town provides several utility functions to help with common project tasks. 125 + 126 + ### Importing Utilities 127 + 128 + Always import utilities with version pins to avoid breaking changes: 129 + 130 + ```ts 131 + import { parseProject, readFile, serveFile } from "https://esm.town/v/std/utils@85-main/index.ts"; 132 + ``` 133 + 134 + ### Available Utilities 135 + 136 + 137 + #### **serveFile** - Serve project files with proper content types 138 + 139 + For example, in Hono: 140 + 141 + ```ts 142 + // serve all files in frontend/ and shared/ 143 + app.get("/frontend/*", c => serveFile(c.req.path, import.meta.url)); 144 + app.get("/shared/*", c => serveFile(c.req.path, import.meta.url)); 145 + ``` 146 + 147 + #### **readFile** - Read files from within the project: 148 + 149 + ```ts 150 + // Read a file from the project 151 + const fileContent = await readFile("/frontend/index.html", import.meta.url); 152 + ``` 153 + 154 + #### **listFiles** - List all files in the project 155 + 156 + ```ts 157 + const files = await listFiles(import.meta.url); 158 + ``` 159 + 160 + #### **parseProject** - Extract information about the current project from import.meta.url 161 + 162 + This is useful for including info for linking back to a val, ie in "view source" urls: 163 + 164 + ```ts 165 + const projectVal = parseProject(import.meta.url); 166 + console.log(projectVal.username); // Owner of the project 167 + console.log(projectVal.name); // Project name 168 + console.log(projectVal.version); // Version number 169 + console.log(projectVal.branch); // Branch name 170 + console.log(projectVal.links.self.project); // URL to the project page 171 + ``` 172 + 173 + However, it's *extremely importing* to note that `parseProject` and other Standard Library utilities ONLY RUN ON THE SERVER. 174 + If you need access to this data on the client, run it in the server and pass it to the client by splicing it into the HTML page 175 + or by making an API request for it. 176 + 177 + ## Val Town Platform Specifics 178 + 179 + - **Redirects:** Use `return new Response(null, { status: 302, headers: { Location: "/place/to/redirect" }})` instead of `Response.redirect` which is broken 180 + - **Images:** Avoid external images or base64 images. Use emojis, unicode symbols, or icon fonts/libraries instead 181 + - **AI Image:** To inline generate an AI image use: `<img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" />` 182 + - **Storage:** DO NOT use the Deno KV module for storage 183 + - **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods 184 + - **Weather Data:** Use open-meteo for weather data (doesn't require API keys) unless otherwise specified 185 + - **View Source:** Add a view source link by importing & using `import.meta.url.replace("ems.sh", "val.town)"` (or passing this data to the client) and include `target="_top"` attribute 186 + - **Error Debugging:** Add `<script src="https://esm.town/v/std/catch"></script>` to HTML to capture client-side errors 187 + - **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 188 + - **Environment Variables:** Use `Deno.env.get('keyname')` when you need to, but generally prefer APIs that don't require keys 189 + - **Imports:** Use `https://esm.sh` for npm and Deno dependencies to ensure compatibility on server and browser 190 + - **Storage Strategy:** Only use backend storage if explicitly required; prefer simple static client-side sites 191 + - **React Configuration:** When using React libraries, pin versions with `?deps=react@18.2.0,react-dom@18.2.0` and start the file with `/** @jsxImportSource https://esm.sh/react@18.2.0 */` 192 + - Ensure all React dependencies and sub-dependencies are pinned to the same version 193 + - **Styling:** Default to using TailwindCSS via `<script src="https://cdn.twind.style" crossorigin></script>` unless otherwise specified 194 + 195 + ## Project Structure and Design Patterns 196 + 197 + ### Recommended Directory Structure 198 + ``` 199 + ├── backend/ 200 + │ ├── database/ 201 + │ │ ├── migrations.ts # Schema definitions 202 + │ │ ├── queries.ts # DB query functions 203 + │ │ └── README.md 204 + │ └── routes/ # Route modules 205 + │ ├── [route].ts 206 + │ └── static.ts # Static file serving 207 + │ ├── index.ts # Main entry point 208 + │ └── README.md 209 + ├── frontend/ 210 + │ ├── components/ 211 + │ │ ├── App.tsx 212 + │ │ └── [Component].tsx 213 + │ ├── favicon.svg 214 + │ ├── index.html # Main HTML template 215 + │ ├── index.tsx # Frontend JS entry point 216 + │ ├── README.md 217 + │ └── style.css 218 + ├── README.md 219 + └── shared/ 220 + ├── README.md 221 + └── utils.ts # Shared types and functions 222 + ``` 223 + 224 + ### Backend (Hono) Best Practices 225 + 226 + - Hono is the recommended API framework 227 + - Main entry point should be `backend/index.ts` 228 + - **Static asset serving:** Use the utility functions to read and serve project files: 229 + ```ts 230 + import { readFile, serveFile } from "https://esm.town/v/std/utils@85-main/index.ts"; 231 + 232 + // serve all files in frontend/ and shared/ 233 + app.get("/frontend/*", c => serveFile(c.req.path, import.meta.url)); 234 + app.get("/shared/*", c => serveFile(c.req.path, import.meta.url)); 235 + 236 + // For index.html, often you'll want to bootstrap with initial data 237 + app.get("/", async c => { 238 + let html = await readFile("/frontend/index.html", import.meta.url); 239 + 240 + // Inject data to avoid extra round-trips 241 + const initialData = await fetchInitialData(); 242 + const dataScript = `<script> 243 + window.__INITIAL_DATA__ = ${JSON.stringify(initialData)}; 244 + </script>`; 245 + 246 + html = html.replace("</head>", `${dataScript}</head>`); 247 + return c.html(html); 248 + }); 249 + ``` 250 + - Create RESTful API routes for CRUD operations 251 + - Always include this snippet at the top-level Hono app to re-throwing errors to see full stack traces: 252 + ```ts 253 + // Unwrap Hono errors to see original error details 254 + app.onError((err, c) => { 255 + throw err; 256 + }); 257 + ``` 258 + 259 + ### Database Patterns 260 + - Run migrations on startup or comment out for performance 261 + - Change table names when modifying schemas rather than altering 262 + - Export clear query functions with proper TypeScript typing 263 + 264 + ## Common Gotchas and Solutions 265 + 266 + 1. **Environment Limitations:** 267 + - Val Town runs on Deno in a serverless context, not Node.js 268 + - Code in `shared/` must work in both frontend and backend environments 269 + - Cannot use `Deno` keyword in shared code 270 + - Use `https://esm.sh` for imports that work in both environments 271 + 272 + 2. **SQLite Peculiarities:** 273 + - Limited support for ALTER TABLE operations 274 + - Create new tables with updated schemas and copy data when needed 275 + - Always run table creation before querying 276 + 277 + 3. **React Configuration:** 278 + - All React dependencies must be pinned to 18.2.0 279 + - Always include `@jsxImportSource https://esm.sh/react@18.2.0` at the top of React files 280 + - Rendering issues often come from mismatched React versions 281 + 282 + 4. **File Handling:** 283 + - Val Town only supports text files, not binary 284 + - Use the provided utilities to read files across branches and forks 285 + - For files in the project, use `readFile` helpers 286 + 287 + 5. **API Design:** 288 + - `fetch` handler is the entry point for HTTP vals 289 + - Run the Hono app with `export default app.fetch // This is the entry point for HTTP vals` 290 +
+29
val/mapped-at-backend/deno.json
··· 1 + { 2 + "$schema": "https://raw.githubusercontent.com/denoland/deno/98f62cee78e85bfc47c62ed703777c6bc8794f1c/cli/schemas/config-file.v1.json", 3 + "lock": false, 4 + "compilerOptions": { 5 + "noImplicitAny": false, 6 + "strict": true, 7 + "types": ["https://www.val.town/types/valtown.d.ts"], 8 + "lib": [ 9 + "dom", 10 + "dom.iterable", 11 + "dom.asynciterable", 12 + "deno.ns", 13 + "deno.unstable" 14 + ] 15 + }, 16 + "lint": { 17 + "include": ["deno:/https/esm.town/**/*"], 18 + "rules": { 19 + "exclude": ["no-explicit-any"] 20 + } 21 + }, 22 + "node_modules_dir": false, 23 + "experimental": { 24 + "unstable-node-globals": true, 25 + "unstable-temporal": true, 26 + "unstable-worker-options": true, 27 + "unstable-sloppy-imports": true 28 + } 29 + }