Merge branch 'ts-final' of github.com:keen-studio/payload into ts-final
This commit is contained in:
@@ -67,6 +67,8 @@ export type AfterDeleteHook = (args?: {
|
||||
doc: any;
|
||||
}) => any;
|
||||
|
||||
export type AfterErrorHook = (err: Error, res: unknown) => { response: any, status: number } | void;
|
||||
|
||||
export type BeforeLoginHook = (args?: {
|
||||
req: PayloadRequest;
|
||||
}) => any;
|
||||
@@ -104,6 +106,7 @@ export type PayloadCollectionConfig = {
|
||||
afterRead?: AfterReadHook[];
|
||||
beforeDelete?: BeforeDeleteHook[];
|
||||
afterDelete?: AfterDeleteHook[];
|
||||
afterError?: AfterErrorHook;
|
||||
beforeLogin?: BeforeLoginHook[];
|
||||
afterLogin?: AfterLoginHook[];
|
||||
afterForgotPassword?: AfterForgotPasswordHook[];
|
||||
|
||||
@@ -231,7 +231,7 @@ async function create(incomingArgs) {
|
||||
// Send verification email if applicable
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (collectionConfig.auth && collectionConfig.auth.verify && !disableVerificationEmail) {
|
||||
if (collectionConfig.auth && collectionConfig.auth.verify) {
|
||||
sendVerificationEmail({
|
||||
config: this.config,
|
||||
sendEmail: this.sendEmail,
|
||||
@@ -239,6 +239,7 @@ async function create(incomingArgs) {
|
||||
user: result,
|
||||
token: data._verificationToken,
|
||||
req,
|
||||
disableEmail: disableVerificationEmail,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { NotFound, Forbidden, ErrorDeletingFile } from '../../errors';
|
||||
import executeAccess from '../../auth/executeAccess';
|
||||
import fileExists from '../../uploads/fileExists';
|
||||
import { BeforeOperationHook } from '../config/types';
|
||||
import { Query } from './types';
|
||||
|
||||
async function deleteQuery(incomingArgs) {
|
||||
let args = incomingArgs;
|
||||
@@ -56,7 +57,7 @@ async function deleteQuery(incomingArgs) {
|
||||
// Retrieve document
|
||||
// /////////////////////////////////////
|
||||
|
||||
const queryToBuild = {
|
||||
const queryToBuild: Query = {
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import executeAccess from '../../auth/executeAccess';
|
||||
import removeInternalFields from '../../utilities/removeInternalFields';
|
||||
import { BeforeOperationHook, BeforeReadHook } from '../config/types';
|
||||
import { Query } from './types';
|
||||
|
||||
async function find(incomingArgs) {
|
||||
let args = incomingArgs;
|
||||
@@ -39,7 +40,7 @@ async function find(incomingArgs) {
|
||||
// Access
|
||||
// /////////////////////////////////////
|
||||
|
||||
const queryToBuild = {};
|
||||
const queryToBuild: Query = {};
|
||||
|
||||
if (where) {
|
||||
let and = [];
|
||||
|
||||
@@ -4,6 +4,7 @@ import { BeforeOperationHook } from '../config/types';
|
||||
import removeInternalFields from '../../utilities/removeInternalFields';
|
||||
import { Forbidden, NotFound } from '../../errors';
|
||||
import executeAccess from '../../auth/executeAccess';
|
||||
import { Query } from './types';
|
||||
|
||||
async function findByID(incomingArgs) {
|
||||
let args = incomingArgs;
|
||||
@@ -45,7 +46,7 @@ async function findByID(incomingArgs) {
|
||||
const accessResults = !overrideAccess ? await executeAccess({ req, disableErrors, id }, collectionConfig.access.read) : true;
|
||||
const hasWhereAccess = typeof accessResults === 'object';
|
||||
|
||||
const queryToBuild = {
|
||||
const queryToBuild: Query = {
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
@@ -76,6 +77,8 @@ async function findByID(incomingArgs) {
|
||||
req.findByID[collectionConfig.slug] = memoize(nonMemoizedFindByID, {
|
||||
isPromise: true,
|
||||
maxSize: 100,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore This is straight from their docs, bad typings
|
||||
transformKey: JSON.stringify,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Configuration } from 'webpack';
|
||||
import SMTPConnection from 'nodemailer/lib/smtp-connection';
|
||||
import { GraphQLType } from 'graphql';
|
||||
import { Payload } from '..';
|
||||
import { PayloadCollectionConfig } from '../collections/config/types';
|
||||
import { AfterErrorHook, PayloadCollectionConfig } from '../collections/config/types';
|
||||
import { PayloadGlobalConfig } from '../globals/config/types';
|
||||
import { PayloadRequest } from '../express/types/payloadRequest';
|
||||
import InitializeGraphQL from '../graphql';
|
||||
@@ -127,7 +127,7 @@ export type PayloadConfig = {
|
||||
components?: { [key: string]: JSX.Element | (() => JSX.Element) };
|
||||
paths?: { [key: string]: string };
|
||||
hooks?: {
|
||||
afterError?: (err: Error, res: unknown) => { response: unknown, status: number} | unknown;
|
||||
afterError?: AfterErrorHook;
|
||||
};
|
||||
webpack?: (config: Configuration) => Configuration;
|
||||
serverModules?: string[];
|
||||
|
||||
@@ -7,13 +7,13 @@ import httpStatus from 'http-status';
|
||||
class ExtendableError extends Error {
|
||||
status: number;
|
||||
|
||||
data: any;
|
||||
data: {[key: string]: unknown};
|
||||
|
||||
isPublic: boolean;
|
||||
|
||||
isOperational: boolean;
|
||||
|
||||
constructor(message: string, status: number, data: any, isPublic: boolean) {
|
||||
constructor(message: string, status: number, data: { [key: string]: unknown }, isPublic: boolean) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
this.message = message;
|
||||
@@ -39,7 +39,7 @@ class APIError extends ExtendableError {
|
||||
* @param {object} data - response data to be returned.
|
||||
* @param {boolean} isPublic - Whether the message should be visible to user or not.
|
||||
*/
|
||||
constructor(message: string, status: number = httpStatus.INTERNAL_SERVER_ERROR, data: any = null, isPublic = false) {
|
||||
constructor(message: string, status: number = httpStatus.INTERNAL_SERVER_ERROR, data: { [key: string]: unknown } = null, isPublic = false) {
|
||||
super(message, status, data, isPublic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ describe('errorHandler', () => {
|
||||
}, logger);
|
||||
await handler(testError, req, res);
|
||||
expect(afterError)
|
||||
// eslint-disable-next-line jest/prefer-called-with
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -113,6 +114,7 @@ describe('errorHandler', () => {
|
||||
}, logger);
|
||||
await handler(testError, req, res);
|
||||
expect(req.collection.config.hooks.afterError)
|
||||
// eslint-disable-next-line jest/prefer-called-with
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import httpStatus from 'http-status';
|
||||
import { Response, NextFunction } from 'express';
|
||||
import { Response } from 'express';
|
||||
import { Logger } from 'pino';
|
||||
import { Config } from '../../config/types';
|
||||
import formatErrorResponse, { ErrorResponse } from '../responses/formatError';
|
||||
import { PayloadRequest } from '../types/payloadRequest';
|
||||
import APIError from '../../errors/APIError';
|
||||
|
||||
export type ErrorHandler = (err: Error, req: PayloadRequest, res: Response, next: NextFunction) => Promise<Response<ErrorResponse>>
|
||||
export type ErrorHandler = (err: Error, req: PayloadRequest, res: Response) => Promise<Response<ErrorResponse> | void>
|
||||
|
||||
// NextFunction must be passed for Express to use this middleware as error handler
|
||||
const errorHandler = (config: Config, logger) => async (err: Error, req: PayloadRequest, res: Response, next: NextFunction): Promise<void> => {
|
||||
const data = formatErrorResponse(err);
|
||||
let response;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const errorHandler = (config: Config, logger: Logger) => async (err: APIError, req: PayloadRequest, res: Response): Promise<void> => {
|
||||
let response = formatErrorResponse(err);
|
||||
let status = err.status || httpStatus.INTERNAL_SERVER_ERROR;
|
||||
|
||||
logger.error(err.stack);
|
||||
|
||||
if (config.debug && config.debug === true) {
|
||||
data.stack = err.stack;
|
||||
response.stack = err.stack;
|
||||
}
|
||||
|
||||
response = {
|
||||
...data,
|
||||
};
|
||||
if (req.collection && typeof req.collection.config.hooks.afterError === 'function') {
|
||||
({ response, status } = await req.collection.config.hooks.afterError(err, response) || { response, status });
|
||||
}
|
||||
|
||||
if (typeof config.hooks.afterError === 'function') {
|
||||
({ response, status } = await config.hooks.afterError(err, response) || { response, status });
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
export type ErrorResponse = unknown;
|
||||
import APIError from '../../errors/APIError';
|
||||
|
||||
const formatErrorResponse = (incoming) => {
|
||||
export type ErrorResponse = { errors: unknown[], data?: any, stack?: string };
|
||||
|
||||
const formatErrorResponse = (incoming: Error | APIError | { [key: string]: unknown }): ErrorResponse => {
|
||||
if (incoming) {
|
||||
if (incoming && incoming.data && incoming.data.length > 0) {
|
||||
if (incoming instanceof APIError && incoming.data && incoming.data.length > 0) {
|
||||
return {
|
||||
errors: [{
|
||||
name: incoming.name,
|
||||
@@ -13,7 +15,7 @@ const formatErrorResponse = (incoming) => {
|
||||
}
|
||||
|
||||
// mongoose
|
||||
if (incoming.errors) {
|
||||
if (!(incoming instanceof APIError || incoming instanceof Error) && incoming.errors) {
|
||||
return {
|
||||
errors: Object.keys(incoming.errors)
|
||||
.reduce((acc, key) => {
|
||||
|
||||
@@ -156,7 +156,6 @@ export type RadioField = FieldBase & {
|
||||
value: string;
|
||||
label: string;
|
||||
}[] | string[];
|
||||
hasMany?: boolean;
|
||||
}
|
||||
|
||||
export type Block = {
|
||||
|
||||
@@ -135,7 +135,7 @@ export class Payload {
|
||||
}
|
||||
|
||||
// Configure email service
|
||||
this.email = buildEmail(this.config.email);
|
||||
this.email = buildEmail(this.emailOptions);
|
||||
|
||||
// Initialize collections & globals
|
||||
initCollections(this);
|
||||
|
||||
Reference in New Issue
Block a user