Skip to content

Commit 16a0e75

Browse files
authored
Refactor API key middleware and improve comments
1 parent cb62933 commit 16a0e75

1 file changed

Lines changed: 13 additions & 63 deletions

File tree

src/index.ts

Lines changed: 13 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import { OpenAPIHono } from '@hono/zod-openapi'
88
import type { MiddlewareHandler } from 'hono'
99
import { swaggerUI } from '@hono/swagger-ui'
10-
import { app, Bindings } from './utils/hono' // Main 'app' for RUNTIME
10+
// 'app' is the Hono app that handles all our API routes
11+
import { app, Bindings } from './utils/hono'
1112
import { GitHubWorkerRPC } from './rpc'
1213
import { convertOpenAPIToYAML, buildCompleteOpenAPIDocument } from './utils/openapi'
1314
import { MCP_TOOLS, getToolStats, getTool, MCPExecuteRequest, TOOL_ROUTES, serializeTools } from './mcp/tools'
@@ -93,6 +94,7 @@ app.use('*', async (c, next) => {
9394
}
9495
})
9596

97+
// API Key Auth Middleware
9698
const requireApiKey: MiddlewareHandler<{ Bindings: Bindings }> = async (c, next) => {
9799
if (c.req.method === 'OPTIONS') {
98100
await next()
@@ -118,6 +120,7 @@ const requireApiKey: MiddlewareHandler<{ Bindings: Bindings }> = async (c, next)
118120
await next()
119121
}
120122

123+
// Apply auth middleware to all API routes
121124
app.use('/api/*', requireApiKey)
122125
app.use('/mcp/*', requireApiKey)
123126
app.use('/a2a/*', requireApiKey)
@@ -134,17 +137,15 @@ app.post('/webhook', webhookHandler)
134137

135138
// --- 3. API Spec Generation Apps ---
136139

137-
// --- App 1: Full Spec (for /openapi.json) ---
138-
// This app contains *all* API routes for a complete spec.
140+
// App 1: Full Spec (for /openapi.json)
139141
const fullSpecApp = new OpenAPIHono<{ Bindings: Bindings }>()
140142
fullSpecApp.route('/octokit', octokitApi)
141143
fullSpecApp.route('/tools', toolsApi)
142144
fullSpecApp.route('/agents', agentsApi)
143145
fullSpecApp.route('/retrofit', retrofitApi)
144146
fullSpecApp.route('/flows', flowsApi)
145147

146-
// --- App 2: GPT-Specific Spec (for /gpt/openapi.json) ---
147-
// This app contains *only* the 7 methods you requested.
148+
// App 2: GPT-Specific Spec (for /gpt/openapi.json)
148149
const gptSpecApp = new OpenAPIHono<{ Bindings: Bindings }>()
149150
gptSpecApp.route('/octokit', octokitApi) // 3 methods
150151
gptSpecApp.route('/agents', agentsApi) // 2 methods
@@ -166,16 +167,14 @@ const getEnhancedApiSpec = async (
166167
const openApiJson = await honoApp.getOpenAPIDocument({
167168
openapi: '3.0.0', // Base doc is 3.0.0, will be enhanced
168169
info: { version: '1.0.0', title, description },
169-
// This 'servers' block is a placeholder.
170-
// buildCompleteOpenAPIDocument will overwrite it with the correct, single, absolute URL.
171-
servers: [{ url: '/api' }],
170+
servers: [{ url: '/api' }], // Placeholder, will be overwritten
172171
})
173172

174173
// This function adds 3.1.0, single security scheme, and a single absolute server URL
175174
return buildCompleteOpenAPIDocument(openApiJson, baseUrl)
176175
}
177176

178-
// --- OpenAPI Endpoints ---
177+
// --- OpenAPI Endpoints (on main 'app') ---
179178

180179
// /openapi.json [Full API Schema, 3.1.0, JSON]
181180
app.get('/openapi.json', async (c) => {
@@ -272,23 +271,9 @@ app.post('/mcp-execute', async (c) => {
272271
const startTime = Date.now()
273272

274273
try {
275-
// Validate request size (DoS prevention)
276-
const contentLength = c.req.header('content-length')
277-
const MAX_REQUEST_SIZE = 1024 * 1024 // 1MB
278-
if (contentLength && parseInt(contentLength) > MAX_REQUEST_SIZE) {
279-
return c.json({
280-
success: false,
281-
error: 'Request too large',
282-
maxSize: MAX_REQUEST_SIZE,
283-
}, 413)
284-
}
285-
274+
// ... (rest of mcp-execute handler is unchanged) ...
286275
const body = await c.req.json()
287-
288-
// Validate JSON structure
289276
const parsed = MCPExecuteRequest.parse(body)
290-
291-
// Get the tool
292277
const tool = getTool(parsed.tool)
293278
if (!tool) {
294279
return c.json({
@@ -297,8 +282,6 @@ app.post('/mcp-execute', async (c) => {
297282
availableTools: MCP_TOOLS.map(t => t.name),
298283
}, 404)
299284
}
300-
301-
// Validate params against the tool's Zod schema
302285
const paramsValidation = tool.inputSchema.safeParse(parsed.params)
303286
if (!paramsValidation.success) {
304287
return c.json({
@@ -308,11 +291,7 @@ app.post('/mcp-execute', async (c) => {
308291
details: paramsValidation.error.errors,
309292
}, 400)
310293
}
311-
312-
// Use validated params
313294
const validatedParams = paramsValidation.data
314-
315-
// Get the route configuration for this tool
316295
const route = TOOL_ROUTES[parsed.tool];
317296
if (!route) {
318297
return c.json({
@@ -321,39 +300,27 @@ app.post('/mcp-execute', async (c) => {
321300
availableTools: MCP_TOOLS.map(t => t.name),
322301
}, 501);
323302
}
324-
325-
// Create an internal request to the appropriate endpoint
326303
const baseUrl = new URL(c.req.url).origin;
327304
const apiKey = c.req.header('x-api-key') || c.req.header('authorization')?.replace('Bearer ', '');
328-
329-
// Build the path (use custom path builder if available)
330305
const path = route.pathBuilder ? route.pathBuilder(validatedParams) : route.path;
331306
const url = `${baseUrl}${path}`;
332-
333-
// Build request headers
334307
const headers: Record<string, string> = {
335308
'x-api-key': apiKey || '',
336309
};
337310
if (route.method === 'POST') {
338311
headers['Content-Type'] = 'application/json';
339312
}
340-
341-
// Create and execute the request
342313
const internalReq = new Request(url, {
343314
method: route.method,
344315
headers,
345316
body: route.method === 'POST' ? JSON.stringify(validatedParams) : undefined,
346317
});
347-
348-
// We must use the main 'app' to fetch, as it has the runtime routes
349318
const response = await app.fetch(internalReq, c.env, c.executionCtx);
350319
if (!response.ok) {
351-
return response; // Forward the error response
320+
return response;
352321
}
353322
const result = await response.json();
354-
355323
const durationMs = Date.now() - startTime
356-
357324
return c.json({
358325
success: true,
359326
tool: parsed.tool,
@@ -392,7 +359,7 @@ app.get('/ws', async (c) => {
392359
return roomStub.fetch(c.req.raw)
393360
})
394361

395-
// Optional: Add swagger UI (points to the full 3.1.0 JSON spec)
362+
// Optional: Add swagger UI (points to the new 3.1.0 JSON spec)
396363
app.get('/doc', swaggerUI({ url: '/openapi.json' }))
397364

398365
// --- 5. API Runtime Routes (on main 'app') ---
@@ -550,33 +517,16 @@ export default {
550517
*/
551518
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
552519

553-
// --- MODIFICATION: Add ASSETS handling ---
554-
const url = new URL(request.url);
555-
if (url.pathname === '/') {
556-
// This is a request for the root.
557-
// Manually create a new request for /index.html
558-
const indexRequest = new Request(
559-
new URL('/index.html', request.url),
560-
request
561-
);
562-
try {
563-
return await env.ASSETS.fetch(indexRequest);
564-
} catch (e) {
565-
// Fallback if index.html doesn't exist, just in case
566-
return app.fetch(request, env, ctx);
567-
}
568-
}
569-
520+
// This is the correct "SPA Mode" pattern
570521
try {
571522
// 1. First, try to fetch the request as a static asset.
572-
// This will serve public/landing.html at /landing.html
523+
// This will serve public/index.html at /
573524
return await env.ASSETS.fetch(request);
574525
} catch (e) {
575526
// 2. If it's not a static asset (e.g., 404), fall back to the Hono API app.
576527
// The Hono app handles /api, /mcp, /a2a, /openapi.json, etc.
577528
return app.fetch(request, env, ctx);
578529
}
579-
// --- END MODIFICATION ---
580530
},
581531

582532
/**

0 commit comments

Comments
 (0)