Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions react-router.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import type { Config } from "@react-router/dev/config"
export default {
ssr: true,
future: {
unstable_viteEnvironmentApi: true,
v8_viteEnvironmentApi: true,
unstable_optimizeDeps: true,
unstable_splitRouteModules: true,
v8_splitRouteModules: true,
},
} satisfies Config
110 changes: 108 additions & 2 deletions workers/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const app = new Hono<AppType>()
function createSuperMemory(userId: string, env: Env) {

const supermemory = new Supermemory({
apiKey: env.SUPERMEMORY_API_KEY,
apiKey: (env as any).SUPERMEMORY_API_KEY,
})

app.post(
Expand Down Expand Up @@ -234,6 +234,97 @@ export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
const url = new URL(request.url)

if (request.method === "OPTIONS") {
return new Response(null, {
status: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Max-Age": "86400",
},
})
}

if (url.pathname === "/oauth/register" && request.method === "POST") {
try {
const body = await request.json() as any
const clientId = `sm_${Math.random().toString(36).substring(2, 15)}`
const clientSecret = `sms_${Math.random().toString(36).substring(2, 25)}`

const responseData = {
client_id: clientId,
client_secret: clientSecret,
client_name: body.client_name || "ChatGPT",
redirect_uris: body.redirect_uris || [],
scope: body.scope || "read write",
grant_types: ["authorization_code"],
response_types: ["code"],
token_endpoint_auth_method: "client_secret_basic",
client_id_issued_at: Math.floor(Date.now() / 1000),
client_secret_expires_at: 0,
}

return new Response(JSON.stringify(responseData), {
status: 201,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
})
} catch (error) {
return new Response(JSON.stringify({ error: "invalid_request" }), {
status: 400,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
})
}
}

// Handle the original failing MCP endpoint
if (url.pathname === "/mcp" && request.method === "POST") {
try {
const body = await request.json() as any

// Check if this is an OAuth registration request
if (body.client_name || body.redirect_uris) {

This comment was marked as outdated.

const clientId = `sm_${Math.random().toString(36).substring(2, 15)}`
const clientSecret = `sms_${Math.random().toString(36).substring(2, 25)}`

const responseData = {
client_id: clientId,
client_secret: clientSecret,
client_name: body.client_name || "ChatGPT",
redirect_uris: body.redirect_uris || [],
scope: body.scope || "read write",
grant_types: ["authorization_code"],
response_types: ["code"],
token_endpoint_auth_method: "client_secret_basic",
client_id_issued_at: Math.floor(Date.now() / 1000),
client_secret_expires_at: 0,
}

return new Response(JSON.stringify(responseData), {
status: 201,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
})
}
} catch (error) {
return new Response(JSON.stringify({ error: "invalid_request" }), {
status: 400,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
})
}
}

if (
url.pathname.includes("sse") ||
url.pathname.endsWith("/messages")
Expand All @@ -254,8 +345,23 @@ export default {
return stub.fetch(request)
}

return requestHandler(request, {
const response = await requestHandler(request, {
cloudflare: { env, ctx },
})

const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
}

return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: {
...Object.fromEntries(response.headers.entries()),
...corsHeaders,
},
})
},
}