1- import { detect } from "../src/lib/detect .ts" ;
1+ import { apiHandler } from "./api .ts" ;
22
33export { McpDurableObject } from "./mcp-do.ts" ;
44
@@ -22,13 +22,6 @@ const json = (body: unknown, status = 200, headers: Record<string, string> = {})
2222 headers : { "content-type" : "application/json; charset=utf-8" , "access-control-allow-origin" : "*" , ...headers } ,
2323 } ) ;
2424
25- // Normalize "https://Vercel.com/foo" / "vercel.com" -> "vercel.com"; reject non-domains.
26- function cleanDomain ( input : string | null ) : string | null {
27- if ( ! input ) return null ;
28- const d = input . trim ( ) . toLowerCase ( ) . replace ( / ^ h t t p s ? : \/ \/ / , "" ) . replace ( / \/ .* $ / , "" ) . replace ( / : \d + $ / , "" ) ;
29- return / ^ [ a - z 0 - 9 . - ] + \. [ a - z ] { 2 , } $ / . test ( d ) ? d : null ;
30- }
31-
3225export default {
3326 async fetch (
3427 request : Request ,
@@ -37,49 +30,58 @@ export default {
3730 ) : Promise < Response > {
3831 const url = new URL ( request . url ) ;
3932
40- // MCP server (write-once tool registry) — point Claude/Cursor at /mcp.
41- // Routed through a single Durable Object so the session map persists.
33+ // MCP server — point Claude/Cursor at /mcp. Routed through a single Durable
34+ // Object so the session map persists across stateless Worker requests .
4235 if ( url . pathname === "/mcp" ) {
43- const stub = env . MCP . get ( env . MCP . idFromName ( "mcp" ) ) ;
44- return stub . fetch ( request ) ;
36+ return env . MCP . get ( env . MCP . idFromName ( "mcp" ) ) . fetch ( request ) ;
37+ }
38+
39+ // Self-describe via the same discovery format the catalog indexes: point at
40+ // our own OpenAPI + MCP endpoint.
41+ if ( url . pathname === "/.well-known/api-catalog" ) {
42+ return json (
43+ {
44+ linkset : [ {
45+ anchor : "https://integrations.sh" ,
46+ "service-desc" : [ { href : "https://integrations.sh/openapi.json" , type : "application/openapi+json" } ] ,
47+ "service-doc" : [ { href : "https://integrations.sh" } ] ,
48+ item : [ { href : "https://integrations.sh/mcp" , type : "application/json" } ] ,
49+ } ] ,
50+ } ,
51+ 200 ,
52+ { "cache-control" : "public, max-age=86400" } ,
53+ ) ;
4554 }
4655
47- // Detection endpoint: run the full agent-readiness battery for a domain.
48- // GET /api/<domain>/detect -> structured DetectionResult (cached 1h).
49- const detectMatch = url . pathname . match ( / ^ \/ a p i \/ ( [ ^ / ] + ) \/ d e t e c t \/ ? $ / ) ;
50- if ( detectMatch ) {
51- const domain = cleanDomain ( decodeURIComponent ( detectMatch [ 1 ] ) ) ;
52- if ( ! domain ) return json ( { error : "invalid domain — GET /api/<domain>/detect" } , 400 ) ;
53- const cacheKey = new Request ( `https://integrations.sh/api/${ domain } /detect` ) ;
56+ // The API + its OpenAPI doc — single source of truth (worker/api.ts).
57+ if ( url . pathname === "/openapi.json" || url . pathname . startsWith ( "/api/" ) ) {
5458 const cache = ( caches as unknown as { default : Cache } ) . default ;
55- const cached = await cache . match ( cacheKey ) ;
59+ const cached = await cache . match ( request ) ;
5660 if ( cached ) return cached ;
57- const result = await detect ( domain ) ;
58- const res = json ( result , 200 , { "cache-control" : "public, max-age=3600" } ) ;
59- ctx . waitUntil ( cache . put ( cacheKey , res . clone ( ) ) ) ;
61+ const res = await apiHandler ( request ) ;
62+ if ( request . method === "GET" && res . status === 200 ) {
63+ const out = new Response ( res . clone ( ) . body , res ) ;
64+ out . headers . set ( "cache-control" , "public, max-age=3600" ) ;
65+ ctx . waitUntil ( cache . put ( request , out . clone ( ) ) ) ;
66+ return out ;
67+ }
6068 return res ;
6169 }
6270
71+ // Analytics: count executor-agent hits.
6372 const ip = request . headers . get ( "cf-connecting-ip" ) || "unknown" ;
6473 const country = request . headers . get ( "cf-ipcountry" ) || "unknown" ;
6574 const agent = request . headers . get ( "user-agent" ) || "unknown" ;
6675 if ( agent . includes ( "executor" ) ) {
6776 ctx . waitUntil (
6877 fetch ( "https://us.i.posthog.com/i/v0/e/" , {
6978 method : "POST" ,
70- headers : {
71- "Content-Type" : "application/json" ,
72- } ,
79+ headers : { "Content-Type" : "application/json" } ,
7380 body : JSON . stringify ( {
7481 api_key : env . POSTHOG_KEY ,
7582 event : "hit" ,
7683 distinct_id : ip ,
77- properties : {
78- $process_person_profile : false ,
79- user_agent : agent ,
80- country,
81- path : url . pathname ,
82- } ,
84+ properties : { $process_person_profile : false , user_agent : agent , country, path : url . pathname } ,
8385 } ) ,
8486 } ) ,
8587 ) ;
0 commit comments