77import { OpenAPIHono } from '@hono/zod-openapi'
88import type { MiddlewareHandler } from 'hono'
99import { swaggerUI } from '@hono/swagger-ui'
10- // 'app' is the Hono app that handles all our API routes
11- import { app , Bindings } from './utils/hono'
10+ import { app , Bindings } from './utils/hono' // Main 'app' for RUNTIME
1211import { GitHubWorkerRPC } from './rpc'
1312import { convertOpenAPIToYAML , buildCompleteOpenAPIDocument } from './utils/openapi'
1413import { MCP_TOOLS , getToolStats , getTool , MCPExecuteRequest , TOOL_ROUTES , serializeTools } from './mcp/tools'
@@ -94,7 +93,6 @@ app.use('*', async (c, next) => {
9493 }
9594} )
9695
97- // API Key Auth Middleware
9896const requireApiKey : MiddlewareHandler < { Bindings : Bindings } > = async ( c , next ) => {
9997 if ( c . req . method === 'OPTIONS' ) {
10098 await next ( )
@@ -120,7 +118,6 @@ const requireApiKey: MiddlewareHandler<{ Bindings: Bindings }> = async (c, next)
120118 await next ( )
121119}
122120
123- // Apply auth middleware to all API routes
124121app . use ( '/api/*' , requireApiKey )
125122app . use ( '/mcp/*' , requireApiKey )
126123app . use ( '/a2a/*' , requireApiKey )
@@ -137,15 +134,17 @@ app.post('/webhook', webhookHandler)
137134
138135// --- 3. API Spec Generation Apps ---
139136
140- // App 1: Full Spec (for /openapi.json)
137+ // --- App 1: Full Spec (for /openapi.json) ---
138+ // This app contains *all* API routes for a complete spec.
141139const fullSpecApp = new OpenAPIHono < { Bindings : Bindings } > ( )
142140fullSpecApp . route ( '/octokit' , octokitApi )
143141fullSpecApp . route ( '/tools' , toolsApi )
144142fullSpecApp . route ( '/agents' , agentsApi )
145143fullSpecApp . route ( '/retrofit' , retrofitApi )
146144fullSpecApp . route ( '/flows' , flowsApi )
147145
148- // App 2: GPT-Specific Spec (for /gpt/openapi.json)
146+ // --- App 2: GPT-Specific Spec (for /gpt/openapi.json) ---
147+ // This app contains *only* the 7 methods you requested.
149148const gptSpecApp = new OpenAPIHono < { Bindings : Bindings } > ( )
150149gptSpecApp . route ( '/octokit' , octokitApi ) // 3 methods
151150gptSpecApp . route ( '/agents' , agentsApi ) // 2 methods
@@ -167,7 +166,9 @@ const getEnhancedApiSpec = async (
167166 const openApiJson = await honoApp . getOpenAPIDocument ( {
168167 openapi : '3.0.0' , // Base doc is 3.0.0, will be enhanced
169168 info : { version : '1.0.0' , title, description } ,
170- servers : [ { url : '/api' } ] , // Placeholder, will be overwritten
169+ // This 'servers' block is a placeholder.
170+ // buildCompleteOpenAPIDocument will overwrite it with the correct, single, absolute URL.
171+ servers : [ { url : '/api' } ] ,
171172 } )
172173
173174 // This function adds 3.1.0, single security scheme, and a single absolute server URL
@@ -271,9 +272,23 @@ app.post('/mcp-execute', async (c) => {
271272 const startTime = Date . now ( )
272273
273274 try {
274- // ... (rest of mcp-execute handler is unchanged) ...
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+
275286 const body = await c . req . json ( )
287+
288+ // Validate JSON structure
276289 const parsed = MCPExecuteRequest . parse ( body )
290+
291+ // Get the tool
277292 const tool = getTool ( parsed . tool )
278293 if ( ! tool ) {
279294 return c . json ( {
@@ -282,6 +297,8 @@ app.post('/mcp-execute', async (c) => {
282297 availableTools : MCP_TOOLS . map ( t => t . name ) ,
283298 } , 404 )
284299 }
300+
301+ // Validate params against the tool's Zod schema
285302 const paramsValidation = tool . inputSchema . safeParse ( parsed . params )
286303 if ( ! paramsValidation . success ) {
287304 return c . json ( {
@@ -291,7 +308,11 @@ app.post('/mcp-execute', async (c) => {
291308 details : paramsValidation . error . errors ,
292309 } , 400 )
293310 }
311+
312+ // Use validated params
294313 const validatedParams = paramsValidation . data
314+
315+ // Get the route configuration for this tool
295316 const route = TOOL_ROUTES [ parsed . tool ] ;
296317 if ( ! route ) {
297318 return c . json ( {
@@ -300,27 +321,39 @@ app.post('/mcp-execute', async (c) => {
300321 availableTools : MCP_TOOLS . map ( t => t . name ) ,
301322 } , 501 ) ;
302323 }
324+
325+ // Create an internal request to the appropriate endpoint
303326 const baseUrl = new URL ( c . req . url ) . origin ;
304327 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)
305330 const path = route . pathBuilder ? route . pathBuilder ( validatedParams ) : route . path ;
306331 const url = `${ baseUrl } ${ path } ` ;
332+
333+ // Build request headers
307334 const headers : Record < string , string > = {
308335 'x-api-key' : apiKey || '' ,
309336 } ;
310337 if ( route . method === 'POST' ) {
311338 headers [ 'Content-Type' ] = 'application/json' ;
312339 }
340+
341+ // Create and execute the request
313342 const internalReq = new Request ( url , {
314343 method : route . method ,
315344 headers,
316345 body : route . method === 'POST' ? JSON . stringify ( validatedParams ) : undefined ,
317346 } ) ;
347+
348+ // We must use the main 'app' to fetch, as it has the runtime routes
318349 const response = await app . fetch ( internalReq , c . env , c . executionCtx ) ;
319350 if ( ! response . ok ) {
320- return response ;
351+ return response ; // Forward the error response
321352 }
322353 const result = await response . json ( ) ;
354+
323355 const durationMs = Date . now ( ) - startTime
356+
324357 return c . json ( {
325358 success : true ,
326359 tool : parsed . tool ,
@@ -518,9 +551,25 @@ export default {
518551 async fetch ( request : Request , env : Env , ctx : ExecutionContext ) : Promise < Response > {
519552
520553 // This is the correct "SPA Mode" pattern
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+
521570 try {
522571 // 1. First, try to fetch the request as a static asset.
523- // This will serve public/index .html at /
572+ // This will serve public/landing .html at /landing.html
524573 return await env . ASSETS . fetch ( request ) ;
525574 } catch ( e ) {
526575 // 2. If it's not a static asset (e.g., 404), fall back to the Hono API app.
0 commit comments