77import { OpenAPIHono } from '@hono/zod-openapi'
88import type { MiddlewareHandler } from 'hono'
99import { 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'
1112import { GitHubWorkerRPC } from './rpc'
1213import { convertOpenAPIToYAML , buildCompleteOpenAPIDocument } from './utils/openapi'
1314import { 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
9698const 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
121124app . use ( '/api/*' , requireApiKey )
122125app . use ( '/mcp/*' , requireApiKey )
123126app . 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)
139141const fullSpecApp = new OpenAPIHono < { Bindings : Bindings } > ( )
140142fullSpecApp . route ( '/octokit' , octokitApi )
141143fullSpecApp . route ( '/tools' , toolsApi )
142144fullSpecApp . route ( '/agents' , agentsApi )
143145fullSpecApp . route ( '/retrofit' , retrofitApi )
144146fullSpecApp . 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)
148149const gptSpecApp = new OpenAPIHono < { Bindings : Bindings } > ( )
149150gptSpecApp . route ( '/octokit' , octokitApi ) // 3 methods
150151gptSpecApp . route ( '/agents' , agentsApi ) // 2 methods
@@ -272,17 +273,6 @@ app.post('/mcp-execute', async (c) => {
272273 const startTime = Date . now ( )
273274
274275 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-
286276 const body = await c . req . json ( )
287277
288278 // Validate JSON structure
@@ -352,7 +342,7 @@ app.post('/mcp-execute', async (c) => {
352342 }
353343 const result = await response . json ( ) ;
354344
355- const durationMs = Date . now ( ) - startTime
345+ const durationMs = Date . Now ( ) - startTime
356346
357347 return c . json ( {
358348 success : true ,
@@ -550,31 +540,39 @@ export default {
550540 */
551541 async fetch ( request : Request , env : Env , ctx : ExecutionContext ) : Promise < Response > {
552542
553- // This is the correct "SPA Mode" pattern
543+ // --- THIS IS THE CORRECT FETCH HANDLER ---
544+ // It correctly routes API calls to Hono and all other calls to ASSETS.
545+
554546 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- }
569547
570- try {
571- // 1. First, try to fetch the request as a static asset.
572- // This will serve public/landing.html at /landing.html
573- return await env . ASSETS . fetch ( request ) ;
574- } catch ( e ) {
575- // 2. If it's not a static asset (e.g., 404), fall back to the Hono API app.
576- // The Hono app handles /api, /mcp, /a2a, /openapi.json, etc.
548+ // List of all your API/dynamic prefixes.
549+ // Any request *not* matching these will be treated as a static asset request.
550+ const apiPrefixes = [
551+ '/api/' ,
552+ '/mcp/' ,
553+ '/a2a/' ,
554+ '/openapi.json' ,
555+ '/openapi.yaml' ,
556+ '/gpt/openapi.json' ,
557+ '/gpt/openapi.yaml' ,
558+ '/doc' , // The Swagger UI
559+ '/healthz' ,
560+ '/webhook' ,
561+ '/mcp-tools' ,
562+ '/ws' // WebSocket endpoint
563+ ] ;
564+
565+ const isApiRoute = apiPrefixes . some ( prefix => url . pathname . startsWith ( prefix ) ) ;
566+
567+ if ( isApiRoute ) {
568+ // It's an API route. Let the Hono app handle it.
577569 return app . fetch ( request , env , ctx ) ;
570+ } else {
571+ // It's not an API route.
572+ // Assume it's a static asset and let env.ASSETS handle it.
573+ // env.ASSETS will automatically serve /index.html for /
574+ // and a 404 for any other file it can't find.
575+ return env . ASSETS . fetch ( request ) ;
578576 }
579577 } ,
580578
@@ -596,32 +594,37 @@ export default {
596594 const searchResults = await searchRepositoriesWithRetry ( searchTerm , env , ctx )
597595
598596 // 2. Analyze each repository
599- for ( const repo of searchResults . items ) {
600- // 2a. Check if the repository has already been analyzed for this session
601- const { results } = await env . DB . prepare (
602- 'SELECT id FROM repo_analysis WHERE session_id = ? AND repo_full_name = ?'
603- ) . bind ( sessionId , repo . full_name ) . all ( )
604-
605- if ( results . length > 0 ) {
606- continue
597+ if ( searchResults && searchResults . items ) {
598+ for ( const repo of searchResults . items ) {
599+ // 2a. Check if the repository has already been analyzed for this session
600+ const { results } = await env . DB . prepare (
601+ 'SELECT id FROM repo_analysis WHERE session_id = ? AND repo_full_name = ?'
602+ ) . bind ( sessionId , repo . full_name ) . all ( )
603+
604+ if ( results . length > 0 ) {
605+ continue
606+ }
607+
608+ // 2b. Analyze the repository
609+ const analysis = await analyzeRepository ( repo , searchTerm , aiBinding )
610+
611+ // 2c. Persist the analysis to D1
612+ await env . DB . prepare (
613+ 'INSERT INTO repo_analysis (session_id, search_id, repo_full_name, repo_url, description, relevancy_score) VALUES (?, ?, ?, ?, ?, ?)'
614+ ) . bind (
615+ sessionId ,
616+ searchId ,
617+ repo . full_name ,
618+ repo . html_url ,
619+ repo . description ,
620+ analysis . relevancyScore
621+ ) . run ( )
607622 }
608-
609- // 2b. Analyze the repository
610- const analysis = await analyzeRepository ( repo , searchTerm , aiBinding )
611-
612- // 2c. Persist the analysis to D1
613- await env . DB . prepare (
614- 'INSERT INTO repo_analysis (session_id, search_id, repo_full_name, repo_url, description, relevancy_score) VALUES (?, ?, ?, ?, ?, ?)'
615- ) . bind (
616- sessionId ,
617- searchId ,
618- repo . full_name ,
619- repo . html_url ,
620- repo . description ,
621- analysis . relevancyScore
622- ) . run ( )
623+ } else {
624+ console . warn ( `No search results for term: ${ searchTerm } ` ) ;
623625 }
624626
627+
625628 // 3. Update the search status
626629 await env . DB . prepare (
627630 'UPDATE searches SET status = ? WHERE id = ?'
@@ -644,28 +647,11 @@ export default {
644647 *
645648 * This class is a NAMED export. Other workers must use this name as the 'entrypoint'
646649 * in their service binding configuration to call these RPC methods.
647- *
648- * Example consumer wrangler.jsonc:
649- * {
650- * "services": [
651- * {
652- * "binding": "GITHUB_WORKER",
653- * "service": "core-github-api",
654- * "entrypoint": "GitHubWorker" // <-- This is the new required key
655- * }
656- * ]
657- * }
658650 */
659651export class GitHubWorker {
660652 private rpc : GitHubWorkerRPC | null = null
661653 private env : Env | null = null
662654
663- // NOTE: 'fetch' and 'queue' handlers are removed from this class
664- // and are now on the 'export default' object.
665-
666- // ==================== RPC Methods ====================
667- // These methods can be called directly when this worker is used as a service binding
668-
669655 private getRPC ( env : Env ) : GitHubWorkerRPC {
670656 if ( ! this . rpc || this . env !== env ) {
671657 this . env = env
0 commit comments