ChatHTMLRenderer.tsx23 matches
9}
1011interface MCPContextAPI {
12// Tool operations
13listTools: () => Promise<any[]>;
37* - Renders HTML in a secure iframe
38* - Provides fullscreen enter/exit affordances
39* - Exposes MCP context API to iframe content
40* - Handles iframe communication via postMessage
41*/
47console.log("[MCP/Browser Renderer] HTMLRenderer: Rendering HTML:", { mcpClients });
4849// Create MCP context API that will be exposed to iframe
50const createMCPContext = useCallback((): MCPContextAPI => {
51const findClientByName = (serverName: string) => {
52console.log("[MCP/Browser Renderer] Finding client by name:", serverName, mcpClients);
177const { type, id, method, args } = event.data;
178179if (type !== "mcp-api-call") {
180return;
181}
186187if (typeof methodFunc !== "function") {
188throw new Error(`Unknown MCP API method: ${method}`);
189}
190192193iframe.contentWindow?.postMessage({
194type: "mcp-api-response",
195id,
196success: true,
199} catch (error) {
200iframe.contentWindow?.postMessage({
201type: "mcp-api-response",
202id,
203success: false,
222</script>
223<script>
224// MCP Context API for iframe content
225window.mcpContext = {
226// Async wrapper for postMessage communication
227async callAPI(method, ...args) {
228return new Promise((resolve, reject) => {
229const id = Math.random().toString(36).substr(2, 9);
230
231const handleResponse = (event) => {
232if (event.data.type === 'mcp-api-response' && event.data.id === id) {
233window.removeEventListener('message', handleResponse);
234if (event.data.success) {
243
244window.parent.postMessage({
245type: 'mcp-api-call',
246id,
247method,
252setTimeout(() => {
253window.removeEventListener('message', handleResponse);
254reject(new Error('MCP API call timeout'));
255}, 30000);
256});
258
259// Convenience methods
260async listTools() { return this.callAPI('listTools'); },
261async callTool(serverName, toolName, args) { return this.callAPI('callTool', serverName, toolName, args); },
262async listPrompts() { return this.callAPI('listPrompts'); },
263async getPrompt(serverName, promptName, args) { return this.callAPI('getPrompt', serverName, promptName, args); },
264async listResources() { return this.callAPI('listResources'); },
265async readResource(serverName, uri) { return this.callAPI('readResource', serverName, uri); },
266log(level, message, data) { this.callAPI('log', level, message, data); },
267requestFullscreen() { this.callAPI('requestFullscreen'); },
268exitFullscreen() { this.callAPI('exitFullscreen'); },
269async isFullscreen() { return this.callAPI('isFullscreen'); }
270};
271
1import { getArticle, getAuthor } from "./_api.ts";
2import { createServer } from "./_server.ts";
3
1import { getArticle } from "./_api.ts";
2import { createServer } from "./_server.ts";
3
1import { getArticle } from "./_api.ts";
2import { createServer } from "./_server.ts";
3
graphql-crash-course_api.ts0 matches
1import { setTimeout } from "node:timers/promises";
23const articles = [{
4id: 0,
5title: "A Crash Course in GraphQL",
hm-invoicesv1PLAN.md14 matches
6## Phase Completion Checklist
7- [x] Phase 1: Foundation & Database Setup
8- [x] Phase 2: Core Backend API
9- [x] Phase 3: Frontend Foundation
10- [x] Phase 4: Enhanced UI & Interactions
59---
6061## Phase 2: Core Backend API
62**Goal**: Build RESTful API endpoints for invoice management
6364### Tasks:
651. **Main API Setup**
66- Create `main.tsx` with Hono app configuration
67- Set up error handling and static file serving
68- Configure CORS if needed
69702. **Invoice API Endpoints**
71- `GET /api/invoices` - List all invoices with filtering
72- `POST /api/invoices` - Create new invoice
73- `PUT /api/invoices/:id` - Update invoice (mainly status changes)
74- `GET /api/invoices/stats` - Dashboard statistics
75763. **Vendor API Endpoints**
77- `GET /api/vendors` - List all vendors
7879### Deliverables:
80- Complete REST API for invoice management
81- API endpoints tested via admin tools or direct calls
82- Proper error handling and validation
83171172## Technical Stack
173- **Backend**: Hono.js for API routes
174- **Database**: SQLite with Val Town's sqlite service
175- **Frontend**: React 18.2.0 with TypeScript
hm-invoicesv1StatusProgress.tsx3 matches
64{getStatusIcon(status, index)}
65</span>
66<span className="text-xs mt-1 capitalize">
67{status}
68</span>
76<div className="text-sm opacity-70">
77Step {currentIndex + 1} of {statuses.length}:
78<span className="font-medium capitalize ml-1">{currentStatus}</span>
79</div>
80{interactive && currentIndex < statuses.length - 1 && (
124max="100"
125></progress>
126<span className="text-xs capitalize font-medium">
127{currentStatus}
128</span>
hm-invoicesv1App.tsx12 matches
23import React, { useState, useEffect } from "https://esm.sh/react@18.2.0";
4import { InvoiceWithVendor, Vendor, InvoiceFilters, InvoiceStats, InvoiceStatus, ApiResponse } from "../../shared/types.ts";
5import InvoiceList from "./InvoiceList.tsx";
6import InvoiceForm from "./InvoiceForm.tsx";
18const [activeTab, setActiveTab] = useState<'dashboard' | 'invoices' | 'add'>('dashboard');
1920// Fetch data from API
21useEffect(() => {
22fetchData();
40
41const [invoicesResponse, vendorsResponse] = await Promise.all([
42fetch(`/api/invoices?${queryParams.toString()}`),
43fetch('/api/vendors')
44]);
4548}
4950const invoicesData: ApiResponse<InvoiceWithVendor[]> = await invoicesResponse.json();
51const vendorsData: ApiResponse<Vendor[]> = await vendorsResponse.json();
5253if (!invoicesData.success || !vendorsData.success) {
69try {
70setStatsLoading(true);
71const response = await fetch('/api/invoices/stats');
72
73if (!response.ok) {
75}
7677const data: ApiResponse<InvoiceStats> = await response.json();
78
79if (!data.success) {
92const handleAddInvoice = async (invoiceData: any) => {
93try {
94const response = await fetch('/api/invoices', {
95method: 'POST',
96headers: {
104}
105106const data: ApiResponse<InvoiceWithVendor> = await response.json();
107
108if (!data.success) {
123const handleStatusUpdate = async (invoiceId: number, newStatus: InvoiceStatus) => {
124try {
125const response = await fetch(`/api/invoices/${invoiceId}`, {
126method: 'PUT',
127headers: {
135}
136137const data: ApiResponse<InvoiceWithVendor> = await response.json();
138
139if (!data.success) {
hm-invoicesv1InvoiceList.tsx1 match
217</div>
218</td>
219<td className="capitalize">{invoice.expected_day}</td>
220<td>{new Date(invoice.invoice_date).toLocaleDateString()}</td>
221<td>
hm-invoicesv1VAL-TOWN-RULES.md10 matches
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)
23### 1. HTTP Trigger
2425- Create web APIs and endpoints
26- Handle HTTP requests and responses
27- Example structure:
133However, it's *extremely importing* to note that `parseProject` and other Standard Library utilities ONLY RUN ON THE SERVER.
134If 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
135or by making an API request for it.
136137## Val Town Platform Specifics
141- **AI Image:** To inline generate an AI image use: `<img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" />`
142- **Storage:** DO NOT use the Deno KV module for storage
143- **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods
144- **Weather Data:** Use open-meteo for weather data (doesn't require API keys) unless otherwise specified
145- **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
146- **Error Debugging:** Add `<script src="https://esm.town/v/std/catch"></script>` to HTML to capture client-side errors
147- **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
148- **Environment Variables:** Use `Deno.env.get('keyname')` when you need to, but generally prefer APIs that don't require keys
149- **Imports:** Use `https://esm.sh` for npm and Deno dependencies to ensure compatibility on server and browser
150- **Storage Strategy:** Only use backend storage if explicitly required; prefer simple static client-side sites
371### Backend (Hono) Best Practices
372373- Hono is the recommended API framework
374- Main entry point should be `main.tsx`
375- **Database Setup:** Use the admin utilities to handle table creation and seeding. Backend should focus on CRUD operations only
397});
398```
399- Create RESTful API routes for CRUD operations
400- Always include this snippet at the top-level Hono app to re-throwing errors to see full stack traces:
401```ts
437- For files in the project, use `readFile` helpers
4384395. **API Design:**
440- `fetch` handler is the entry point for HTTP vals
441- Run the Hono app with `export default app.fetch // This is the entry point for HTTP vals`