MCPcopy Create free account
hub / github.com/hashintel/hash / fetch

Function fetch

apps/petrinaut-website/api/chat.ts:128–227  ·  view source on GitHub ↗
(request: Request)

Source from the content-addressed store, hash-verified

126 * See https://vercel.com/changelog/node-js-vercel-functions-now-support-fetch-web-handlers
127 */
128const fetch = async (request: Request): Promise<Response> => {
129 if (request.method === "OPTIONS") {
130 // We'll always serve this same-origin so we don't need any CORS config
131 return new Response(null, { status: 204 });
132 }
133
134 if (request.method !== "POST") {
135 logChatFailure("Rejected unsupported method", { method: request.method });
136 return jsonResponse({ error: "Method not allowed" }, { status: 405 });
137 }
138
139 const clientIp = resolveClientIp(request);
140 if (process.env.VERCEL_ENV === "production" && !clientIp) {
141 // Vercel's edge always sets x-forwarded-for in production. If it isn't
142 // present, the request reached us through an unexpected path and we have
143 // no way to rate-limit it - reject conservatively rather than fail open.
144 logChatFailure("Rejected production request with no resolvable client IP");
145 return jsonResponse(
146 { error: "Could not determine client IP" },
147 { status: 400 },
148 );
149 }
150
151 if (clientIp && !checkRateLimit(clientIp)) {
152 logChatFailure("Rejected rate-limited request", { clientIp });
153 return jsonResponse({ error: "Rate limit exceeded" }, { status: 429 });
154 }
155
156 const apiKey = process.env.OPENAI_API_KEY;
157 if (!apiKey) {
158 logChatFailure("Missing OpenAI API key");
159 return jsonResponse(
160 { error: "OPENAI_API_KEY is not configured" },
161 { status: 500 },
162 );
163 }
164
165 let body: unknown;
166 try {
167 body = await request.json();
168 } catch (error) {
169 logChatFailure("Rejected invalid JSON", { error });
170 return jsonResponse({ error: "Invalid JSON" }, { status: 400 });
171 }
172
173 const parsed = requestSchema.safeParse(body);
174 if (!parsed.success) {
175 logChatFailure("Rejected invalid chat request", { error: parsed.error });
176 return jsonResponse({ error: "Invalid chat request" }, { status: 400 });
177 }
178
179 const validatedMessages = await safeValidateUIMessages<UIMessage>({
180 messages: parsed.data.messages,
181 tools: petrinautAiValidationTools,
182 });
183
184 if (!validatedMessages.success) {
185 logChatFailure("Rejected invalid chat messages", {

Callers 15

oAuthLinearCallbackFunction · 0.85
getEmbedResponseFunction · 0.85
block-framer.tsxFile · 0.85
defaultFetchFnFunction · 0.85
callExternalApiMethodFunction · 0.85
fetchEmbedCodeFunction · 0.85
makeGraphQlRequestFunction · 0.85
PdfPreviewFunction · 0.85
GoogleAuthProviderFunction · 0.85
loadOAuthClientFunction · 0.85

Calls 6

resolveClientIpFunction · 0.85
jsonMethod · 0.80
logChatFailureFunction · 0.70
jsonResponseFunction · 0.70
checkRateLimitFunction · 0.70
validationErrorBodyFunction · 0.70

Tested by

no test coverage detected