OpenTowniesend-message.ts11 matches
19}
2021const { messages, project, branchId, anthropicApiKey, selectedFiles, images } = await c.req.json();
22console.log("Original messages:", JSON.stringify(messages, null, 2));
23console.log("Images received:", JSON.stringify(images, null, 2));
2425// Check if API key is available
26if (!anthropicApiKey) {
27return Response.json({
28error: "Anthropic API key is required. Please log out and add your Anthropic API key to use this app.",
29}, { status: 400 });
30}
3132let apiKey;
33if (!anthropicApiKey) {
34return Response.json({
35error: "Anthropic API key is required. Please log out and add your Anthropic API key to use this app.",
36}, { status: 400 });
37} else if (anthropicApiKey === Deno.env.get("PASSWORD")) {
38apiKey = Deno.env.get("PROVIDED_ANTHROPIC_API_KEY");
39} else {
40apiKey = anthropicApiKey;
41}
4243const anthropic = createAnthropic({
44apiKey,
45});
46
OpenTowniePreview.tsx1 match
90value={customPath}
91onChange={handlePathChange}
92placeholder="Path (e.g., /api/data)"
93/>
94</div>
OpenTownieLoginRoute.tsx7 matches
8const { isAuthenticated, authenticate, error } = useAuth();
9const [tokenValue, setTokenValue] = useState("");
10const [apiKey, setApiKey] = useState("");
11// const [invalid, setInvalid] = useState(""); // TODO
1213const handleSubmit = (e) => {
14e.preventDefault();
15authenticate(tokenValue, apiKey);
16}
1736>
37<div>
38<label htmlFor="valtown-token" className="label">Val Town API Token</label>
39<input
40type="password"
48</div>
49<div>
50<label htmlFor="anthropic-api-key" className="label">Anthropic API Key</label>
51<input
52type="password"
53id="anthropic-api-key"
54name="anthropic-key"
55value={apiKey}
56onChange={e => {
57setApiKey(e.target.value);
58}}
59/>
OpenTownieindex.ts2 matches
11app.get("*", async (c, next) => {
12const path = c.req.path;
13if (path.startsWith("/api/") || c.req.header("Accept")?.includes("application/json")) {
14return next();
15}
21});
2223app.route("/api", backend);
24app.get("/frontend/*", c => {
25return serveFile(c.req.path, import.meta.url);
OpenTownieHome.tsx6 matches
48</h2>
49<ol>
50<li>Login with your Val Town API token</li>
51<li>Add your Anthropic API key</li>
52<li>Select a project to work on</li>
53<li>Chat with Claude about your code</li>
86</div>
87<h3>Cost Tracking</h3>
88<p>See estimated API usage costs for each interaction</p>
89</div>
90</section>
99<ul>
100<li>React frontend with TypeScript</li>
101<li>Hono API server backend</li>
102<li>Web Audio API for sound notifications</li>
103<li>AI SDK for Claude integration</li>
104</ul>
105<p >
106The application proxies requests to the Anthropic API and Val Town API, allowing Claude to view and edit your project files directly.
107</p>
108<div >
OpenTownieChatRoute.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,
IClickWolfindex.ts2 matches
12app.get("/frontend/**/*", c => serveFile(c.req.path, import.meta.url));
1314// Add your API routes here
15// app.get("/api/data", c => c.json({ hello: "world" }));
1617// Unwrap and rethrow Hono errors as the original error
blog2025-04-08-migration.md1 match
83We didn't. We left them where they are, and proxy to them.
8485Writing a proxy in Val Town (or any functions platform with the ['fetch handler' interface](https://blog.val.town/blog/the-api-we-forgot-to-name/)) is a delight:
8687```ts
bloglive-reload.ts1 match
82// if we wanted to create a /lastUpdatedAt route,
83// which would let us pass a val town bearer token, we could do that here
84// gives us 10k API requests per minute instead of 1k
85// and would work with private projects
86
blogget-old-posts.ts25 matches
19export const oldPosts: BlogPost[] = [
20{
21"title": "Solving the internal / external API riddle",
22"slug": "api-conundrum",
23"link": "/blog/api-conundrum",
24"description": "Figuring out how to provide an API that's usable by everyone and fast for us to iterate on",
25"pubDate": "Thu, 27 Mar 2025 00:00:00 GMT",
26"author": "Tom MacWright",
27},
28{
29"title": "API Tokens Scopes",
30"slug": "api-token-scopes",
31"link": "/blog/api-token-scopes",
32"description": "Improving security with granular control over permissions",
33"pubDate": "Fri, 01 Nov 2024 00:00:00 GMT",
59},
60{
61"title": "Expanding the Vals API - RFC",
62"slug": "expanding-the-vals-api-rfc",
63"link": "/blog/expanding-the-vals-api-rfc",
64"description": "Our REST API lets you do a lot - and soon it will enable more",
65"pubDate": "Fri, 30 Jun 2023 00:00:00 GMT",
66"author": "André Terron",
133},
134{
135"title": "The perks of a good OpenAPI spec",
136"slug": "openapi",
137"link": "/blog/openapi",
138"description": "Taking advantage of our typed REST API to build a platform around\nVal Town.",
139"pubDate": "Thu, 25 Jul 2024 00:00:00 GMT",
140"author": "Tom MacWright",
262},
263{
264"title": "The API we forgot to name",
265"slug": "the-api-we-forgot-to-name",
266"link": "/blog/the-api-we-forgot-to-name",
267"description": "An API that takes a Request and returns a Response - what was that, again?",
268"pubDate": "Thu, 19 Oct 2023 00:00:00 GMT",
269"author": "Steve Krouse",
286},
287{
288"title": "Deprecating the Run API",
289"slug": "deprecating-the-run-api",
290"link": "/blog/deprecating-the-run-api",
291"description": "Not every function should be an API",
292"pubDate": "Wed, 07 Feb 2024 00:00:00 GMT",
293"author": "André Terron",
321"slug": "val-town-newsletter-1",
322"link": "/blog/val-town-newsletter-1",
323"description": "Programmatic notifications, Hacker News API, and more.",
324"pubDate": "Wed, 04 Jan 2023 00:00:00 GMT",
325"author": "Steve Krouse",
450"slug": "val-town-newsletter-22",
451"link": "/blog/val-town-newsletter-22",
452"description": "Townie upgrades, Scoped API permissions, Fal partnership",
453"pubDate": "Mon, 02 Dec 2024 00:00:00 GMT",
454"author": "Steve Krouse",