Merge branch 'ts-final' of github.com:keen-studio/payload into ts-final

This commit is contained in:
James
2020-12-01 17:35:13 -05:00
16 changed files with 45 additions and 28 deletions

View File

@@ -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[];

View File

@@ -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,
});
}

View File

@@ -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: [
{

View File

@@ -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 = [];

View File

@@ -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,
});
}

View File

@@ -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[];

View File

@@ -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);
}
}

View File

@@ -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();
});
});

View File

@@ -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 });

View File

@@ -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) => {

View File

@@ -156,7 +156,6 @@ export type RadioField = FieldBase & {
value: string;
label: string;
}[] | string[];
hasMany?: boolean;
}
export type Block = {

View File

@@ -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);