Skip to content

Commit 09647a4

Browse files
committed
fix(chat): add GET and OPTIONS endpoints, safely type env secrets, expose /chat alias
1 parent 9c6e824 commit 09647a4

4 files changed

Lines changed: 88 additions & 22 deletions

File tree

‎apps/site/src/env.d.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ declare namespace App {
3030
}
3131
}
3232

33+
declare namespace Cloudflare {
34+
interface Env {
35+
SANITY_API_READ_TOKEN?: string;
36+
}
37+
}
38+
3339
declare namespace astroHTML.JSX {
3440
interface FormHTMLAttributes {
3541
toolname?: string;

‎apps/site/src/pages/api/chat.ts‎

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,40 @@ export const prerender = false;
99
const SANITY_CONTEXT_MCP_URL =
1010
"https://api.sanity.io/v1/context/organizations/ovF2qiKSO/mcp/agent-aj-mcp";
1111

12+
export const OPTIONS: APIRoute = async () => {
13+
return new Response(null, {
14+
status: 204,
15+
headers: {
16+
"access-control-allow-origin": "*",
17+
"access-control-allow-methods": "GET, POST, OPTIONS",
18+
"access-control-allow-headers": "Content-Type, Authorization",
19+
},
20+
});
21+
};
22+
23+
export const GET: APIRoute = async () => {
24+
return new Response(
25+
JSON.stringify({
26+
status: "ready",
27+
name: "CodingCat AI Assistant",
28+
model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
29+
mcp: SANITY_CONTEXT_MCP_URL,
30+
}),
31+
{
32+
status: 200,
33+
headers: {
34+
"content-type": "application/json; charset=utf-8",
35+
"access-control-allow-origin": "*",
36+
},
37+
},
38+
);
39+
};
40+
1241
export const POST: APIRoute = async ({ request }) => {
13-
const cfEnv = env as unknown as Cloudflare.Env | undefined;
42+
const cfEnv = env as unknown as Record<string, unknown> | undefined;
1443
const sanityToken =
15-
cfEnv?.SANITY_API_READ_TOKEN || process.env.SANITY_API_READ_TOKEN;
44+
(cfEnv?.SANITY_API_READ_TOKEN as string | undefined) ||
45+
process.env.SANITY_API_READ_TOKEN;
1646

1747
if (!sanityToken) {
1848
return new Response(
@@ -21,7 +51,10 @@ export const POST: APIRoute = async ({ request }) => {
2151
}),
2252
{
2353
status: 500,
24-
headers: { "Content-Type": "application/json" },
54+
headers: {
55+
"content-type": "application/json; charset=utf-8",
56+
"access-control-allow-origin": "*",
57+
},
2558
},
2659
);
2760
}
@@ -37,7 +70,10 @@ export const POST: APIRoute = async ({ request }) => {
3770
JSON.stringify({ error: "Invalid JSON request body" }),
3871
{
3972
status: 400,
40-
headers: { "Content-Type": "application/json" },
73+
headers: {
74+
"content-type": "application/json; charset=utf-8",
75+
"access-control-allow-origin": "*",
76+
},
4177
},
4278
);
4379
}
@@ -51,7 +87,10 @@ export const POST: APIRoute = async ({ request }) => {
5187
JSON.stringify({ error: "Please provide a prompt or messages array" }),
5288
{
5389
status: 400,
54-
headers: { "Content-Type": "application/json" },
90+
headers: {
91+
"content-type": "application/json; charset=utf-8",
92+
"access-control-allow-origin": "*",
93+
},
5594
},
5695
);
5796
}
@@ -64,18 +103,20 @@ export const POST: APIRoute = async ({ request }) => {
64103
content: m.content,
65104
}));
66105

67-
// 1. Connect MCP client to Sanity Context MCP endpoint
68-
const mcpClient = await createMCPClient({
69-
transport: {
70-
type: "http",
71-
url: SANITY_CONTEXT_MCP_URL,
72-
headers: {
73-
Authorization: `Bearer ${sanityToken}`,
74-
},
75-
},
76-
});
106+
let mcpClient: Awaited<ReturnType<typeof createMCPClient>> | undefined;
77107

78108
try {
109+
// 1. Connect MCP client to Sanity Context MCP endpoint
110+
mcpClient = await createMCPClient({
111+
transport: {
112+
type: "http",
113+
url: SANITY_CONTEXT_MCP_URL,
114+
headers: {
115+
Authorization: `Bearer ${sanityToken}`,
116+
},
117+
},
118+
});
119+
79120
const tools = await mcpClient.tools();
80121

81122
// 2. Setup Cloudflare Workers AI model
@@ -89,7 +130,10 @@ export const POST: APIRoute = async ({ request }) => {
89130
}),
90131
{
91132
status: 500,
92-
headers: { "Content-Type": "application/json" },
133+
headers: {
134+
"content-type": "application/json; charset=utf-8",
135+
"access-control-allow-origin": "*",
136+
},
93137
},
94138
);
95139
}
@@ -107,17 +151,28 @@ export const POST: APIRoute = async ({ request }) => {
107151
stopWhen: isStepCount(10),
108152
onFinish: async () => {
109153
try {
110-
await mcpClient.close();
154+
if (mcpClient) {
155+
await mcpClient.close();
156+
}
111157
} catch {
112158
// Ignore cleanup errors
113159
}
114160
},
115161
});
116162

117-
return result.toTextStreamResponse();
163+
const textResponse = result.toTextStreamResponse();
164+
const headers = new Headers(textResponse.headers);
165+
headers.set("access-control-allow-origin", "*");
166+
return new Response(textResponse.body, {
167+
status: textResponse.status,
168+
statusText: textResponse.statusText,
169+
headers,
170+
});
118171
} catch (err) {
119172
try {
120-
await mcpClient.close();
173+
if (mcpClient) {
174+
await mcpClient.close();
175+
}
121176
} catch {}
122177

123178
console.error("[Chat API Error]", err);
@@ -130,7 +185,10 @@ export const POST: APIRoute = async ({ request }) => {
130185
}),
131186
{
132187
status: 500,
133-
headers: { "Content-Type": "application/json" },
188+
headers: {
189+
"content-type": "application/json; charset=utf-8",
190+
"access-control-allow-origin": "*",
191+
},
134192
},
135193
);
136194
}

‎apps/site/src/pages/api/mcp.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,10 @@ export const POST: APIRoute = async ({ request }) => {
8989
const rawBody = await request.text();
9090

9191
// Read server-side Sanity Context token from cloudflare:workers env or process.env
92-
const cfEnv = env as unknown as Cloudflare.Env | undefined;
92+
const cfEnv = env as unknown as Record<string, unknown> | undefined;
9393
const sanityToken =
94-
cfEnv?.SANITY_API_READ_TOKEN || process.env.SANITY_API_READ_TOKEN;
94+
(cfEnv?.SANITY_API_READ_TOKEN as string | undefined) ||
95+
process.env.SANITY_API_READ_TOKEN;
9596

9697
if (!sanityToken) {
9798
return new Response(

‎apps/site/src/pages/chat.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { GET, OPTIONS, POST, prerender } from "./api/chat";

0 commit comments

Comments
 (0)