import joi from 'joi'; import { Response } from 'express'; import { Logger } from '../logger'; import { UnleashError } from '../error/unleash-error'; import { fromLegacyError } from '../error/from-legacy-error'; import createError from 'http-errors'; export const customJoi = joi.extend((j) => ({ type: 'isUrlFriendly', base: j.string(), messages: { 'isUrlFriendly.base': '{{#label}} must be URL friendly', }, validate(value, helpers) { // Base validation regardless of the rules applied if (encodeURIComponent(value) !== value) { // Generate an error, state and options need to be passed return { value, errors: helpers.error('isUrlFriendly.base') }; } return undefined; }, })); export const nameType = customJoi.isUrlFriendly().min(1).max(100).required(); export const handleErrors: ( res: Response, logger: Logger, error: Error, ) => void = (res, logger, error) => { if (createError.isHttpError(error)) { return ( res // @ts-expect-error http errors all have statuses, but there are no // types provided .status(error.status ?? 400) .json({ message: error.message }) .end() ); } const finalError = error instanceof UnleashError ? error : fromLegacyError(error); const format = (thing: object) => JSON.stringify(thing, null, 2); if (!(error instanceof UnleashError)) { logger.debug( `I encountered an error that wasn't an instance of the \`UnleashError\` type. The original error was: ${format( error, )}. It was mapped to ${format(finalError.toJSON())}`, ); } if (finalError.statusCode === 500) { logger.error( `Server failed executing request: ${format(error)}`, error, ); } return res.status(finalError.statusCode).json(finalError).end(); };