Highly ambitious ATProtocol AppView service and sdks
1/// <reference lib="deno.ns" />
2
3import { allRoutes } from "./routes.ts";
4import { serveDir } from "@std/http/file-server";
5
6const PORT = parseInt(Deno.env.get("PORT") || "3001");
7const VITE_DEV_SERVER = "http://localhost:5173"; // Default Vite dev server port
8
9// Check if we're in development mode (Vite dev server running)
10const isDevelopment = Deno.env.get("NODE_ENV") !== "production";
11
12async function defaultHandler(req: Request): Promise<Response> {
13 const url = new URL(req.url);
14
15 // In development, proxy to Vite dev server
16 if (isDevelopment) {
17 try {
18 // For SPA routing: All non-API routes go to Vite
19 // Vite will handle returning index.html for unknown routes
20 const viteUrl = new URL(url.pathname + url.search, VITE_DEV_SERVER);
21
22 // Create a clean headers object without Host header
23 const proxyHeaders = new Headers();
24 for (const [key, value] of req.headers.entries()) {
25 // Skip host and connection headers
26 if (
27 key.toLowerCase() !== "host" &&
28 key.toLowerCase() !== "connection"
29 ) {
30 proxyHeaders.set(key, value);
31 }
32 }
33
34 return await fetch(viteUrl.toString(), {
35 method: req.method,
36 headers: proxyHeaders,
37 body:
38 req.method !== "GET" && req.method !== "HEAD" ? req.body : undefined,
39 });
40 } catch (_error) {
41 return new Response(
42 `<!DOCTYPE html>
43<html>
44<head>
45 <title>Vite Dev Server Not Running</title>
46 <style>
47 body {
48 font-family: system-ui, -apple-system, sans-serif;
49 padding: 40px;
50 max-width: 600px;
51 margin: 0 auto;
52 line-height: 1.6;
53 }
54 h1 { color: #e74c3c; }
55 code {
56 background: #f4f4f4;
57 padding: 2px 6px;
58 border-radius: 3px;
59 font-family: monospace;
60 }
61 .command {
62 background: #2c3e50;
63 color: #ecf0f1;
64 padding: 15px;
65 border-radius: 5px;
66 margin: 15px 0;
67 }
68 </style>
69</head>
70<body>
71 <h1>⚠️ Vite Dev Server Not Running</h1>
72 <p>The Deno server is running, but it can't connect to the Vite dev server at <code>${VITE_DEV_SERVER}</code>.</p>
73 <p><strong>Start the Vite dev server in a separate terminal:</strong></p>
74 <div class="command">cd frontend-v2<br>deno task dev:vite</div>
75 <p>Then refresh this page.</p>
76</body>
77</html>`,
78 {
79 status: 503,
80 headers: { "Content-Type": "text/html" },
81 }
82 );
83 }
84 } else {
85 // In production, serve static files from dist/
86 // For SPA routing: return index.html for non-file requests
87 const response = await serveDir(req, {
88 fsRoot: "./dist",
89 quiet: true,
90 });
91
92 // If file not found (404), return index.html for SPA routing
93 if (response.status === 404) {
94 const indexFile = await Deno.readFile("./dist/index.html");
95 return new Response(indexFile, {
96 headers: { "Content-Type": "text/html" },
97 });
98 }
99
100 return response;
101 }
102}
103
104// Custom routing handler that directly matches routes
105async function handler(req: Request): Promise<Response> {
106 const url = new URL(req.url);
107
108 // Only log non-asset requests to reduce noise
109 if (
110 !url.pathname.startsWith("/src/") &&
111 !url.pathname.startsWith("/@") &&
112 !url.pathname.includes(".js") &&
113 !url.pathname.includes(".css")
114 ) {
115 console.log(`[${req.method}] ${url.pathname}`);
116 }
117
118 // Try to match against our defined routes first
119 for (const routeDef of allRoutes) {
120 const match = routeDef.pattern.exec(url);
121 if (match && req.method === routeDef.method) {
122 console.log(`✓ Matched API route: ${routeDef.method} ${url.pathname}`);
123 return await routeDef.handler(req);
124 }
125 }
126
127 // Fall back to default handler (proxy to Vite or serve static)
128 return await defaultHandler(req);
129}
130
131Deno.serve(
132 {
133 port: PORT,
134 hostname: "0.0.0.0",
135 onListen: ({ port, hostname }) => {
136 console.log(`Frontend-v2 server running on http://${hostname}:${port}`);
137 if (isDevelopment) {
138 console.log(`Proxying to Vite dev server at ${VITE_DEV_SERVER}`);
139 }
140 },
141 },
142 handler
143);