fix(next): removes reliance on instanceof from api error formatting (#5482)
This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -10,7 +10,7 @@
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"command": "pnpm run dev _community -- --no-turbo",
|
||||
"command": "node --no-deprecation test/dev.js fields",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"name": "Run Dev Community",
|
||||
"request": "launch",
|
||||
|
||||
@@ -26,6 +26,7 @@ export const updateOne: UpdateOne = async function updateOne(
|
||||
})
|
||||
|
||||
let result
|
||||
|
||||
try {
|
||||
result = await Model.findOneAndUpdate(query, data, options)
|
||||
} catch (error) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import path from 'path'
|
||||
import { APIError } from 'payload/errors'
|
||||
|
||||
import { streamFile } from '../../../next-stream-file/index.js'
|
||||
import { RouteError } from '../RouteError.js'
|
||||
import { routeError } from '../routeError.js'
|
||||
import { checkFileAccess } from './checkFileAccess.js'
|
||||
|
||||
// /:collectionSlug/file/:filename
|
||||
@@ -64,7 +64,7 @@ export const getFile = async ({ collection, filename, req }: Args): Promise<Resp
|
||||
status: httpStatus.OK,
|
||||
})
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
return routeError({
|
||||
collection,
|
||||
err: error,
|
||||
req,
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {
|
||||
} from './types.js'
|
||||
|
||||
import { createPayloadRequest } from '../../utilities/createPayloadRequest.js'
|
||||
import { RouteError } from './RouteError.js'
|
||||
import { routeError } from './routeError.js'
|
||||
import { access } from './auth/access.js'
|
||||
import { forgotPassword } from './auth/forgotPassword.js'
|
||||
import { init } from './auth/init.js'
|
||||
@@ -281,7 +281,7 @@ export const GET =
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
return routeError({
|
||||
collection,
|
||||
err: error,
|
||||
req,
|
||||
@@ -423,7 +423,7 @@ export const POST =
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
return routeError({
|
||||
collection,
|
||||
err: error,
|
||||
req,
|
||||
@@ -492,7 +492,7 @@ export const DELETE =
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
return routeError({
|
||||
collection,
|
||||
err: error,
|
||||
req,
|
||||
@@ -561,7 +561,7 @@ export const PATCH =
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
return routeError({
|
||||
collection,
|
||||
err: error,
|
||||
req,
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
import type { Collection, PayloadRequest } from 'payload/types'
|
||||
|
||||
import httpStatus from 'http-status'
|
||||
import { APIError } from 'payload/errors'
|
||||
import { APIError, ValidationError } from 'payload/errors'
|
||||
|
||||
export type ErrorResponse = { data?: any; errors: unknown[]; stack?: string }
|
||||
|
||||
const formatErrors = (incoming: { [key: string]: unknown } | APIError | Error): ErrorResponse => {
|
||||
const formatErrors = (incoming: { [key: string]: unknown } | APIError): ErrorResponse => {
|
||||
if (incoming) {
|
||||
if (incoming instanceof APIError && incoming.data) {
|
||||
// Cannot use `instanceof` to check error type: https://github.com/microsoft/TypeScript/issues/13965
|
||||
// Instead, get the prototype of the incoming error and check its constructor name
|
||||
const proto = Object.getPrototypeOf(incoming)
|
||||
|
||||
// Payload 'ValidationError' and 'APIError'
|
||||
if (
|
||||
(proto.constructor.name === 'ValidationError' || proto.constructor.name === 'APIError') &&
|
||||
incoming.data
|
||||
) {
|
||||
return {
|
||||
errors: [
|
||||
{
|
||||
@@ -19,8 +27,8 @@ const formatErrors = (incoming: { [key: string]: unknown } | APIError | Error):
|
||||
}
|
||||
}
|
||||
|
||||
// mongoose
|
||||
if (!(incoming instanceof APIError || incoming instanceof Error) && incoming.errors) {
|
||||
// Mongoose 'ValidationError': https://mongoosejs.com/docs/api/error.html#Error.ValidationError
|
||||
if (proto.constructor.name === 'ValidationError' && 'errors' in incoming && incoming.errors) {
|
||||
return {
|
||||
errors: Object.keys(incoming.errors).reduce((acc, key) => {
|
||||
acc.push({
|
||||
@@ -58,7 +66,7 @@ const formatErrors = (incoming: { [key: string]: unknown } | APIError | Error):
|
||||
}
|
||||
}
|
||||
|
||||
export const RouteError = async ({
|
||||
export const routeError = async ({
|
||||
collection,
|
||||
err,
|
||||
req,
|
||||
@@ -78,7 +86,9 @@ export const RouteError = async ({
|
||||
}
|
||||
|
||||
const { config, logger } = req.payload
|
||||
|
||||
let response = formatErrors(err)
|
||||
|
||||
let status = err.status || httpStatus.INTERNAL_SERVER_ERROR
|
||||
|
||||
logger.error(err.stack)
|
||||
@@ -11,7 +11,11 @@
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "preserve",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"noEmit": true,
|
||||
"outDir": "./dist",
|
||||
"resolveJsonModule": true,
|
||||
@@ -19,7 +23,11 @@
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": false,
|
||||
"types": ["jest", "node", "@types/jest"],
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
"@types/jest"
|
||||
],
|
||||
"incremental": true,
|
||||
"isolatedModules": true,
|
||||
"plugins": [
|
||||
@@ -28,26 +36,65 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@payload-config": ["./test/admin/config.ts"],
|
||||
"@payloadcms/live-preview": ["./packages/live-preview/src"],
|
||||
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],
|
||||
"@payloadcms/ui/assets": ["./packages/ui/src/assets/index.ts"],
|
||||
"@payloadcms/ui/elements/*": ["./packages/ui/src/elements/*/index.tsx"],
|
||||
"@payloadcms/ui/fields/*": ["./packages/ui/src/fields/*/index.tsx"],
|
||||
"@payloadcms/ui/forms/*": ["./packages/ui/src/forms/*/index.tsx"],
|
||||
"@payloadcms/ui/graphics/*": ["./packages/ui/src/graphics/*/index.tsx"],
|
||||
"@payloadcms/ui/hooks/*": ["./packages/ui/src/hooks/*.ts"],
|
||||
"@payloadcms/ui/icons/*": ["./packages/ui/src/icons/*/index.tsx"],
|
||||
"@payloadcms/ui/providers/*": ["./packages/ui/src/providers/*/index.tsx"],
|
||||
"@payloadcms/ui/templates/*": ["./packages/ui/src/templates/*/index.tsx"],
|
||||
"@payloadcms/ui/utilities/*": ["./packages/ui/src/utilities/*.ts"],
|
||||
"@payloadcms/ui/scss": ["./packages/ui/src/scss.scss"],
|
||||
"@payloadcms/ui/scss/app.scss": ["./packages/ui/src/scss/app.scss"],
|
||||
"@payloadcms/next/*": ["./packages/next/src/*"],
|
||||
"@payloadcms/next": ["./packages/next/src/exports/*"]
|
||||
"@payload-config": [
|
||||
"./test/fields/config.ts"
|
||||
],
|
||||
"@payloadcms/live-preview": [
|
||||
"./packages/live-preview/src"
|
||||
],
|
||||
"@payloadcms/live-preview-react": [
|
||||
"./packages/live-preview-react/src/index.ts"
|
||||
],
|
||||
"@payloadcms/ui/assets": [
|
||||
"./packages/ui/src/assets/index.ts"
|
||||
],
|
||||
"@payloadcms/ui/elements/*": [
|
||||
"./packages/ui/src/elements/*/index.tsx"
|
||||
],
|
||||
"@payloadcms/ui/fields/*": [
|
||||
"./packages/ui/src/fields/*/index.tsx"
|
||||
],
|
||||
"@payloadcms/ui/forms/*": [
|
||||
"./packages/ui/src/forms/*/index.tsx"
|
||||
],
|
||||
"@payloadcms/ui/graphics/*": [
|
||||
"./packages/ui/src/graphics/*/index.tsx"
|
||||
],
|
||||
"@payloadcms/ui/hooks/*": [
|
||||
"./packages/ui/src/hooks/*.ts"
|
||||
],
|
||||
"@payloadcms/ui/icons/*": [
|
||||
"./packages/ui/src/icons/*/index.tsx"
|
||||
],
|
||||
"@payloadcms/ui/providers/*": [
|
||||
"./packages/ui/src/providers/*/index.tsx"
|
||||
],
|
||||
"@payloadcms/ui/templates/*": [
|
||||
"./packages/ui/src/templates/*/index.tsx"
|
||||
],
|
||||
"@payloadcms/ui/utilities/*": [
|
||||
"./packages/ui/src/utilities/*.ts"
|
||||
],
|
||||
"@payloadcms/ui/scss": [
|
||||
"./packages/ui/src/scss.scss"
|
||||
],
|
||||
"@payloadcms/ui/scss/app.scss": [
|
||||
"./packages/ui/src/scss/app.scss"
|
||||
],
|
||||
"@payloadcms/next/*": [
|
||||
"./packages/next/src/*"
|
||||
],
|
||||
"@payloadcms/next": [
|
||||
"./packages/next/src/exports/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exclude": ["dist", "build", "temp", "node_modules"],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"build",
|
||||
"temp",
|
||||
"node_modules"
|
||||
],
|
||||
"composite": true,
|
||||
"references": [
|
||||
{
|
||||
@@ -108,5 +155,9 @@
|
||||
"path": "./packages/ui"
|
||||
}
|
||||
],
|
||||
"include": ["next-env.d.ts", ".next/types/**/*.ts", "scripts/**/*.ts"]
|
||||
}
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
".next/types/**/*.ts",
|
||||
"scripts/**/*.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user