From 8af8b7b3a0f8c76863b76ffca54c9260978ef0e2 Mon Sep 17 00:00:00 2001
From: James <james@trbl.design>
Date: Wed, 21 Apr 2021 21:50:19 -0400
Subject: [PATCH] feat: builds plugin infrastructure

---
 src/collections/config/types.ts |  3 ++-
 src/config/build.ts             |  4 ++++
 src/config/schema.ts            |  5 ++++-
 src/config/types.ts             | 13 ++++++++-----
 src/globals/config/types.ts     |  4 +++-
 src/graphql/index.ts            |  4 ++--
 6 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/src/collections/config/types.ts b/src/collections/config/types.ts
index 07b326301dd..875fec2c884 100644
--- a/src/collections/config/types.ts
+++ b/src/collections/config/types.ts
@@ -137,9 +137,10 @@ export type PayloadCollectionConfig = {
   timestamps?: boolean
 };
 
-export interface CollectionConfig extends Omit<DeepRequired<PayloadCollectionConfig>, 'auth' | 'upload'> {
+export interface CollectionConfig extends Omit<DeepRequired<PayloadCollectionConfig>, 'auth' | 'upload' | 'fields'> {
   auth: Auth;
   upload: Upload;
+  fields: Field[];
 }
 
 export type Collection = {
diff --git a/src/config/build.ts b/src/config/build.ts
index 38734f61310..4fe727191f3 100644
--- a/src/config/build.ts
+++ b/src/config/build.ts
@@ -9,5 +9,9 @@ import sanitize from './sanitize';
 export function buildConfig(config: PayloadConfig): Config {
   const sanitized = sanitize(config);
 
+  if (Array.isArray(config.plugins)) {
+    return sanitized.plugins.reduce((configWithPlugins, plugin) => plugin(configWithPlugins), sanitized);
+  }
+
   return sanitized;
 }
diff --git a/src/config/schema.ts b/src/config/schema.ts
index 78667440a78..9e6dc1e8c7a 100644
--- a/src/config/schema.ts
+++ b/src/config/schema.ts
@@ -79,7 +79,7 @@ export default joi.object({
     .keys({
       json: joi.object(),
       compression: joi.object(),
-      middleware: joi.array().items(joi.object()),
+      middleware: joi.array().items(joi.func()),
     }),
   local: joi.boolean(),
   upload: joi.object()
@@ -116,4 +116,7 @@ export default joi.object({
   hooks: joi.object().keys({
     afterError: joi.func(),
   }),
+  plugins: joi.array().items(
+    joi.func(),
+  ),
 });
diff --git a/src/config/types.ts b/src/config/types.ts
index eb8bc0d1871..2bfb05e4f74 100644
--- a/src/config/types.ts
+++ b/src/config/types.ts
@@ -9,7 +9,6 @@ import { Payload } from '..';
 import { AfterErrorHook, PayloadCollectionConfig, CollectionConfig } from '../collections/config/types';
 import { PayloadGlobalConfig, GlobalConfig } from '../globals/config/types';
 import { PayloadRequest } from '../express/types';
-import InitializeGraphQL from '../graphql';
 import { Where } from '../types';
 
 type Email = {
@@ -17,6 +16,9 @@ type Email = {
   fromAddress: string;
 }
 
+// eslint-disable-next-line no-use-before-define
+type Plugin = (config: Config) => Config;
+
 export type EmailTransport = Email & {
   transport: Transporter;
   transportOptions?: SMTPConnection.Options;
@@ -99,7 +101,7 @@ export type PayloadConfig = {
   };
   debug?: boolean
   express?: {
-    json: {
+    json?: {
       limit?: number
     },
     compression?: {
@@ -126,8 +128,8 @@ export type PayloadConfig = {
     fallback?: boolean
   };
   graphQL?: {
-    mutations?: ((graphQL: typeof GraphQL, payload: InitializeGraphQL) => any),
-    queries?: ((graphQL: typeof GraphQL, payload: InitializeGraphQL) => any),
+    mutations?: ((graphQL: typeof GraphQL, payload: Payload) => Record<string, unknown>),
+    queries?: ((graphQL: typeof GraphQL, payload: Payload) => Record<string, unknown>),
     maxComplexity?: number;
     disablePlaygroundInProduction?: boolean;
     disable?: boolean;
@@ -136,9 +138,10 @@ export type PayloadConfig = {
   hooks?: {
     afterError?: AfterErrorHook;
   };
+  plugins?: Plugin[]
 };
 
-export type Config = Omit<DeepRequired<PayloadConfig>, 'collections'> & {
+export type Config = Omit<DeepRequired<PayloadConfig>, 'collections' | 'globals'> & {
   collections: CollectionConfig[]
   globals: GlobalConfig[]
   paths: { [key: string]: string };
diff --git a/src/globals/config/types.ts b/src/globals/config/types.ts
index bb848db4dd2..f7b33f71b15 100644
--- a/src/globals/config/types.ts
+++ b/src/globals/config/types.ts
@@ -62,7 +62,9 @@ export type PayloadGlobalConfig = {
   }
 }
 
-export type GlobalConfig = DeepRequired<PayloadGlobalConfig>
+export interface GlobalConfig extends Omit<DeepRequired<PayloadGlobalConfig>, 'fields'> {
+  fields: Field[]
+}
 
 export type Globals = {
   Model: GlobalModel
diff --git a/src/graphql/index.ts b/src/graphql/index.ts
index 09dfc49e6c0..b6b483e9ef8 100644
--- a/src/graphql/index.ts
+++ b/src/graphql/index.ts
@@ -99,7 +99,7 @@ class InitializeGraphQL {
     };
 
     if (typeof this.config.graphQL.queries === 'function') {
-      const customQueries = this.config.graphQL.queries(GraphQL, this);
+      const customQueries = this.config.graphQL.queries(GraphQL, init);
       this.Query = {
         ...this.Query,
         fields: {
@@ -110,7 +110,7 @@ class InitializeGraphQL {
     }
 
     if (typeof this.config.graphQL.mutations === 'function') {
-      const customMutations = this.config.graphQL.mutations(GraphQL, this);
+      const customMutations = this.config.graphQL.mutations(GraphQL, init);
       this.Mutation = {
         ...this.Mutation,
         fields: {