* Improve typing of client CORS helper * Take node-fetch as a dependency * Add explicit Firebase region into config * Add new Vercel proxy API routes that talk to backend * Call Vercel proxy routes from `api-call` module * Tweak import to try to get Vercel happy * Tidy up a tiny bit
		
			
				
	
	
		
			63 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			63 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { NextApiRequest, NextApiResponse } from 'next'
 | |
| import { FIREBASE_CONFIG } from 'common/envs/constants'
 | |
| import { promisify } from 'util'
 | |
| import { pipeline } from 'stream'
 | |
| import fetch, { Headers, Response } from 'node-fetch'
 | |
| 
 | |
| function getProxiedRequestHeaders(req: NextApiRequest, whitelist: string[]) {
 | |
|   const result = new Headers()
 | |
|   for (let name of whitelist) {
 | |
|     const v = req.headers[name.toLowerCase()]
 | |
|     if (Array.isArray(v)) {
 | |
|       for (let vv of v) {
 | |
|         result.append(name, vv)
 | |
|       }
 | |
|     } else if (v != null) {
 | |
|       result.append(name, v)
 | |
|     }
 | |
|   }
 | |
|   result.append('X-Forwarded-For', req.socket.remoteAddress || '')
 | |
|   result.append('Via', 'Vercel public API')
 | |
|   return result
 | |
| }
 | |
| 
 | |
| function getProxiedResponseHeaders(res: Response, whitelist: string[]) {
 | |
|   const result: { [k: string]: string } = {}
 | |
|   for (let name of whitelist) {
 | |
|     const v = res.headers.get(name)
 | |
|     if (v != null) {
 | |
|       result[name] = v
 | |
|     }
 | |
|   }
 | |
|   return result
 | |
| }
 | |
| 
 | |
| export const fetchBackend = (req: NextApiRequest, endpoint: string) => {
 | |
|   const { projectId, region } = FIREBASE_CONFIG
 | |
|   const url = `https://${region}-${projectId}.cloudfunctions.net/${endpoint}`
 | |
|   const headers = getProxiedRequestHeaders(req, [
 | |
|     'Authorization',
 | |
|     'Content-Length',
 | |
|     'Content-Type',
 | |
|     'Origin',
 | |
|   ])
 | |
|   return fetch(url, { headers, method: req.method, body: req })
 | |
| }
 | |
| 
 | |
| export const forwardResponse = async (
 | |
|   res: NextApiResponse,
 | |
|   backendRes: Response
 | |
| ) => {
 | |
|   const headers = getProxiedResponseHeaders(backendRes, [
 | |
|     'Access-Control-Allow-Origin',
 | |
|     'Content-Type',
 | |
|     'Cache-Control',
 | |
|     'ETag',
 | |
|     'Vary',
 | |
|   ])
 | |
|   res.writeHead(backendRes.status, headers)
 | |
|   if (backendRes.body != null) {
 | |
|     return await promisify(pipeline)(backendRes.body, res)
 | |
|   }
 | |
| }
 |