From a8082c551bdf9afa89315e40540dc19d225aa1ec Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Wed, 27 Mar 2024 09:06:47 -0400 Subject: [PATCH] fix(next): removes reliance on instanceof from api error formatting (#5482) --- .vscode/launch.json | 2 +- packages/db-mongodb/src/updateOne.ts | 1 + .../next/src/routes/rest/files/getFile.ts | 4 +- packages/next/src/routes/rest/index.ts | 10 +- .../rest/{RouteError.ts => routeError.ts} | 22 +++-- tsconfig.json | 95 ++++++++++++++----- 6 files changed, 98 insertions(+), 36 deletions(-) rename packages/next/src/routes/rest/{RouteError.ts => routeError.ts} (76%) diff --git a/.vscode/launch.json b/.vscode/launch.json index a0270193a..4b6bafac4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -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", diff --git a/packages/db-mongodb/src/updateOne.ts b/packages/db-mongodb/src/updateOne.ts index e4a1312bc..9602a22fd 100644 --- a/packages/db-mongodb/src/updateOne.ts +++ b/packages/db-mongodb/src/updateOne.ts @@ -26,6 +26,7 @@ export const updateOne: UpdateOne = async function updateOne( }) let result + try { result = await Model.findOneAndUpdate(query, data, options) } catch (error) { diff --git a/packages/next/src/routes/rest/files/getFile.ts b/packages/next/src/routes/rest/files/getFile.ts index 4a0322401..6d564a02b 100644 --- a/packages/next/src/routes/rest/files/getFile.ts +++ b/packages/next/src/routes/rest/files/getFile.ts @@ -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 { +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) diff --git a/tsconfig.json b/tsconfig.json index 645fbaeff..5e34fd5bc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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" + ] +} \ No newline at end of file