| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- 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.BRIVEN_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'
- }
- }
|