test.ts128 lines · main
1import { IS_PLATFORM } from 'common'
2import { NextApiRequest, NextApiResponse } from 'next'
3
4import { isValidEdgeFunctionURL } from '@/lib/api/edgeFunctions'
5
6export default async function handler(req: NextApiRequest, res: NextApiResponse) {
7 const { method } = req
8
9 switch (method) {
10 case 'POST':
11 return handlePost(req, res)
12 default:
13 return new Response(
14 JSON.stringify({ data: null, error: { message: `Method ${method} Not Allowed` } }),
15 {
16 status: 405,
17 headers: { 'Content-Type': 'application/json', Allow: 'POST' },
18 }
19 )
20 }
21}
22
23async function handlePost(req: NextApiRequest, res: NextApiResponse) {
24 try {
25 const { url: requestUrl, method, body: requestBody, headers: customHeaders } = req.body
26 const url = IS_PLATFORM
27 ? requestUrl
28 : requestUrl.replace(process.env.BRIVEN_PUBLIC_URL, process.env.BRIVEN_URL)
29
30 const validEdgeFnUrl = isValidEdgeFunctionURL(url, IS_PLATFORM)
31
32 if (!validEdgeFnUrl) {
33 return res.status(400).json({
34 status: 400,
35 error: { message: 'Provided URL is not a valid Briven edge function URL' },
36 })
37 }
38
39 // Remove any undefined or null values from custom headers
40 const sanitizedCustomHeaders = Object.entries(customHeaders || {}).reduce(
41 (acc, [key, value]) => {
42 if (value !== undefined && value !== null && value !== '') {
43 acc[key] = value as string
44 }
45 return acc
46 },
47 {} as Record<string, string>
48 )
49
50 // Only use custom headers and ensure Content-Type is set
51 const requestHeaders: Record<string, string> = {
52 'Content-Type': 'application/json',
53 ...sanitizedCustomHeaders,
54 }
55
56 // Use the test authorization header if provided
57 if (sanitizedCustomHeaders['x-test-authorization']) {
58 requestHeaders['Authorization'] = sanitizedCustomHeaders['x-test-authorization']
59 // Remove the x-test-authorization header as we've moved it to Authorization
60 delete requestHeaders['x-test-authorization']
61 }
62
63 // Prepare the request body based on method and Content-Type
64 let finalBody = undefined
65 if (method !== 'GET' && method !== 'HEAD') {
66 if (requestHeaders['Content-Type'] === 'application/json') {
67 finalBody = typeof requestBody === 'string' ? requestBody : JSON.stringify(requestBody)
68 } else {
69 finalBody = requestBody
70 }
71 }
72
73 const response = await fetch(url, {
74 method,
75 headers: requestHeaders,
76 body: finalBody,
77 redirect: 'manual', // don't follow the redirect and return response as is
78 })
79
80 // Handle non-JSON responses
81 let responseBody: string
82 const contentType = response.headers.get('content-type')
83 if (contentType?.includes('application/json')) {
84 // If JSON, parse and stringify to ensure it's valid JSON
85 const jsonBody = await response.json()
86 responseBody = JSON.stringify(jsonBody)
87 } else {
88 // For non-JSON responses, get raw text
89 responseBody = await response.text()
90 }
91
92 if (!response.ok) {
93 // Try to parse error response if it's JSON
94 try {
95 const errorBody = JSON.parse(responseBody)
96
97 return res.status(response.status).json({
98 status: response.status,
99 error: { message: errorBody?.error || 'Edge function returned an error' },
100 })
101 } catch (parseError) {
102 // If not JSON, return the raw error
103 return res.status(response.status).json({
104 status: response.status,
105 error: { message: responseBody || 'Edge function returned an error' },
106 })
107 }
108 }
109
110 const responseHeaders: Record<string, string> = {}
111 response.headers.forEach((value, key) => {
112 responseHeaders[key] = value
113 })
114
115 return res.status(response.status).json({
116 status: response.status,
117 headers: responseHeaders,
118 body: responseBody,
119 })
120 } catch (error: any) {
121 return res.status(500).json({
122 status: 500,
123 error: {
124 message: error.message || 'Failed to test edge function',
125 },
126 })
127 }
128}