1import { basicAuthMiddleware } from "./auth.ts";
2import { handleApiRequest } from "./api/index.ts";
3import { getRequests } from "./api/requests.ts";
4import { getUserSummary } from "./api/user-summary.ts";
5import { getInferenceCalls } from "./api/inference-calls.ts";
6import { renderDashboard } from "./views/dashboard.ts";
7import { renderRequests } from "./views/requests.ts";
22const path = url.pathname;
2324// Handle API requests
25if (path.startsWith("/api/")) {
26return handleApiRequest(req);
27}
28
45/**
6* Handle API requests
7*/
8export async function handleApiRequest(req: Request): Promise<Response> {
9const url = new URL(req.url);
10const path = url.pathname.replace("/api/", "");
11
12try {
13// Route to the appropriate API handler
14if (path === "requests") {
15const usageId = url.searchParams.get("usage_id");
59}
60} catch (error) {
61console.error("API error:", error);
62return new Response(JSON.stringify({ error: error.message }), {
63status: 500,
42</h2>
43<ol>
44<li>Login with your Val Town API token (with projects:read, projects:write, user:read permissions)</li>
45<li>Select a project to work on</li>
46<li>Chat with Claude about your code</li>
79</div>
80<h3>Cost Tracking</h3>
81<p>See estimated API usage costs for each interaction</p>
82</div>
83</section>
92<ul>
93<li>React frontend with TypeScript</li>
94<li>Hono API server backend</li>
95<li>Web Audio API for sound notifications</li>
96<li>AI SDK for Claude integration</li>
97</ul>
98<p>
99The application proxies requests to the Anthropic API and Val Town API, allowing Claude to view and edit your
100project files directly.
101</p>
TownieChatRoute.tsx2 matches
63refetch: () => void;
64}) {
65const { token, anthropicApiKey } = useAuth();
66const [images, setImages] = useState<(string|null)[]>([]);
67const [selectedFiles, setSelectedFiles] = useState<string[]>([]);
81project,
82branchId,
83anthropicApiKey,
84bearerToken: token,
85selectedFiles,
10const [query, setQuery] = React.useState("");
11const [targetAccount, setTargetAccount] = React.useState("");
12const [apiKey, setApiKey] = React.useState("");
13const [searchType, setSearchType] = React.useState("Latest");
14const [sinceDate, setSinceDate] = React.useState("");
50const fetchAllTweets = React.useCallback(
51async (fullQuery, type, targetCount) => {
52if (!apiKey.trim()) {
53setError("Please enter your SocialData API Key.");
54return;
55}
79}
8081const response = await fetch(`/api/search?${params.toString()}`, {
82headers: { "X-Api-Key": apiKey },
83});
8488const errorData = await response
89.json()
90.catch(() => ({ message: `API Error: ${response.statusText}` }));
91throw new Error(
92errorData.message
93|| `API Error: ${response.statusText} on page ${pageNum}`,
94);
95}
100if (data.status === "error") {
101throw new Error(
102data.message || `API returned an error on page ${pageNum}`,
103);
104}
135}
136},
137[apiKey],
138);
139144return;
145}
146if (!apiKey.trim()) {
147setError("Please enter your SocialData API Key.");
148return;
149}
176{ className: "app" },
177React.createElement("h1", { className: "title" }, "X Search"),
178// API Key Input
179React.createElement(
180"div",
185React.createElement(
186"label",
187{ htmlFor: "apiKey", className: "label" },
188"API Key",
189),
190React.createElement("input", {
191type: "password",
192id: "apiKey",
193value: apiKey,
194onChange: (e) => setApiKey(e.target.value),
195placeholder: "Enter SocialData API Key",
196className: "input",
197}),
565rel: "noopener noreferrer",
566},
567"SocialData API",
568),
569" | ",
598const url = new URL(request.url);
599600// Search API Proxy Endpoint
601if (url.pathname === "/api/search" && request.method === "GET") {
602const apiKey = request.headers.get("X-Api-Key");
603if (!apiKey) {
604return Response.json(
605{ status: "error", message: "API Key missing in request" },
606{ status: 400 },
607);
619}
620621const apiUrl = new URL("https://api.socialdata.tools/twitter/search");
622apiUrl.searchParams.set("query", query);
623apiUrl.searchParams.set("type", type);
624if (cursor) apiUrl.searchParams.set("cursor", cursor);
625626try {
627const apiResponse = await fetch(apiUrl.toString(), {
628headers: {
629Authorization: `Bearer ${apiKey}`,
630Accept: "application/json",
631},
634let responseData;
635try {
636responseData = await apiResponse.json();
637} catch (e) {
638const text = await apiResponse.text();
639console.error("Non-JSON response from SocialData:", text);
640return Response.json(
641{
642status: "error",
643message: `SocialData API non-JSON response: ${apiResponse.statusText}`,
644},
645{ status: apiResponse.status },
646);
647}
648649if (!apiResponse.ok || responseData.status === "error") {
650console.error(
651`SocialData API Error (${apiResponse.status}):`,
652responseData,
653);
656status: "error",
657message: responseData?.message
658|| `SocialData API Error: ${apiResponse.statusText}`,
659},
660{ status: apiResponse.status },
661);
662}
41: `applications/${DISCORD_APP_ID}/commands`;
4243console.log(`📡 Using API endpoint: ${endpoint}`);
4445try {
4950// Register the command using POST for a single command
51const response = await fetch(`https://discord.com/api/v10/${endpoint}`, {
52method: "POST", // Using POST for single command creation
53headers: {
19console.log(`📤 Sending follow-up message: ${content}`);
20try {
21await fetch(`https://discord.com/api/v10/webhooks/${applicationId}/${interactionToken}/messages/@original`, {
22method: "PATCH",
23headers: {
50: `applications/${DISCORD_APP_ID}/commands`;
5152console.log(`📡 Using API endpoint: ${endpoint}`);
5354try {
5859// Register the command using POST for a single command
60const response = await fetch(`https://discord.com/api/v10/${endpoint}`, {
61method: "POST", // Using POST for single command creation
62headers: {
57: `applications/${DISCORD_APP_ID}/commands`;
5859console.log(`📡 Using API endpoint: ${endpoint}`);
60const results = [];
616768// Register the command using POST for a single command
69const response = await fetch(`https://discord.com/api/v10/${endpoint}`, {
70method: "POST", // Using POST for single command creation
71headers: {
50: `applications/${DISCORD_APP_ID}/commands`;
5152console.log(`📡 Using API endpoint: ${endpoint}`);
5354try {
5859// Register the command using POST for a single command
60const response = await fetch(`https://discord.com/api/v10/${endpoint}`, {
61method: "POST", // Using POST for single command creation
62headers: {