mirror of
https://github.com/supabase/supabase.git
synced 2026-05-06 08:56:46 -04:00
133 lines
3.5 KiB
TypeScript
133 lines
3.5 KiB
TypeScript
import type { IncomingHttpHeaders } from 'node:http'
|
|
import { snakeCase } from 'lodash'
|
|
import z from 'zod'
|
|
|
|
import { IS_PLATFORM } from '@/lib/constants'
|
|
|
|
/**
|
|
* Construct headers for api request.
|
|
* For platform, it will include apiKey into the provided headers.
|
|
*
|
|
* To prevent relay frontend request headers like useragent, referrer... into the middleware requests.
|
|
* We will only keep the header keys that are in this list: Accept, Authorization, Content-Type, x-connection-encrypted
|
|
*/
|
|
export function constructHeaders(headers: { [prop: string]: any }) {
|
|
if (headers) {
|
|
const cleansedHeaders = {
|
|
Accept: headers.Accept,
|
|
Authorization: headers.Authorization,
|
|
cookie: headers.cookie,
|
|
'Content-Type': headers['Content-Type'],
|
|
'x-connection-encrypted': headers['x-connection-encrypted'],
|
|
} as any
|
|
// clean up key with underfined value
|
|
Object.keys(cleansedHeaders).forEach((key) =>
|
|
cleansedHeaders[key] === undefined ? delete cleansedHeaders[key] : {}
|
|
)
|
|
return {
|
|
...cleansedHeaders,
|
|
// [Joshen] JFYI both Alaister and I checked on this and realised this might not be used actually
|
|
// Could be safe to remove but leaving it here for now
|
|
...(!IS_PLATFORM && { apiKey: `${process.env.SUPABASE_SERVICE_KEY}` }),
|
|
}
|
|
} else {
|
|
return {
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json',
|
|
}
|
|
}
|
|
}
|
|
|
|
// Typically for HTTP payloads
|
|
// @ts-ignore
|
|
export const toSnakeCase = (object) => {
|
|
const snakeCaseObject = {}
|
|
const snakeCaseArray = []
|
|
|
|
if (!object) return null
|
|
|
|
if (Array.isArray(object)) {
|
|
for (const item of object) {
|
|
if (typeof item === 'object') {
|
|
snakeCaseArray.push(toSnakeCase(item))
|
|
} else {
|
|
snakeCaseArray.push(item)
|
|
}
|
|
}
|
|
return snakeCaseArray
|
|
} else if (typeof object === 'object') {
|
|
for (const key of Object.keys(object)) {
|
|
if (typeof object[key] === 'object') {
|
|
// @ts-ignore
|
|
snakeCaseObject[snakeCase(key)] = toSnakeCase(object[key])
|
|
} else {
|
|
// @ts-ignore
|
|
snakeCaseObject[snakeCase(key)] = object[key]
|
|
}
|
|
}
|
|
return snakeCaseObject
|
|
} else {
|
|
return object
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Converts Node.js `IncomingHttpHeaders` to Fetch API `Headers`.
|
|
*/
|
|
export function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Headers {
|
|
const headers = new Headers()
|
|
for (const [key, value] of Object.entries(nodeHeaders)) {
|
|
if (Array.isArray(value)) {
|
|
value.forEach((v) => headers.append(key, v))
|
|
} else if (value !== undefined) {
|
|
headers.append(key, value)
|
|
}
|
|
}
|
|
return headers
|
|
}
|
|
|
|
/**
|
|
* Zod transformer to parse boolean values from strings.
|
|
*
|
|
* Use when accepting a boolean value in a query parameter.
|
|
*/
|
|
export function zBooleanString(errorMsg?: string) {
|
|
return z.string().transform((value, ctx) => {
|
|
if (value === 'true') {
|
|
return true
|
|
}
|
|
|
|
if (value === 'false') {
|
|
return false
|
|
}
|
|
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: errorMsg || 'must be a boolean string',
|
|
})
|
|
return z.NEVER
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Transform a comma-separated string into an array of strings.
|
|
*
|
|
* Use when accepting a list of values in a query parameter.
|
|
*/
|
|
export function commaSeparatedStringIntoArray(value: string): string[] {
|
|
return value
|
|
.split(',')
|
|
.map((v) => v.trim())
|
|
.filter(Boolean)
|
|
}
|
|
|
|
export class InternalServerError extends Error {
|
|
constructor(
|
|
message: string,
|
|
public details?: Record<string, unknown>
|
|
) {
|
|
super(message)
|
|
this.name = 'InternalServerError'
|
|
}
|
|
}
|