feat: ability to add context to payload's request object (#2796)
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
This commit is contained in:
127
docs/hooks/context.mdx
Normal file
127
docs/hooks/context.mdx
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
---
|
||||||
|
title: Context
|
||||||
|
label: Context
|
||||||
|
order: 50
|
||||||
|
desc: Context allows you to pass in extra data that can be shared between hooks
|
||||||
|
keywords: hooks, context, payload context, payloadcontext, data, extra data, shared data, shared, extra
|
||||||
|
---
|
||||||
|
|
||||||
|
The `context` object in hooks is used to share data across different hooks. The persists throughout the entire lifecycle of a request and is available within every hook. This allows you to add logic to your hooks based on the request state by setting properties to `req.context` and using them elsewhere.
|
||||||
|
|
||||||
|
## When to use Context
|
||||||
|
|
||||||
|
Context gives you a way forward on otherwise difficult problems such as:
|
||||||
|
|
||||||
|
1. **Passing data between hooks**: Needing data in multiple hooks from a 3rd party API, it could be retrieved and used in `beforeChange` and later used again in an `afterChange` hook without having to fetch it twice.
|
||||||
|
2. **Preventing infinite loops**: Calling `payload.update()` on the same document that triggered an `afterChange` hook will create an infinite loop, control the flow by assigning a no-op condition to context
|
||||||
|
3. **Passing data to local API**: Setting values on the `req.context` and pass it to `payload.create()` you can provide additional data to hooks without adding extraneous fields.
|
||||||
|
4. **Passing data between hooks and middleware or custom endpoints**: Hooks could set context across multiple collections and then be used in a final `postMiddleware`.
|
||||||
|
|
||||||
|
## How to Use Context
|
||||||
|
|
||||||
|
Let's see examples on how context can be used in the first two scenarios mentioned above:
|
||||||
|
|
||||||
|
### Passing data between hooks
|
||||||
|
|
||||||
|
To pass data between hooks, you can assign values to context in an earlier hook in the lifecycle of a request and expect it the context in a later hook.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const Customer: CollectionConfig = {
|
||||||
|
slug: 'customers',
|
||||||
|
hooks: {
|
||||||
|
beforeChange: [async ({ context, data }) => {
|
||||||
|
// assign the customerData to context for use later
|
||||||
|
context.customerData = await fetchCustomerData(data.customerID);
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
// some data we use here
|
||||||
|
name: context.customerData.name
|
||||||
|
};
|
||||||
|
}],
|
||||||
|
afterChange: [async ({ context, doc, req }) => {
|
||||||
|
// use context.customerData without needing to fetch it again
|
||||||
|
if (context.customerData.contacted === false) {
|
||||||
|
createTodo('Call Customer', context.customerData)
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
fields: [ /* ... */ ],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Preventing infinite loops
|
||||||
|
|
||||||
|
Let's say you have an `afterChange` hook, and you want to do a calculation inside the hook (as the document ID needed for the calculation is available in the `afterChange` hook, but not in the `beforeChange` hook). Once that's done, you want to update the document with the result of the calculation.
|
||||||
|
|
||||||
|
Bad example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const Customer: CollectionConfig = {
|
||||||
|
slug: 'customers',
|
||||||
|
hooks: {
|
||||||
|
afterChange: [async ({ doc }) => {
|
||||||
|
await payload.update({
|
||||||
|
// DANGER: updating the same slug as the collection in an afterChange will create an infinite loop!
|
||||||
|
collection: 'customers',
|
||||||
|
id: doc.id,
|
||||||
|
data: {
|
||||||
|
...(await fetchCustomerData(data.customerID))
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
fields: [ /* ... */ ],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Instead of the above, we need to tell the `afterChange` hook to not run again if it performs the update (and thus not update itself again). We can solve that with context.
|
||||||
|
|
||||||
|
Fixed example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const MyCollection: CollectionConfig = {
|
||||||
|
slug: 'slug',
|
||||||
|
hooks: {
|
||||||
|
afterChange: [async ({ context, doc }) => {
|
||||||
|
// return if flag was previously set
|
||||||
|
if (context.triggerAfterChange === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await payload.update({
|
||||||
|
collection: contextHooksSlug,
|
||||||
|
id: doc.id,
|
||||||
|
data: {
|
||||||
|
...(await fetchCustomerData(data.customerID))
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
// set a flag to prevent from running again
|
||||||
|
triggerAfterChange: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
fields: [ /* ... */ ],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Typing context
|
||||||
|
|
||||||
|
The default typescript interface for `context` is `{ [key: string]: unknown }`. If you prefer a more strict typing in your project or when authoring plugins for others, you can override this using the `declare` syntax.
|
||||||
|
|
||||||
|
This is known as "type augmentation" - a TypeScript feature which allows us to add types to existing objects. Simply put this in any .ts or .d.ts file:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { RequestContext as OriginalRequestContext } from 'payload';
|
||||||
|
|
||||||
|
declare module 'payload' {
|
||||||
|
// Create a new interface that merges your additional fields with the original one
|
||||||
|
export interface RequestContext extends OriginalRequestContext {
|
||||||
|
myObject?: string;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will add a the property `myObject` with a type of string to every context object. Make sure to follow this example correctly, as type augmentation can mess up your types if you do it wrong.
|
||||||
@@ -77,6 +77,7 @@ You can specify more options within the Local API vs. REST or GraphQL due to the
|
|||||||
| `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. |
|
| `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. |
|
||||||
| `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. |
|
| `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. |
|
||||||
| `pagination` | Set to false to return all documents and avoid querying for document counts. |
|
| `pagination` | Set to false to return all documents and avoid querying for document counts. |
|
||||||
|
| `context` | [Context](/docs/hooks/context), which will then be passed to `context` and `req.context`, which can be read by hooks. Useful if you want to pass additional information to the hooks which shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook to determine if it should run or not. |
|
||||||
|
|
||||||
_There are more options available on an operation by operation basis outlined below._
|
_There are more options available on an operation by operation basis outlined below._
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ async function forgotPassword(incomingArgs: Arguments): Promise<string | null> {
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'forgotPassword',
|
operation: 'forgotPassword',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ async function forgotPassword(incomingArgs: Arguments): Promise<string | null> {
|
|||||||
|
|
||||||
await collectionConfig.hooks.afterForgotPassword.reduce(async (priorHook, hook) => {
|
await collectionConfig.hooks.afterForgotPassword.reduce(async (priorHook, hook) => {
|
||||||
await priorHook;
|
await priorHook;
|
||||||
await hook({ args });
|
await hook({ args, context: req.context });
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Payload } from '../../../payload';
|
|||||||
import { getDataLoader } from '../../../collections/dataloader';
|
import { getDataLoader } from '../../../collections/dataloader';
|
||||||
import i18n from '../../../translations/init';
|
import i18n from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -27,6 +28,7 @@ async function localForgotPassword<T extends keyof GeneratedTypes['collections']
|
|||||||
disableEmail,
|
disableEmail,
|
||||||
req = {} as PayloadRequest,
|
req = {} as PayloadRequest,
|
||||||
} = options;
|
} = options;
|
||||||
|
setRequestContext(options.req);
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Payload } from '../../../payload';
|
|||||||
import { getDataLoader } from '../../../collections/dataloader';
|
import { getDataLoader } from '../../../collections/dataloader';
|
||||||
import i18n from '../../../translations/init';
|
import i18n from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: TSlug
|
collection: TSlug
|
||||||
@@ -37,6 +38,8 @@ async function localLogin<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
overrideAccess = true,
|
overrideAccess = true,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
} = options;
|
} = options;
|
||||||
|
setRequestContext(options.req);
|
||||||
|
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { PayloadRequest } from '../../../express/types';
|
|||||||
import { getDataLoader } from '../../../collections/dataloader';
|
import { getDataLoader } from '../../../collections/dataloader';
|
||||||
import i18n from '../../../translations/init';
|
import i18n from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -26,6 +27,7 @@ async function localResetPassword<T extends keyof GeneratedTypes['collections']>
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
req = {} as PayloadRequest,
|
req = {} as PayloadRequest,
|
||||||
} = options;
|
} = options;
|
||||||
|
setRequestContext(options.req);
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import unlock from '../unlock';
|
|||||||
import { getDataLoader } from '../../../collections/dataloader';
|
import { getDataLoader } from '../../../collections/dataloader';
|
||||||
import i18n from '../../../translations/init';
|
import i18n from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -25,6 +26,7 @@ async function localUnlock<T extends keyof GeneratedTypes['collections']>(
|
|||||||
overrideAccess = true,
|
overrideAccess = true,
|
||||||
req = {} as PayloadRequest,
|
req = {} as PayloadRequest,
|
||||||
} = options;
|
} = options;
|
||||||
|
setRequestContext(options.req);
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'login',
|
operation: 'login',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -133,6 +134,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
user = (await hook({
|
user = (await hook({
|
||||||
user,
|
user,
|
||||||
req: args.req,
|
req: args.req,
|
||||||
|
context: req.context,
|
||||||
})) || user;
|
})) || user;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -172,6 +174,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
user,
|
user,
|
||||||
req: args.req,
|
req: args.req,
|
||||||
token,
|
token,
|
||||||
|
context: req.context,
|
||||||
}) || user;
|
}) || user;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -186,6 +189,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -198,6 +202,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
user = await hook({
|
user = await hook({
|
||||||
req,
|
req,
|
||||||
doc: user,
|
doc: user,
|
||||||
|
context: req.context,
|
||||||
}) || user;
|
}) || user;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ async function logout(incomingArgs: Arguments): Promise<string> {
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
req,
|
req,
|
||||||
res,
|
res,
|
||||||
|
context: req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ async function me({
|
|||||||
response = await hook({
|
response = await hook({
|
||||||
req,
|
req,
|
||||||
response,
|
response,
|
||||||
|
context: req.context,
|
||||||
}) || response;
|
}) || response;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'refresh',
|
operation: 'refresh',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -114,6 +115,7 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
|||||||
res: args.res,
|
res: args.res,
|
||||||
exp,
|
exp,
|
||||||
token: refreshedToken,
|
token: refreshedToken,
|
||||||
|
context: args.req.context,
|
||||||
})) || response;
|
})) || response;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Response } from 'express';
|
|||||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||||
import { Access, Endpoint, EntityDescription, GeneratePreviewURL } from '../../config/types';
|
import { Access, Endpoint, EntityDescription, GeneratePreviewURL } from '../../config/types';
|
||||||
import { Field } from '../../fields/config/types';
|
import { Field } from '../../fields/config/types';
|
||||||
import { PayloadRequest } from '../../express/types';
|
import { PayloadRequest, RequestContext } from '../../express/types';
|
||||||
import { Auth, IncomingAuthType, User } from '../../auth/types';
|
import { Auth, IncomingAuthType, User } from '../../auth/types';
|
||||||
import { IncomingUploadType, Upload } from '../../uploads/types';
|
import { IncomingUploadType, Upload } from '../../uploads/types';
|
||||||
import { IncomingCollectionVersions, SanitizedCollectionVersions } from '../../versions/types';
|
import { IncomingCollectionVersions, SanitizedCollectionVersions } from '../../versions/types';
|
||||||
@@ -49,6 +49,7 @@ export type BeforeOperationHook = (args: {
|
|||||||
* Hook operation being performed
|
* Hook operation being performed
|
||||||
*/
|
*/
|
||||||
operation: HookOperationType;
|
operation: HookOperationType;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type BeforeValidateHook<T extends TypeWithID = any> = (args: {
|
export type BeforeValidateHook<T extends TypeWithID = any> = (args: {
|
||||||
@@ -64,6 +65,7 @@ export type BeforeValidateHook<T extends TypeWithID = any> = (args: {
|
|||||||
* `undefined` on 'create' operation
|
* `undefined` on 'create' operation
|
||||||
*/
|
*/
|
||||||
originalDoc?: T;
|
originalDoc?: T;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type BeforeChangeHook<T extends TypeWithID = any> = (args: {
|
export type BeforeChangeHook<T extends TypeWithID = any> = (args: {
|
||||||
@@ -79,6 +81,7 @@ export type BeforeChangeHook<T extends TypeWithID = any> = (args: {
|
|||||||
* `undefined` on 'create' operation
|
* `undefined` on 'create' operation
|
||||||
*/
|
*/
|
||||||
originalDoc?: T;
|
originalDoc?: T;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type AfterChangeHook<T extends TypeWithID = any> = (args: {
|
export type AfterChangeHook<T extends TypeWithID = any> = (args: {
|
||||||
@@ -89,53 +92,62 @@ export type AfterChangeHook<T extends TypeWithID = any> = (args: {
|
|||||||
* Hook operation being performed
|
* Hook operation being performed
|
||||||
*/
|
*/
|
||||||
operation: CreateOrUpdateOperation;
|
operation: CreateOrUpdateOperation;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type BeforeReadHook<T extends TypeWithID = any> = (args: {
|
export type BeforeReadHook<T extends TypeWithID = any> = (args: {
|
||||||
doc: T;
|
doc: T;
|
||||||
req: PayloadRequest;
|
req: PayloadRequest;
|
||||||
query: { [key: string]: any };
|
query: { [key: string]: any };
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type AfterReadHook<T extends TypeWithID = any> = (args: {
|
export type AfterReadHook<T extends TypeWithID = any> = (args: {
|
||||||
doc: T;
|
doc: T;
|
||||||
req: PayloadRequest;
|
req: PayloadRequest;
|
||||||
query?: { [key: string]: any };
|
query?: { [key: string]: any };
|
||||||
findMany?: boolean
|
findMany?: boolean;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type BeforeDeleteHook = (args: {
|
export type BeforeDeleteHook = (args: {
|
||||||
req: PayloadRequest;
|
req: PayloadRequest;
|
||||||
id: string | number;
|
id: string | number;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type AfterDeleteHook<T extends TypeWithID = any> = (args: {
|
export type AfterDeleteHook<T extends TypeWithID = any> = (args: {
|
||||||
doc: T;
|
doc: T;
|
||||||
req: PayloadRequest;
|
req: PayloadRequest;
|
||||||
id: string | number;
|
id: string | number;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type AfterErrorHook = (err: Error, res: unknown) => { response: any, status: number } | void;
|
export type AfterErrorHook = (err: Error, res: unknown, context: RequestContext) => { response: any, status: number } | void;
|
||||||
|
|
||||||
export type BeforeLoginHook<T extends TypeWithID = any> = (args: {
|
export type BeforeLoginHook<T extends TypeWithID = any> = (args: {
|
||||||
req: PayloadRequest;
|
req: PayloadRequest;
|
||||||
user: T
|
user: T;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type AfterLoginHook<T extends TypeWithID = any> = (args: {
|
export type AfterLoginHook<T extends TypeWithID = any> = (args: {
|
||||||
req: PayloadRequest;
|
req: PayloadRequest;
|
||||||
user: T;
|
user: T;
|
||||||
token: string;
|
token: string;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type AfterLogoutHook<T extends TypeWithID = any> = (args: {
|
export type AfterLogoutHook<T extends TypeWithID = any> = (args: {
|
||||||
req: PayloadRequest;
|
req: PayloadRequest;
|
||||||
res: Response;
|
res: Response;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type AfterMeHook<T extends TypeWithID = any> = (args: {
|
export type AfterMeHook<T extends TypeWithID = any> = (args: {
|
||||||
req: PayloadRequest;
|
req: PayloadRequest;
|
||||||
response: unknown;
|
response: unknown;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type AfterRefreshHook<T extends TypeWithID = any> = (args: {
|
export type AfterRefreshHook<T extends TypeWithID = any> = (args: {
|
||||||
@@ -143,10 +155,12 @@ export type AfterRefreshHook<T extends TypeWithID = any> = (args: {
|
|||||||
res: Response;
|
res: Response;
|
||||||
token: string;
|
token: string;
|
||||||
exp: number;
|
exp: number;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
export type AfterForgotPasswordHook = (args: {
|
export type AfterForgotPasswordHook = (args: {
|
||||||
args?: any;
|
args?: any;
|
||||||
|
context: RequestContext;
|
||||||
}) => any;
|
}) => any;
|
||||||
|
|
||||||
type BeforeDuplicateArgs<T> = {
|
type BeforeDuplicateArgs<T> = {
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'create',
|
operation: 'create',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -130,6 +131,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
operation: 'create',
|
operation: 'create',
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -143,6 +145,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
data,
|
data,
|
||||||
req,
|
req,
|
||||||
operation: 'create',
|
operation: 'create',
|
||||||
|
context: req.context,
|
||||||
})) || data;
|
})) || data;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -165,6 +168,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
data,
|
data,
|
||||||
req,
|
req,
|
||||||
operation: 'create',
|
operation: 'create',
|
||||||
|
context: req.context,
|
||||||
})) || data;
|
})) || data;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -180,6 +184,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
operation: 'create',
|
operation: 'create',
|
||||||
req,
|
req,
|
||||||
skipValidation: shouldSaveDraft,
|
skipValidation: shouldSaveDraft,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -203,7 +208,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
doc: resultWithLocales,
|
doc: resultWithLocales,
|
||||||
payload: req.payload,
|
payload: req.payload,
|
||||||
password: data.password as string,
|
password: data.password as string,
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
doc = await Model.create(resultWithLocales);
|
doc = await Model.create(resultWithLocales);
|
||||||
@@ -266,6 +271,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -278,6 +284,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
result = await hook({
|
result = await hook({
|
||||||
req,
|
req,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -292,6 +299,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
entityConfig: collectionConfig,
|
entityConfig: collectionConfig,
|
||||||
operation: 'create',
|
operation: 'create',
|
||||||
req,
|
req,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -306,6 +314,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
previousDoc: {},
|
previousDoc: {},
|
||||||
req: args.req,
|
req: args.req,
|
||||||
operation: 'create',
|
operation: 'create',
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'delete',
|
operation: 'delete',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -116,6 +117,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
|||||||
return hook({
|
return hook({
|
||||||
req,
|
req,
|
||||||
id,
|
id,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -150,6 +152,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -162,6 +165,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
|||||||
result = await hook({
|
result = await hook({
|
||||||
req,
|
req,
|
||||||
doc: result || doc,
|
doc: result || doc,
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -176,6 +180,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
|||||||
req,
|
req,
|
||||||
id,
|
id,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'delete',
|
operation: 'delete',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -72,6 +73,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
|||||||
return hook({
|
return hook({
|
||||||
req,
|
req,
|
||||||
id,
|
id,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -145,6 +147,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -157,6 +160,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
|||||||
result = await hook({
|
result = await hook({
|
||||||
req,
|
req,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -167,7 +171,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
|||||||
await collectionConfig.hooks.afterDelete.reduce(async (priorHook, hook) => {
|
await collectionConfig.hooks.afterDelete.reduce(async (priorHook, hook) => {
|
||||||
await priorHook;
|
await priorHook;
|
||||||
|
|
||||||
result = await hook({ req, id, doc: result }) || result;
|
result = await hook({ req, id, doc: result, context: req.context }) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'read',
|
operation: 'read',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -180,7 +181,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
|||||||
await collectionConfig.hooks.beforeRead.reduce(async (priorHook, hook) => {
|
await collectionConfig.hooks.beforeRead.reduce(async (priorHook, hook) => {
|
||||||
await priorHook;
|
await priorHook;
|
||||||
|
|
||||||
docRef = await hook({ req, query, doc: docRef }) || docRef;
|
docRef = await hook({ req, query, doc: docRef, context: req.context }) || docRef;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
return docRef;
|
return docRef;
|
||||||
@@ -202,6 +203,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
|||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
findMany: true,
|
findMany: true,
|
||||||
|
context: req.context,
|
||||||
}))),
|
}))),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -217,7 +219,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
|||||||
await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook) => {
|
await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook) => {
|
||||||
await priorHook;
|
await priorHook;
|
||||||
|
|
||||||
docRef = await hook({ req, query, doc: docRef, findMany: true }) || doc;
|
docRef = await hook({ req, query, doc: docRef, findMany: true, context: req.context }) || doc;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
return docRef;
|
return docRef;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ async function findByID<T extends TypeWithID>(
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'read',
|
operation: 'read',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -138,6 +139,7 @@ async function findByID<T extends TypeWithID>(
|
|||||||
req,
|
req,
|
||||||
query,
|
query,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -153,6 +155,7 @@ async function findByID<T extends TypeWithID>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -166,6 +169,7 @@ async function findByID<T extends TypeWithID>(
|
|||||||
req,
|
req,
|
||||||
query,
|
query,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
|||||||
req,
|
req,
|
||||||
query,
|
query,
|
||||||
doc: result.version,
|
doc: result.version,
|
||||||
|
context: req.context,
|
||||||
}) || result.version;
|
}) || result.version;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -113,6 +114,7 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -126,6 +128,7 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
|||||||
req,
|
req,
|
||||||
query,
|
query,
|
||||||
doc: result.version,
|
doc: result.version,
|
||||||
|
context: req.context,
|
||||||
}) || result.version;
|
}) || result.version;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
|||||||
await collectionConfig.hooks.beforeRead.reduce(async (priorHook, hook) => {
|
await collectionConfig.hooks.beforeRead.reduce(async (priorHook, hook) => {
|
||||||
await priorHook;
|
await priorHook;
|
||||||
|
|
||||||
docRef.version = await hook({ req, query, doc: docRef.version }) || docRef.version;
|
docRef.version = await hook({ req, query, doc: docRef.version, context: req.context }) || docRef.version;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
return docRef;
|
return docRef;
|
||||||
@@ -133,6 +133,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
|||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
findMany: true,
|
findMany: true,
|
||||||
|
context: req.context,
|
||||||
}),
|
}),
|
||||||
}))),
|
}))),
|
||||||
};
|
};
|
||||||
@@ -149,7 +150,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
|||||||
await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook) => {
|
await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook) => {
|
||||||
await priorHook;
|
await priorHook;
|
||||||
|
|
||||||
docRef.version = await hook({ req, query, doc: doc.version, findMany: true }) || doc.version;
|
docRef.version = await hook({ req, query, doc: doc.version, findMany: true, context: req.context }) || doc.version;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
return docRef;
|
return docRef;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Config as GeneratedTypes } from 'payload/generated-types';
|
|||||||
import { UploadedFile } from 'express-fileupload';
|
import { UploadedFile } from 'express-fileupload';
|
||||||
import { MarkOptional } from 'ts-essentials';
|
import { MarkOptional } from 'ts-essentials';
|
||||||
import { Payload } from '../../../payload';
|
import { Payload } from '../../../payload';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { Document } from '../../../types';
|
import { Document } from '../../../types';
|
||||||
import getFileByPath from '../../../uploads/getFileByPath';
|
import getFileByPath from '../../../uploads/getFileByPath';
|
||||||
import create from '../create';
|
import create from '../create';
|
||||||
@@ -10,6 +10,7 @@ import { getDataLoader } from '../../dataloader';
|
|||||||
import { File } from '../../../uploads/types';
|
import { File } from '../../../uploads/types';
|
||||||
import i18n from '../../../translations/init';
|
import i18n from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: TSlug
|
collection: TSlug
|
||||||
@@ -26,6 +27,10 @@ export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
|||||||
overwriteExistingFiles?: boolean
|
overwriteExistingFiles?: boolean
|
||||||
req?: PayloadRequest
|
req?: PayloadRequest
|
||||||
draft?: boolean
|
draft?: boolean
|
||||||
|
/**
|
||||||
|
* context, which will then be passed to req.context, which can be read by hooks
|
||||||
|
*/
|
||||||
|
context?: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function createLocal<TSlug extends keyof GeneratedTypes['collections']>(
|
export default async function createLocal<TSlug extends keyof GeneratedTypes['collections']>(
|
||||||
@@ -47,7 +52,9 @@ export default async function createLocal<TSlug extends keyof GeneratedTypes['co
|
|||||||
overwriteExistingFiles = false,
|
overwriteExistingFiles = false,
|
||||||
req = {} as PayloadRequest,
|
req = {} as PayloadRequest,
|
||||||
draft,
|
draft,
|
||||||
|
context,
|
||||||
} = options;
|
} = options;
|
||||||
|
setRequestContext(req, context);
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Config as GeneratedTypes } from '../../../generated-types';
|
import { Config as GeneratedTypes } from '../../../generated-types';
|
||||||
import { Document, Where } from '../../../types';
|
import { Document, Where } from '../../../types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { Payload } from '../../../payload';
|
import { Payload } from '../../../payload';
|
||||||
import deleteOperation from '../delete';
|
import deleteOperation from '../delete';
|
||||||
import deleteByID from '../deleteByID';
|
import deleteByID from '../deleteByID';
|
||||||
@@ -8,6 +8,7 @@ import { getDataLoader } from '../../dataloader';
|
|||||||
import i18n from '../../../translations/init';
|
import i18n from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
import { BulkOperationResult } from '../../config/types';
|
import { BulkOperationResult } from '../../config/types';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type BaseOptions<T extends keyof GeneratedTypes['collections']> = {
|
export type BaseOptions<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -17,6 +18,10 @@ export type BaseOptions<T extends keyof GeneratedTypes['collections']> = {
|
|||||||
user?: Document
|
user?: Document
|
||||||
overrideAccess?: boolean
|
overrideAccess?: boolean
|
||||||
showHiddenFields?: boolean
|
showHiddenFields?: boolean
|
||||||
|
/**
|
||||||
|
* context, which will then be passed to req.context, which can be read by hooks
|
||||||
|
*/
|
||||||
|
context?: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ByIDOptions<T extends keyof GeneratedTypes['collections']> = BaseOptions<T> & {
|
export type ByIDOptions<T extends keyof GeneratedTypes['collections']> = BaseOptions<T> & {
|
||||||
@@ -45,6 +50,7 @@ async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>(pa
|
|||||||
user,
|
user,
|
||||||
overrideAccess = true,
|
overrideAccess = true,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
@@ -63,6 +69,7 @@ async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>(pa
|
|||||||
payload,
|
payload,
|
||||||
i18n: i18n(payload.config.i18n),
|
i18n: i18n(payload.config.i18n),
|
||||||
} as PayloadRequest;
|
} as PayloadRequest;
|
||||||
|
setRequestContext(req, context);
|
||||||
|
|
||||||
if (!req.t) req.t = req.i18n.t;
|
if (!req.t) req.t = req.i18n.t;
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ import { Config as GeneratedTypes } from 'payload/generated-types';
|
|||||||
import { PaginatedDocs } from '../../../mongoose/types';
|
import { PaginatedDocs } from '../../../mongoose/types';
|
||||||
import { Document, Where } from '../../../types';
|
import { Document, Where } from '../../../types';
|
||||||
import { Payload } from '../../../payload';
|
import { Payload } from '../../../payload';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import find from '../find';
|
import find from '../find';
|
||||||
import { getDataLoader } from '../../dataloader';
|
import { getDataLoader } from '../../dataloader';
|
||||||
import i18n from '../../../translations/init';
|
import i18n from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -25,6 +26,10 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
|||||||
where?: Where
|
where?: Where
|
||||||
draft?: boolean
|
draft?: boolean
|
||||||
req?: PayloadRequest
|
req?: PayloadRequest
|
||||||
|
/**
|
||||||
|
* context, which will then be passed to req.context, which can be read by hooks
|
||||||
|
*/
|
||||||
|
context?: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function findLocal<T extends keyof GeneratedTypes['collections']>(
|
export default async function findLocal<T extends keyof GeneratedTypes['collections']>(
|
||||||
@@ -48,7 +53,9 @@ export default async function findLocal<T extends keyof GeneratedTypes['collecti
|
|||||||
draft = false,
|
draft = false,
|
||||||
pagination = true,
|
pagination = true,
|
||||||
req = {} as PayloadRequest,
|
req = {} as PayloadRequest,
|
||||||
|
context,
|
||||||
} = options;
|
} = options;
|
||||||
|
setRequestContext(options.req, context);
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { Document } from '../../../types';
|
import { Document } from '../../../types';
|
||||||
import findByID from '../findByID';
|
import findByID from '../findByID';
|
||||||
import { Payload } from '../../../payload';
|
import { Payload } from '../../../payload';
|
||||||
import { getDataLoader } from '../../dataloader';
|
import { getDataLoader } from '../../dataloader';
|
||||||
import i18n from '../../../translations/init';
|
import i18n from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -20,6 +21,10 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
|||||||
disableErrors?: boolean
|
disableErrors?: boolean
|
||||||
req?: PayloadRequest
|
req?: PayloadRequest
|
||||||
draft?: boolean
|
draft?: boolean
|
||||||
|
/**
|
||||||
|
* context, which will then be passed to req.context, which can be read by hooks
|
||||||
|
*/
|
||||||
|
context?: RequestContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function findByIDLocal<T extends keyof GeneratedTypes['collections']>(
|
export default async function findByIDLocal<T extends keyof GeneratedTypes['collections']>(
|
||||||
@@ -39,7 +44,9 @@ export default async function findByIDLocal<T extends keyof GeneratedTypes['coll
|
|||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
req = {} as PayloadRequest,
|
req = {} as PayloadRequest,
|
||||||
draft = false,
|
draft = false,
|
||||||
|
context,
|
||||||
} = options;
|
} = options;
|
||||||
|
setRequestContext(options.req, context);
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||||
import { Payload } from '../../../payload';
|
import { Payload } from '../../../payload';
|
||||||
import { Document } from '../../../types';
|
import { Document } from '../../../types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { TypeWithVersion } from '../../../versions/types';
|
import { TypeWithVersion } from '../../../versions/types';
|
||||||
import findVersionByID from '../findVersionByID';
|
import findVersionByID from '../findVersionByID';
|
||||||
import { getDataLoader } from '../../dataloader';
|
import { getDataLoader } from '../../dataloader';
|
||||||
import i18n from '../../../translations/init';
|
import i18n from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -19,6 +20,11 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
|||||||
showHiddenFields?: boolean
|
showHiddenFields?: boolean
|
||||||
disableErrors?: boolean
|
disableErrors?: boolean
|
||||||
req?: PayloadRequest
|
req?: PayloadRequest
|
||||||
|
draft?: boolean
|
||||||
|
/**
|
||||||
|
* context, which will then be passed to req.context, which can be read by hooks
|
||||||
|
*/
|
||||||
|
context?: RequestContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function findVersionByIDLocal<T extends keyof GeneratedTypes['collections']>(
|
export default async function findVersionByIDLocal<T extends keyof GeneratedTypes['collections']>(
|
||||||
@@ -35,7 +41,9 @@ export default async function findVersionByIDLocal<T extends keyof GeneratedType
|
|||||||
disableErrors = false,
|
disableErrors = false,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
req = {} as PayloadRequest,
|
req = {} as PayloadRequest,
|
||||||
|
context,
|
||||||
} = options;
|
} = options;
|
||||||
|
setRequestContext(options.req, context);
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import { Payload } from '../../../payload';
|
|||||||
import { Document, Where } from '../../../types';
|
import { Document, Where } from '../../../types';
|
||||||
import { PaginatedDocs } from '../../../mongoose/types';
|
import { PaginatedDocs } from '../../../mongoose/types';
|
||||||
import { TypeWithVersion } from '../../../versions/types';
|
import { TypeWithVersion } from '../../../versions/types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import findVersions from '../findVersions';
|
import findVersions from '../findVersions';
|
||||||
import { getDataLoader } from '../../dataloader';
|
import { getDataLoader } from '../../dataloader';
|
||||||
import i18nInit from '../../../translations/init';
|
import i18nInit from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -21,6 +22,11 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
|||||||
showHiddenFields?: boolean
|
showHiddenFields?: boolean
|
||||||
sort?: string
|
sort?: string
|
||||||
where?: Where
|
where?: Where
|
||||||
|
draft?: boolean
|
||||||
|
/**
|
||||||
|
* context, which will then be passed to req.context, which can be read by hooks
|
||||||
|
*/
|
||||||
|
context?: RequestContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function findVersionsLocal<T extends keyof GeneratedTypes['collections']>(
|
export default async function findVersionsLocal<T extends keyof GeneratedTypes['collections']>(
|
||||||
@@ -39,6 +45,7 @@ export default async function findVersionsLocal<T extends keyof GeneratedTypes['
|
|||||||
overrideAccess = true,
|
overrideAccess = true,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
sort,
|
sort,
|
||||||
|
context,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
@@ -57,6 +64,7 @@ export default async function findVersionsLocal<T extends keyof GeneratedTypes['
|
|||||||
payload,
|
payload,
|
||||||
i18n,
|
i18n,
|
||||||
} as PayloadRequest;
|
} as PayloadRequest;
|
||||||
|
setRequestContext(req, context);
|
||||||
|
|
||||||
if (!req.t) req.t = req.i18n.t;
|
if (!req.t) req.t = req.i18n.t;
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||||
import { Payload } from '../../../payload';
|
import { Payload } from '../../../payload';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { Document } from '../../../types';
|
import { Document } from '../../../types';
|
||||||
import { getDataLoader } from '../../dataloader';
|
import { getDataLoader } from '../../dataloader';
|
||||||
import restoreVersion from '../restoreVersion';
|
import restoreVersion from '../restoreVersion';
|
||||||
import i18nInit from '../../../translations/init';
|
import i18nInit from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -16,6 +17,11 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
|||||||
user?: Document
|
user?: Document
|
||||||
overrideAccess?: boolean
|
overrideAccess?: boolean
|
||||||
showHiddenFields?: boolean
|
showHiddenFields?: boolean
|
||||||
|
draft?: boolean
|
||||||
|
/**
|
||||||
|
* context, which will then be passed to req.context, which can be read by hooks
|
||||||
|
*/
|
||||||
|
context?: RequestContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function restoreVersionLocal<T extends keyof GeneratedTypes['collections']>(
|
export default async function restoreVersionLocal<T extends keyof GeneratedTypes['collections']>(
|
||||||
@@ -31,6 +37,7 @@ export default async function restoreVersionLocal<T extends keyof GeneratedTypes
|
|||||||
user,
|
user,
|
||||||
overrideAccess = true,
|
overrideAccess = true,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
@@ -49,6 +56,7 @@ export default async function restoreVersionLocal<T extends keyof GeneratedTypes
|
|||||||
i18n,
|
i18n,
|
||||||
t: i18n.t,
|
t: i18n.t,
|
||||||
} as PayloadRequest;
|
} as PayloadRequest;
|
||||||
|
setRequestContext(req, context);
|
||||||
|
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import { Payload } from '../../../payload';
|
|||||||
import { Document, Where } from '../../../types';
|
import { Document, Where } from '../../../types';
|
||||||
import getFileByPath from '../../../uploads/getFileByPath';
|
import getFileByPath from '../../../uploads/getFileByPath';
|
||||||
import update from '../update';
|
import update from '../update';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { getDataLoader } from '../../dataloader';
|
import { getDataLoader } from '../../dataloader';
|
||||||
import { File } from '../../../uploads/types';
|
import { File } from '../../../uploads/types';
|
||||||
import i18nInit from '../../../translations/init';
|
import i18nInit from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
import updateByID from '../updateByID';
|
import updateByID from '../updateByID';
|
||||||
import { BulkOperationResult } from '../../config/types';
|
import { BulkOperationResult } from '../../config/types';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type BaseOptions<TSlug extends keyof GeneratedTypes['collections']> = {
|
export type BaseOptions<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: TSlug
|
collection: TSlug
|
||||||
@@ -26,6 +27,10 @@ export type BaseOptions<TSlug extends keyof GeneratedTypes['collections']> = {
|
|||||||
overwriteExistingFiles?: boolean
|
overwriteExistingFiles?: boolean
|
||||||
draft?: boolean
|
draft?: boolean
|
||||||
autosave?: boolean
|
autosave?: boolean
|
||||||
|
/**
|
||||||
|
* context, which will then be passed to req.context, which can be read by hooks
|
||||||
|
*/
|
||||||
|
context?: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ByIDOptions<TSlug extends keyof GeneratedTypes['collections']> = BaseOptions<TSlug> & {
|
export type ByIDOptions<TSlug extends keyof GeneratedTypes['collections']> = BaseOptions<TSlug> & {
|
||||||
@@ -60,6 +65,7 @@ async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>(pa
|
|||||||
autosave,
|
autosave,
|
||||||
id,
|
id,
|
||||||
where,
|
where,
|
||||||
|
context,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const collection = payload.collections[collectionSlug];
|
const collection = payload.collections[collectionSlug];
|
||||||
@@ -82,6 +88,7 @@ async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>(pa
|
|||||||
file: file ?? await getFileByPath(filePath),
|
file: file ?? await getFileByPath(filePath),
|
||||||
},
|
},
|
||||||
} as PayloadRequest;
|
} as PayloadRequest;
|
||||||
|
setRequestContext(req, context);
|
||||||
|
|
||||||
if (!req.t) req.t = req.i18n.t;
|
if (!req.t) req.t = req.i18n.t;
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
|||||||
req,
|
req,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -155,6 +156,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
|||||||
result = await hook({
|
result = await hook({
|
||||||
req,
|
req,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -168,6 +170,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
|||||||
previousDoc: prevDocWithLocales,
|
previousDoc: prevDocWithLocales,
|
||||||
entityConfig: collectionConfig,
|
entityConfig: collectionConfig,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
|
context: req.context,
|
||||||
req,
|
req,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -183,6 +186,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
|||||||
req,
|
req,
|
||||||
previousDoc: prevDocWithLocales,
|
previousDoc: prevDocWithLocales,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -149,6 +150,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
req,
|
req,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
showHiddenFields: true,
|
showHiddenFields: true,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
await deleteAssociatedFiles({ config, collectionConfig, files: filesToUpload, doc: docWithLocales, t, overrideDelete: false });
|
await deleteAssociatedFiles({ config, collectionConfig, files: filesToUpload, doc: docWithLocales, t, overrideDelete: false });
|
||||||
@@ -165,6 +167,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
operation: 'update',
|
operation: 'update',
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -179,6 +182,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
req,
|
req,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
originalDoc,
|
originalDoc,
|
||||||
|
context: req.context,
|
||||||
})) || data;
|
})) || data;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -202,6 +206,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
req,
|
req,
|
||||||
originalDoc,
|
originalDoc,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
|
context: req.context,
|
||||||
})) || data;
|
})) || data;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -218,6 +223,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
operation: 'update',
|
operation: 'update',
|
||||||
req,
|
req,
|
||||||
skipValidation: shouldSaveDraft || data._status === 'draft',
|
skipValidation: shouldSaveDraft || data._status === 'draft',
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -275,6 +281,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
req,
|
req,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -287,6 +294,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
result = await hook({
|
result = await hook({
|
||||||
req,
|
req,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -301,6 +309,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
entityConfig: collectionConfig,
|
entityConfig: collectionConfig,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
req,
|
req,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -315,6 +324,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
previousDoc: originalDoc,
|
previousDoc: originalDoc,
|
||||||
req,
|
req,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
args = (await hook({
|
args = (await hook({
|
||||||
args,
|
args,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
|
context: args.req.context,
|
||||||
})) || args;
|
})) || args;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -130,6 +131,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
req,
|
req,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
showHiddenFields: true,
|
showHiddenFields: true,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -165,6 +167,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
operation: 'update',
|
operation: 'update',
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -179,6 +182,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
req,
|
req,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
originalDoc,
|
originalDoc,
|
||||||
|
context: req.context,
|
||||||
})) || data;
|
})) || data;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -202,6 +206,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
req,
|
req,
|
||||||
originalDoc,
|
originalDoc,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
|
context: req.context,
|
||||||
})) || data;
|
})) || data;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -218,18 +223,19 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
operation: 'update',
|
operation: 'update',
|
||||||
req,
|
req,
|
||||||
skipValidation: shouldSaveDraft || data._status === 'draft',
|
skipValidation: shouldSaveDraft || data._status === 'draft',
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
// Handle potential password update
|
// Handle potential password update
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const dataToUpdate: Record<string, unknown> = { ...result }
|
const dataToUpdate: Record<string, unknown> = { ...result };
|
||||||
|
|
||||||
if (shouldSavePassword && typeof password === 'string') {
|
if (shouldSavePassword && typeof password === 'string') {
|
||||||
const { hash, salt } = await generatePasswordSaltHash({ password })
|
const { hash, salt } = await generatePasswordSaltHash({ password });
|
||||||
dataToUpdate.salt = salt
|
dataToUpdate.salt = salt;
|
||||||
dataToUpdate.hash = hash
|
dataToUpdate.hash = hash;
|
||||||
delete data.password;
|
delete data.password;
|
||||||
delete result.password;
|
delete result.password;
|
||||||
}
|
}
|
||||||
@@ -287,6 +293,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
req,
|
req,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -299,6 +306,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
result = await hook({
|
result = await hook({
|
||||||
req,
|
req,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
@@ -313,6 +321,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
entityConfig: collectionConfig,
|
entityConfig: collectionConfig,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
req,
|
req,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -327,6 +336,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
previousDoc: originalDoc,
|
previousDoc: originalDoc,
|
||||||
req,
|
req,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
|
context: req.context,
|
||||||
}) || result;
|
}) || result;
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
|
|
||||||
|
|||||||
10
src/express/middleware/defaultPayload.ts
Normal file
10
src/express/middleware/defaultPayload.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import type { Response, NextFunction } from 'express';
|
||||||
|
import type { PayloadRequest } from '../types';
|
||||||
|
import { setRequestContext } from '../setRequestContext';
|
||||||
|
|
||||||
|
function defaultPayload(req: PayloadRequest, res: Response, next: NextFunction) {
|
||||||
|
setRequestContext(req);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defaultPayload;
|
||||||
@@ -21,11 +21,11 @@ const errorHandler = (config: SanitizedConfig, logger: Logger) => async (err: AP
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.collection && typeof req.collection.config.hooks.afterError === 'function') {
|
if (req.collection && typeof req.collection.config.hooks.afterError === 'function') {
|
||||||
({ response, status } = await req.collection.config.hooks.afterError(err, response) || { response, status });
|
({ response, status } = await req.collection.config.hooks.afterError(err, response, req.context) || { response, status });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof config.hooks.afterError === 'function') {
|
if (typeof config.hooks.afterError === 'function') {
|
||||||
({ response, status } = await config.hooks.afterError(err, response) || { response, status });
|
({ response, status } = await config.hooks.afterError(err, response, req.context) || { response, status });
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(status).send(response);
|
res.status(status).send(response);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { PayloadRequest } from '../types';
|
|||||||
import corsHeaders from './corsHeaders';
|
import corsHeaders from './corsHeaders';
|
||||||
import convertPayload from './convertPayload';
|
import convertPayload from './convertPayload';
|
||||||
import { i18nMiddleware } from './i18n';
|
import { i18nMiddleware } from './i18n';
|
||||||
|
import defaultPayload from './defaultPayload';
|
||||||
|
|
||||||
const middleware = (payload: Payload): any => {
|
const middleware = (payload: Payload): any => {
|
||||||
const rateLimitOptions: {
|
const rateLimitOptions: {
|
||||||
@@ -32,6 +33,7 @@ const middleware = (payload: Payload): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
defaultPayload,
|
||||||
...(payload.config.express.preMiddleware || []),
|
...(payload.config.express.preMiddleware || []),
|
||||||
rateLimit(rateLimitOptions),
|
rateLimit(rateLimitOptions),
|
||||||
passport.initialize(),
|
passport.initialize(),
|
||||||
|
|||||||
18
src/express/setRequestContext.ts
Normal file
18
src/express/setRequestContext.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
import type { PayloadRequest, RequestContext } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This makes sure that req.context always exists (is {}) and populates it with an optional default context.
|
||||||
|
* This function mutates directly to avoid copying memory. As payloadRequest is not a primitive, the scope of the mutation is not limited to this function but should also be reflected in the calling function.
|
||||||
|
*/
|
||||||
|
export function setRequestContext(req: PayloadRequest = { context: null } as PayloadRequest, context: RequestContext = {}) {
|
||||||
|
if (req.context) {
|
||||||
|
if (Object.keys(req.context).length === 0 && req.context.constructor === Object) { // check if req.context is just {}
|
||||||
|
req.context = context; // Faster - ... is bad for performance
|
||||||
|
} else {
|
||||||
|
req.context = { ...req.context, ...context }; // Merge together
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
req.context = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,10 +24,16 @@ export declare type PayloadRequest<U = any> = Request & {
|
|||||||
* - Configuration from payload-config.ts
|
* - Configuration from payload-config.ts
|
||||||
* - MongoDB model for this collection
|
* - MongoDB model for this collection
|
||||||
* - GraphQL type metadata
|
* - GraphQL type metadata
|
||||||
* */
|
*/
|
||||||
collection?: Collection;
|
collection?: Collection;
|
||||||
/** What triggered this request */
|
/** What triggered this request */
|
||||||
payloadAPI?: 'REST' | 'local' | 'GraphQL';
|
payloadAPI?: 'REST' | 'local' | 'GraphQL';
|
||||||
|
/** context allows you to pass your own data to the request object as context
|
||||||
|
* This is useful for, for example, passing data from a beforeChange hook to an afterChange hook.
|
||||||
|
* payoadContext can also be fully typed using declare module
|
||||||
|
* {@link https://payloadcms.com/docs/hooks/context More info in the Payload Documentation}.
|
||||||
|
*/
|
||||||
|
context: RequestContext;
|
||||||
/** Uploaded files */
|
/** Uploaded files */
|
||||||
files?: {
|
files?: {
|
||||||
/**
|
/**
|
||||||
@@ -49,3 +55,7 @@ export declare type PayloadRequest<U = any> = Request & {
|
|||||||
[slug: string]: (q: unknown) => Document;
|
[slug: string]: (q: unknown) => Document;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface RequestContext {
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { EditorProps } from '@monaco-editor/react';
|
|||||||
import { Operation, Where } from '../../types';
|
import { Operation, Where } from '../../types';
|
||||||
import { SanitizedConfig } from '../../config/types';
|
import { SanitizedConfig } from '../../config/types';
|
||||||
import { TypeWithID } from '../../collections/config/types';
|
import { TypeWithID } from '../../collections/config/types';
|
||||||
import { PayloadRequest } from '../../express/types';
|
import { PayloadRequest, RequestContext } from '../../express/types';
|
||||||
import { ConditionalDateProps } from '../../admin/components/elements/DatePicker/types';
|
import { ConditionalDateProps } from '../../admin/components/elements/DatePicker/types';
|
||||||
import { Description } from '../../admin/components/forms/FieldDescription/types';
|
import { Description } from '../../admin/components/forms/FieldDescription/types';
|
||||||
import { User } from '../../auth';
|
import { User } from '../../auth';
|
||||||
@@ -33,6 +33,7 @@ export type FieldHookArgs<T extends TypeWithID = any, P = any, S = any> = {
|
|||||||
/** The value of the field. */
|
/** The value of the field. */
|
||||||
value?: P,
|
value?: P,
|
||||||
previousValue?: P,
|
previousValue?: P,
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FieldHook<T extends TypeWithID = any, P = any, S = any> = (args: FieldHookArgs<T, P, S>) => Promise<P> | P;
|
export type FieldHook<T extends TypeWithID = any, P = any, S = any> = (args: FieldHookArgs<T, P, S>) => Promise<P> | P;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SanitizedCollectionConfig } from '../../../collections/config/types';
|
import { SanitizedCollectionConfig } from '../../../collections/config/types';
|
||||||
import { SanitizedGlobalConfig } from '../../../globals/config/types';
|
import { SanitizedGlobalConfig } from '../../../globals/config/types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { traverseFields } from './traverseFields';
|
import { traverseFields } from './traverseFields';
|
||||||
import deepCopyObject from '../../../utilities/deepCopyObject';
|
import deepCopyObject from '../../../utilities/deepCopyObject';
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ type Args<T> = {
|
|||||||
entityConfig: SanitizedCollectionConfig | SanitizedGlobalConfig
|
entityConfig: SanitizedCollectionConfig | SanitizedGlobalConfig
|
||||||
operation: 'create' | 'update'
|
operation: 'create' | 'update'
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export const afterChange = async <T extends Record<string, unknown>>({
|
export const afterChange = async <T extends Record<string, unknown>>({
|
||||||
@@ -20,6 +21,7 @@ export const afterChange = async <T extends Record<string, unknown>>({
|
|||||||
entityConfig,
|
entityConfig,
|
||||||
operation,
|
operation,
|
||||||
req,
|
req,
|
||||||
|
context,
|
||||||
}: Args<T>): Promise<T> => {
|
}: Args<T>): Promise<T> => {
|
||||||
const doc = deepCopyObject(incomingDoc);
|
const doc = deepCopyObject(incomingDoc);
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ export const afterChange = async <T extends Record<string, unknown>>({
|
|||||||
previousSiblingDoc: previousDoc,
|
previousSiblingDoc: previousDoc,
|
||||||
siblingDoc: doc,
|
siblingDoc: doc,
|
||||||
siblingData: data,
|
siblingData: data,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { Field, fieldAffectsData, TabAsField, tabHasName } from '../../config/types';
|
import { Field, fieldAffectsData, TabAsField, tabHasName } from '../../config/types';
|
||||||
import { traverseFields } from './traverseFields';
|
import { traverseFields } from './traverseFields';
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@ type Args = {
|
|||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
siblingData: Record<string, unknown>
|
siblingData: Record<string, unknown>
|
||||||
siblingDoc: Record<string, unknown>
|
siblingDoc: Record<string, unknown>
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is responsible for the following actions, in order:
|
// This function is responsible for the following actions, in order:
|
||||||
@@ -28,6 +29,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingData,
|
siblingData,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
|
context,
|
||||||
}: Args): Promise<void> => {
|
}: Args): Promise<void> => {
|
||||||
if (fieldAffectsData(field)) {
|
if (fieldAffectsData(field)) {
|
||||||
// Execute hooks
|
// Execute hooks
|
||||||
@@ -45,6 +47,7 @@ export const promise = async ({
|
|||||||
siblingData,
|
siblingData,
|
||||||
operation,
|
operation,
|
||||||
req,
|
req,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hookedValue !== undefined) {
|
if (hookedValue !== undefined) {
|
||||||
@@ -67,6 +70,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingData: siblingData?.[field.name] as Record<string, unknown> || {},
|
siblingData: siblingData?.[field.name] as Record<string, unknown> || {},
|
||||||
siblingDoc: siblingDoc[field.name] as Record<string, unknown>,
|
siblingDoc: siblingDoc[field.name] as Record<string, unknown>,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -88,6 +92,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingData: siblingData?.[field.name]?.[i] || {},
|
siblingData: siblingData?.[field.name]?.[i] || {},
|
||||||
siblingDoc: { ...row } || {},
|
siblingDoc: { ...row } || {},
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
@@ -114,6 +119,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingData: siblingData?.[field.name]?.[i] || {},
|
siblingData: siblingData?.[field.name]?.[i] || {},
|
||||||
siblingDoc: { ...row } || {},
|
siblingDoc: { ...row } || {},
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -135,6 +141,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingData: siblingData || {},
|
siblingData: siblingData || {},
|
||||||
siblingDoc: { ...siblingDoc },
|
siblingDoc: { ...siblingDoc },
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -161,6 +168,7 @@ export const promise = async ({
|
|||||||
previousDoc,
|
previousDoc,
|
||||||
siblingData: tabSiblingData,
|
siblingData: tabSiblingData,
|
||||||
siblingDoc: tabSiblingDoc,
|
siblingDoc: tabSiblingDoc,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -177,6 +185,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingData: siblingData || {},
|
siblingData: siblingData || {},
|
||||||
siblingDoc: { ...siblingDoc },
|
siblingDoc: { ...siblingDoc },
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Field, TabAsField } from '../../config/types';
|
import { Field, TabAsField } from '../../config/types';
|
||||||
import { promise } from './promise';
|
import { promise } from './promise';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
data: Record<string, unknown>
|
data: Record<string, unknown>
|
||||||
@@ -12,6 +12,7 @@ type Args = {
|
|||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
siblingData: Record<string, unknown>
|
siblingData: Record<string, unknown>
|
||||||
siblingDoc: Record<string, unknown>
|
siblingDoc: Record<string, unknown>
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export const traverseFields = async ({
|
export const traverseFields = async ({
|
||||||
@@ -24,6 +25,7 @@ export const traverseFields = async ({
|
|||||||
req,
|
req,
|
||||||
siblingData,
|
siblingData,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
|
context,
|
||||||
}: Args): Promise<void> => {
|
}: Args): Promise<void> => {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
@@ -38,6 +40,7 @@ export const traverseFields = async ({
|
|||||||
req,
|
req,
|
||||||
siblingData,
|
siblingData,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SanitizedCollectionConfig } from '../../../collections/config/types';
|
import { SanitizedCollectionConfig } from '../../../collections/config/types';
|
||||||
import { SanitizedGlobalConfig } from '../../../globals/config/types';
|
import { SanitizedGlobalConfig } from '../../../globals/config/types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { traverseFields } from './traverseFields';
|
import { traverseFields } from './traverseFields';
|
||||||
import deepCopyObject from '../../../utilities/deepCopyObject';
|
import deepCopyObject from '../../../utilities/deepCopyObject';
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@ type Args = {
|
|||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
showHiddenFields: boolean
|
showHiddenFields: boolean
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function afterRead<T = any>(args: Args): Promise<T> {
|
export async function afterRead<T = any>(args: Args): Promise<T> {
|
||||||
@@ -27,6 +28,7 @@ export async function afterRead<T = any>(args: Args): Promise<T> {
|
|||||||
req,
|
req,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
const doc = deepCopyObject(incomingDoc);
|
const doc = deepCopyObject(incomingDoc);
|
||||||
@@ -51,6 +53,7 @@ export async function afterRead<T = any>(args: Args): Promise<T> {
|
|||||||
req,
|
req,
|
||||||
siblingDoc: doc,
|
siblingDoc: doc,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(fieldPromises);
|
await Promise.all(fieldPromises);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import { Field, fieldAffectsData, TabAsField, tabHasName } from '../../config/types';
|
import { Field, fieldAffectsData, TabAsField, tabHasName } from '../../config/types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { traverseFields } from './traverseFields';
|
import { traverseFields } from './traverseFields';
|
||||||
import richTextRelationshipPromise from '../../richText/richTextRelationshipPromise';
|
import richTextRelationshipPromise from '../../richText/richTextRelationshipPromise';
|
||||||
import relationshipPopulationPromise from './relationshipPopulationPromise';
|
import relationshipPopulationPromise from './relationshipPopulationPromise';
|
||||||
@@ -18,6 +18,7 @@ type Args = {
|
|||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
siblingDoc: Record<string, unknown>
|
siblingDoc: Record<string, unknown>
|
||||||
showHiddenFields: boolean
|
showHiddenFields: boolean
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is responsible for the following actions, in order:
|
// This function is responsible for the following actions, in order:
|
||||||
@@ -41,6 +42,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
}: Args): Promise<void> => {
|
}: Args): Promise<void> => {
|
||||||
if (fieldAffectsData(field) && field.hidden && typeof siblingDoc[field.name] !== 'undefined' && !showHiddenFields) {
|
if (fieldAffectsData(field) && field.hidden && typeof siblingDoc[field.name] !== 'undefined' && !showHiddenFields) {
|
||||||
delete siblingDoc[field.name];
|
delete siblingDoc[field.name];
|
||||||
@@ -161,6 +163,7 @@ export const promise = async ({
|
|||||||
siblingData: siblingDoc,
|
siblingData: siblingDoc,
|
||||||
operation: 'read',
|
operation: 'read',
|
||||||
req,
|
req,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hookedValue !== undefined) {
|
if (hookedValue !== undefined) {
|
||||||
@@ -178,6 +181,7 @@ export const promise = async ({
|
|||||||
siblingData: siblingDoc,
|
siblingData: siblingDoc,
|
||||||
req,
|
req,
|
||||||
value: siblingDoc[field.name],
|
value: siblingDoc[field.name],
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hookedValue !== undefined) {
|
if (hookedValue !== undefined) {
|
||||||
@@ -227,6 +231,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc: groupDoc,
|
siblingDoc: groupDoc,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -250,6 +255,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc: row || {},
|
siblingDoc: row || {},
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else if (!shouldHoistLocalizedValue && typeof rows === 'object' && rows !== null) {
|
} else if (!shouldHoistLocalizedValue && typeof rows === 'object' && rows !== null) {
|
||||||
@@ -269,6 +275,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc: row || {},
|
siblingDoc: row || {},
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -298,6 +305,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc: row || {},
|
siblingDoc: row || {},
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -321,6 +329,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc: row || {},
|
siblingDoc: row || {},
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -346,6 +355,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -371,6 +381,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc: tabDoc,
|
siblingDoc: tabDoc,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -390,6 +401,7 @@ export const promise = async ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Field, TabAsField } from '../../config/types';
|
import { Field, TabAsField } from '../../config/types';
|
||||||
import { promise } from './promise';
|
import { promise } from './promise';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
currentDepth: number
|
currentDepth: number
|
||||||
@@ -15,6 +15,7 @@ type Args = {
|
|||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
siblingDoc: Record<string, unknown>
|
siblingDoc: Record<string, unknown>
|
||||||
showHiddenFields: boolean
|
showHiddenFields: boolean
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export const traverseFields = ({
|
export const traverseFields = ({
|
||||||
@@ -30,6 +31,7 @@ export const traverseFields = ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
}: Args): void => {
|
}: Args): void => {
|
||||||
fields.forEach((field) => {
|
fields.forEach((field) => {
|
||||||
fieldPromises.push(promise({
|
fieldPromises.push(promise({
|
||||||
@@ -45,6 +47,7 @@ export const traverseFields = ({
|
|||||||
req,
|
req,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { SanitizedCollectionConfig } from '../../../collections/config/types';
|
import { SanitizedCollectionConfig } from '../../../collections/config/types';
|
||||||
import { SanitizedGlobalConfig } from '../../../globals/config/types';
|
import { SanitizedGlobalConfig } from '../../../globals/config/types';
|
||||||
import { Operation } from '../../../types';
|
import { Operation } from '../../../types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { traverseFields } from './traverseFields';
|
import { traverseFields } from './traverseFields';
|
||||||
import { ValidationError } from '../../../errors';
|
import { ValidationError } from '../../../errors';
|
||||||
import deepCopyObject from '../../../utilities/deepCopyObject';
|
import deepCopyObject from '../../../utilities/deepCopyObject';
|
||||||
@@ -15,6 +15,7 @@ type Args<T> = {
|
|||||||
operation: Operation
|
operation: Operation
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
skipValidation?: boolean
|
skipValidation?: boolean
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export const beforeChange = async <T extends Record<string, unknown>>({
|
export const beforeChange = async <T extends Record<string, unknown>>({
|
||||||
@@ -26,6 +27,7 @@ export const beforeChange = async <T extends Record<string, unknown>>({
|
|||||||
operation,
|
operation,
|
||||||
req,
|
req,
|
||||||
skipValidation,
|
skipValidation,
|
||||||
|
context,
|
||||||
}: Args<T>): Promise<T> => {
|
}: Args<T>): Promise<T> => {
|
||||||
const data = deepCopyObject(incomingData);
|
const data = deepCopyObject(incomingData);
|
||||||
const mergeLocaleActions = [];
|
const mergeLocaleActions = [];
|
||||||
@@ -46,6 +48,7 @@ export const beforeChange = async <T extends Record<string, unknown>>({
|
|||||||
siblingDocWithLocales: docWithLocales,
|
siblingDocWithLocales: docWithLocales,
|
||||||
fields: entityConfig.fields,
|
fields: entityConfig.fields,
|
||||||
skipValidation,
|
skipValidation,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import merge from 'deepmerge';
|
import merge from 'deepmerge';
|
||||||
import { Field, fieldAffectsData, TabAsField, tabHasName } from '../../config/types';
|
import { Field, fieldAffectsData, TabAsField, tabHasName } from '../../config/types';
|
||||||
import { Operation } from '../../../types';
|
import { Operation } from '../../../types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import getValueWithDefault from '../../getDefaultValue';
|
import getValueWithDefault from '../../getDefaultValue';
|
||||||
import { traverseFields } from './traverseFields';
|
import { traverseFields } from './traverseFields';
|
||||||
import { getExistingRowDoc } from './getExistingRowDoc';
|
import { getExistingRowDoc } from './getExistingRowDoc';
|
||||||
@@ -23,6 +23,7 @@ type Args = {
|
|||||||
siblingDoc: Record<string, unknown>
|
siblingDoc: Record<string, unknown>
|
||||||
siblingDocWithLocales?: Record<string, unknown>
|
siblingDocWithLocales?: Record<string, unknown>
|
||||||
skipValidation: boolean
|
skipValidation: boolean
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is responsible for the following actions, in order:
|
// This function is responsible for the following actions, in order:
|
||||||
@@ -49,6 +50,7 @@ export const promise = async ({
|
|||||||
siblingDoc,
|
siblingDoc,
|
||||||
siblingDocWithLocales,
|
siblingDocWithLocales,
|
||||||
skipValidation,
|
skipValidation,
|
||||||
|
context,
|
||||||
}: Args): Promise<void> => {
|
}: Args): Promise<void> => {
|
||||||
const passesCondition = (field.admin?.condition) ? field.admin.condition(data, siblingData, { user: req.user }) : true;
|
const passesCondition = (field.admin?.condition) ? field.admin.condition(data, siblingData, { user: req.user }) : true;
|
||||||
let skipValidationFromHere = skipValidation || !passesCondition;
|
let skipValidationFromHere = skipValidation || !passesCondition;
|
||||||
@@ -96,6 +98,7 @@ export const promise = async ({
|
|||||||
siblingData,
|
siblingData,
|
||||||
operation,
|
operation,
|
||||||
req,
|
req,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hookedValue !== undefined) {
|
if (hookedValue !== undefined) {
|
||||||
@@ -208,6 +211,7 @@ export const promise = async ({
|
|||||||
siblingDoc: siblingDoc[field.name] as Record<string, unknown>,
|
siblingDoc: siblingDoc[field.name] as Record<string, unknown>,
|
||||||
siblingDocWithLocales: siblingDocWithLocales[field.name] as Record<string, unknown>,
|
siblingDocWithLocales: siblingDocWithLocales[field.name] as Record<string, unknown>,
|
||||||
skipValidation: skipValidationFromHere,
|
skipValidation: skipValidationFromHere,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -234,6 +238,7 @@ export const promise = async ({
|
|||||||
siblingDoc: getExistingRowDoc(row, siblingDoc[field.name]),
|
siblingDoc: getExistingRowDoc(row, siblingDoc[field.name]),
|
||||||
siblingDocWithLocales: getExistingRowDoc(row, siblingDocWithLocales[field.name]),
|
siblingDocWithLocales: getExistingRowDoc(row, siblingDocWithLocales[field.name]),
|
||||||
skipValidation: skipValidationFromHere,
|
skipValidation: skipValidationFromHere,
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -267,6 +272,7 @@ export const promise = async ({
|
|||||||
siblingDoc: getExistingRowDoc(row, siblingDoc[field.name]),
|
siblingDoc: getExistingRowDoc(row, siblingDoc[field.name]),
|
||||||
siblingDocWithLocales: getExistingRowDoc(row, siblingDocWithLocales[field.name]),
|
siblingDocWithLocales: getExistingRowDoc(row, siblingDocWithLocales[field.name]),
|
||||||
skipValidation: skipValidationFromHere,
|
skipValidation: skipValidationFromHere,
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -294,6 +300,7 @@ export const promise = async ({
|
|||||||
siblingDoc,
|
siblingDoc,
|
||||||
siblingDocWithLocales,
|
siblingDocWithLocales,
|
||||||
skipValidation: skipValidationFromHere,
|
skipValidation: skipValidationFromHere,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -331,6 +338,7 @@ export const promise = async ({
|
|||||||
siblingDoc: tabSiblingDoc,
|
siblingDoc: tabSiblingDoc,
|
||||||
siblingDocWithLocales: tabSiblingDocWithLocales,
|
siblingDocWithLocales: tabSiblingDocWithLocales,
|
||||||
skipValidation: skipValidationFromHere,
|
skipValidation: skipValidationFromHere,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -352,6 +360,7 @@ export const promise = async ({
|
|||||||
siblingDoc,
|
siblingDoc,
|
||||||
siblingDocWithLocales,
|
siblingDocWithLocales,
|
||||||
skipValidation: skipValidationFromHere,
|
skipValidation: skipValidationFromHere,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Field, TabAsField } from '../../config/types';
|
import { Field, TabAsField } from '../../config/types';
|
||||||
import { promise } from './promise';
|
import { promise } from './promise';
|
||||||
import { Operation } from '../../../types';
|
import { Operation } from '../../../types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
data: Record<string, unknown>
|
data: Record<string, unknown>
|
||||||
@@ -18,6 +18,7 @@ type Args = {
|
|||||||
siblingDoc: Record<string, unknown>
|
siblingDoc: Record<string, unknown>
|
||||||
siblingDocWithLocales: Record<string, unknown>
|
siblingDocWithLocales: Record<string, unknown>
|
||||||
skipValidation?: boolean
|
skipValidation?: boolean
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export const traverseFields = async ({
|
export const traverseFields = async ({
|
||||||
@@ -35,6 +36,7 @@ export const traverseFields = async ({
|
|||||||
siblingDoc,
|
siblingDoc,
|
||||||
siblingDocWithLocales,
|
siblingDocWithLocales,
|
||||||
skipValidation,
|
skipValidation,
|
||||||
|
context,
|
||||||
}: Args): Promise<void> => {
|
}: Args): Promise<void> => {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
@@ -54,6 +56,7 @@ export const traverseFields = async ({
|
|||||||
siblingDoc,
|
siblingDoc,
|
||||||
siblingDocWithLocales,
|
siblingDocWithLocales,
|
||||||
skipValidation,
|
skipValidation,
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SanitizedCollectionConfig } from '../../../collections/config/types';
|
import { SanitizedCollectionConfig } from '../../../collections/config/types';
|
||||||
import { SanitizedGlobalConfig } from '../../../globals/config/types';
|
import { SanitizedGlobalConfig } from '../../../globals/config/types';
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { traverseFields } from './traverseFields';
|
import { traverseFields } from './traverseFields';
|
||||||
import deepCopyObject from '../../../utilities/deepCopyObject';
|
import deepCopyObject from '../../../utilities/deepCopyObject';
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ type Args<T> = {
|
|||||||
operation: 'create' | 'update'
|
operation: 'create' | 'update'
|
||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export const beforeValidate = async <T extends Record<string, unknown>>({
|
export const beforeValidate = async <T extends Record<string, unknown>>({
|
||||||
@@ -22,6 +23,7 @@ export const beforeValidate = async <T extends Record<string, unknown>>({
|
|||||||
operation,
|
operation,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
|
context,
|
||||||
}: Args<T>): Promise<T> => {
|
}: Args<T>): Promise<T> => {
|
||||||
const data = deepCopyObject(incomingData);
|
const data = deepCopyObject(incomingData);
|
||||||
|
|
||||||
@@ -35,6 +37,7 @@ export const beforeValidate = async <T extends Record<string, unknown>>({
|
|||||||
req,
|
req,
|
||||||
siblingData: data,
|
siblingData: data,
|
||||||
siblingDoc: doc,
|
siblingDoc: doc,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { Field, fieldAffectsData, TabAsField, tabHasName, valueIsValueWithRelation } from '../../config/types';
|
import { Field, fieldAffectsData, TabAsField, tabHasName, valueIsValueWithRelation } from '../../config/types';
|
||||||
import { traverseFields } from './traverseFields';
|
import { traverseFields } from './traverseFields';
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@ type Args<T> = {
|
|||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
siblingData: Record<string, unknown>
|
siblingData: Record<string, unknown>
|
||||||
siblingDoc: Record<string, unknown>
|
siblingDoc: Record<string, unknown>
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is responsible for the following actions, in order:
|
// This function is responsible for the following actions, in order:
|
||||||
@@ -30,6 +31,7 @@ export const promise = async <T>({
|
|||||||
req,
|
req,
|
||||||
siblingData,
|
siblingData,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
|
context,
|
||||||
}: Args<T>): Promise<void> => {
|
}: Args<T>): Promise<void> => {
|
||||||
if (fieldAffectsData(field)) {
|
if (fieldAffectsData(field)) {
|
||||||
if (field.name === 'id') {
|
if (field.name === 'id') {
|
||||||
@@ -170,6 +172,7 @@ export const promise = async <T>({
|
|||||||
siblingData,
|
siblingData,
|
||||||
operation,
|
operation,
|
||||||
req,
|
req,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hookedValue !== undefined) {
|
if (hookedValue !== undefined) {
|
||||||
@@ -207,6 +210,7 @@ export const promise = async <T>({
|
|||||||
req,
|
req,
|
||||||
siblingData: groupData,
|
siblingData: groupData,
|
||||||
siblingDoc: groupDoc,
|
siblingDoc: groupDoc,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -228,6 +232,7 @@ export const promise = async <T>({
|
|||||||
req,
|
req,
|
||||||
siblingData: row,
|
siblingData: row,
|
||||||
siblingDoc: siblingDoc[field.name]?.[i] || {},
|
siblingDoc: siblingDoc[field.name]?.[i] || {},
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
@@ -254,6 +259,7 @@ export const promise = async <T>({
|
|||||||
req,
|
req,
|
||||||
siblingData: row,
|
siblingData: row,
|
||||||
siblingDoc: siblingDoc[field.name]?.[i] || {},
|
siblingDoc: siblingDoc[field.name]?.[i] || {},
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -275,6 +281,7 @@ export const promise = async <T>({
|
|||||||
req,
|
req,
|
||||||
siblingData,
|
siblingData,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -301,6 +308,7 @@ export const promise = async <T>({
|
|||||||
req,
|
req,
|
||||||
siblingData: tabSiblingData,
|
siblingData: tabSiblingData,
|
||||||
siblingDoc: tabSiblingDoc,
|
siblingDoc: tabSiblingDoc,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -317,6 +325,7 @@ export const promise = async <T>({
|
|||||||
req,
|
req,
|
||||||
siblingData,
|
siblingData,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
|
context,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PayloadRequest } from '../../../express/types';
|
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||||
import { Field, TabAsField } from '../../config/types';
|
import { Field, TabAsField } from '../../config/types';
|
||||||
import { promise } from './promise';
|
import { promise } from './promise';
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ type Args<T> = {
|
|||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
siblingData: Record<string, unknown>
|
siblingData: Record<string, unknown>
|
||||||
siblingDoc: Record<string, unknown>
|
siblingDoc: Record<string, unknown>
|
||||||
|
context: RequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export const traverseFields = async <T>({
|
export const traverseFields = async <T>({
|
||||||
@@ -24,6 +25,7 @@ export const traverseFields = async <T>({
|
|||||||
req,
|
req,
|
||||||
siblingData,
|
siblingData,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
|
context,
|
||||||
}: Args<T>): Promise<void> => {
|
}: Args<T>): Promise<void> => {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
fields.forEach((field) => {
|
fields.forEach((field) => {
|
||||||
@@ -37,6 +39,7 @@ export const traverseFields = async <T>({
|
|||||||
req,
|
req,
|
||||||
siblingData,
|
siblingData,
|
||||||
siblingDoc,
|
siblingDoc,
|
||||||
|
context,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T
|
|||||||
req,
|
req,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
|||||||
req,
|
req,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
findMany: true,
|
findMany: true,
|
||||||
|
context: req.context,
|
||||||
}),
|
}),
|
||||||
}))),
|
}))),
|
||||||
} as PaginatedDocs<T>;
|
} as PaginatedDocs<T>;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Document } from '../../../types';
|
|||||||
import findOne from '../findOne';
|
import findOne from '../findOne';
|
||||||
import i18nInit from '../../../translations/init';
|
import i18nInit from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['globals']> = {
|
export type Options<T extends keyof GeneratedTypes['globals']> = {
|
||||||
slug: T
|
slug: T
|
||||||
@@ -50,6 +51,7 @@ export default async function findOneLocal<T extends keyof GeneratedTypes['globa
|
|||||||
i18n,
|
i18n,
|
||||||
t: i18n.t,
|
t: i18n.t,
|
||||||
} as PayloadRequest;
|
} as PayloadRequest;
|
||||||
|
setRequestContext(req);
|
||||||
|
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { TypeWithVersion } from '../../../versions/types';
|
|||||||
import findVersionByID from '../findVersionByID';
|
import findVersionByID from '../findVersionByID';
|
||||||
import i18nInit from '../../../translations/init';
|
import i18nInit from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['globals']> = {
|
export type Options<T extends keyof GeneratedTypes['globals']> = {
|
||||||
slug: T
|
slug: T
|
||||||
@@ -52,6 +53,7 @@ export default async function findVersionByIDLocal<T extends keyof GeneratedType
|
|||||||
i18n,
|
i18n,
|
||||||
t: i18n.t,
|
t: i18n.t,
|
||||||
} as PayloadRequest;
|
} as PayloadRequest;
|
||||||
|
setRequestContext(req);
|
||||||
|
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { getDataLoader } from '../../../collections/dataloader';
|
|||||||
import i18nInit from '../../../translations/init';
|
import i18nInit from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
import { TypeWithVersion } from '../../../versions/types';
|
import { TypeWithVersion } from '../../../versions/types';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['globals']> = {
|
export type Options<T extends keyof GeneratedTypes['globals']> = {
|
||||||
slug: T
|
slug: T
|
||||||
@@ -57,6 +58,7 @@ export default async function findVersionsLocal<T extends keyof GeneratedTypes['
|
|||||||
i18n,
|
i18n,
|
||||||
t: i18n.t,
|
t: i18n.t,
|
||||||
} as PayloadRequest;
|
} as PayloadRequest;
|
||||||
|
setRequestContext(req);
|
||||||
|
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Document } from '../../../types';
|
|||||||
import restoreVersion from '../restoreVersion';
|
import restoreVersion from '../restoreVersion';
|
||||||
import i18nInit from '../../../translations/init';
|
import i18nInit from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['globals']> = {
|
export type Options<T extends keyof GeneratedTypes['globals']> = {
|
||||||
slug: string
|
slug: string
|
||||||
@@ -49,6 +50,7 @@ export default async function restoreVersionLocal<T extends keyof GeneratedTypes
|
|||||||
i18n,
|
i18n,
|
||||||
t: i18n.t,
|
t: i18n.t,
|
||||||
} as PayloadRequest;
|
} as PayloadRequest;
|
||||||
|
setRequestContext(req);
|
||||||
|
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import update from '../update';
|
|||||||
import { getDataLoader } from '../../../collections/dataloader';
|
import { getDataLoader } from '../../../collections/dataloader';
|
||||||
import i18nInit from '../../../translations/init';
|
import i18nInit from '../../../translations/init';
|
||||||
import { APIError } from '../../../errors';
|
import { APIError } from '../../../errors';
|
||||||
|
import { setRequestContext } from '../../../express/setRequestContext';
|
||||||
|
|
||||||
export type Options<TSlug extends keyof GeneratedTypes['globals']> = {
|
export type Options<TSlug extends keyof GeneratedTypes['globals']> = {
|
||||||
slug: TSlug
|
slug: TSlug
|
||||||
@@ -52,6 +53,7 @@ export default async function updateLocal<TSlug extends keyof GeneratedTypes['gl
|
|||||||
i18n,
|
i18n,
|
||||||
t: i18n.t,
|
t: i18n.t,
|
||||||
} as PayloadRequest;
|
} as PayloadRequest;
|
||||||
|
setRequestContext(req);
|
||||||
|
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
|||||||
req,
|
req,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -132,6 +133,7 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
|||||||
entityConfig: globalConfig,
|
entityConfig: globalConfig,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
req,
|
req,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
req,
|
req,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -113,6 +114,7 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
operation: 'update',
|
operation: 'update',
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -155,6 +157,7 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
operation: 'update',
|
operation: 'update',
|
||||||
req,
|
req,
|
||||||
skipValidation: shouldSaveDraft,
|
skipValidation: shouldSaveDraft,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -207,6 +210,7 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
req,
|
req,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
context: req.context,
|
||||||
});
|
});
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -232,6 +236,7 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
previousDoc: originalDoc,
|
previousDoc: originalDoc,
|
||||||
entityConfig: globalConfig,
|
entityConfig: globalConfig,
|
||||||
operation: 'update',
|
operation: 'update',
|
||||||
|
context: req.context,
|
||||||
req,
|
req,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const errorHandler = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (afterErrorHook) {
|
if (afterErrorHook) {
|
||||||
({ response } = await afterErrorHook(err, response) || { response });
|
({ response } = await afterErrorHook(err, response, null) || { response });
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { InitOptions } from './config/types';
|
|||||||
import { initHTTP } from './initHTTP';
|
import { initHTTP } from './initHTTP';
|
||||||
import { Payload as LocalPayload, BasePayload } from './payload';
|
import { Payload as LocalPayload, BasePayload } from './payload';
|
||||||
|
|
||||||
|
import type { RequestContext } from './express/types';
|
||||||
|
|
||||||
export { getPayload } from './payload';
|
export { getPayload } from './payload';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
@@ -25,3 +27,5 @@ const payload = new Payload();
|
|||||||
|
|
||||||
export default payload;
|
export default payload;
|
||||||
module.exports = payload;
|
module.exports = payload;
|
||||||
|
// Export RequestContext type
|
||||||
|
export type { RequestContext };
|
||||||
|
|||||||
68
test/hooks/collections/ContextHooks/index.ts
Normal file
68
test/hooks/collections/ContextHooks/index.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
import payload from '../../../../src';
|
||||||
|
import { CollectionConfig } from '../../../../src/collections/config/types';
|
||||||
|
import type { PayloadRequest } from '../../../../src/types';
|
||||||
|
|
||||||
|
export const contextHooksSlug = 'context-hooks';
|
||||||
|
const ContextHooks: CollectionConfig = {
|
||||||
|
slug: contextHooksSlug,
|
||||||
|
access: {
|
||||||
|
read: () => true,
|
||||||
|
create: () => true,
|
||||||
|
delete: () => true,
|
||||||
|
update: () => true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
beforeOperation: [async ({ context, args }) => {
|
||||||
|
// eslint-disable-next-line prefer-destructuring
|
||||||
|
const req: PayloadRequest = args.req;
|
||||||
|
|
||||||
|
if (!req.query || !Object.keys(req.query).length) {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(req.query).forEach((key) => {
|
||||||
|
if (key.startsWith('context_')) {
|
||||||
|
// Strip 'context_' from key, add it to context object and remove it from query params
|
||||||
|
const newKey = key.substring('context_'.length);
|
||||||
|
context[newKey] = req.query[key];
|
||||||
|
delete req.query[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}],
|
||||||
|
beforeChange: [({ context, data, req }) => {
|
||||||
|
if (!context.secretValue) {
|
||||||
|
context.secretValue = 'secret';
|
||||||
|
}
|
||||||
|
if (req.context !== context) {
|
||||||
|
throw new Error('req.context !== context');
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}],
|
||||||
|
afterChange: [async ({ context, doc }) => {
|
||||||
|
if (context.triggerAfterChange === false) { // Make sure we don't trigger afterChange again and again in an infinite loop
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await payload.update({
|
||||||
|
collection: contextHooksSlug,
|
||||||
|
id: doc.id,
|
||||||
|
data: {
|
||||||
|
value: context.secretValue ?? '',
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
triggerAfterChange: false, // Make sure we don't trigger afterChange again and again in an infinite loop. This should be done via context and not a potential disableHooks property, as we want to specifically test the context functionality here
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'value',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ContextHooks;
|
||||||
@@ -5,9 +5,11 @@ import NestedAfterReadHooks from './collections/NestedAfterReadHooks';
|
|||||||
import ChainingHooks from './collections/ChainingHooks';
|
import ChainingHooks from './collections/ChainingHooks';
|
||||||
import Relations from './collections/Relations';
|
import Relations from './collections/Relations';
|
||||||
import Users, { seedHooksUsers } from './collections/Users';
|
import Users, { seedHooksUsers } from './collections/Users';
|
||||||
|
import ContextHooks from './collections/ContextHooks';
|
||||||
|
|
||||||
export default buildConfigWithDefaults({
|
export default buildConfigWithDefaults({
|
||||||
collections: [
|
collections: [
|
||||||
|
ContextHooks,
|
||||||
TransformHooks,
|
TransformHooks,
|
||||||
Hooks,
|
Hooks,
|
||||||
NestedAfterReadHooks,
|
NestedAfterReadHooks,
|
||||||
|
|||||||
@@ -12,13 +12,16 @@ import type { NestedAfterReadHook } from './payload-types';
|
|||||||
import { hooksUsersSlug } from './collections/Users';
|
import { hooksUsersSlug } from './collections/Users';
|
||||||
import { devUser, regularUser } from '../credentials';
|
import { devUser, regularUser } from '../credentials';
|
||||||
import { AuthenticationError } from '../../src/errors';
|
import { AuthenticationError } from '../../src/errors';
|
||||||
|
import { contextHooksSlug } from './collections/ContextHooks';
|
||||||
|
|
||||||
let client: RESTClient;
|
let client: RESTClient;
|
||||||
|
let apiUrl;
|
||||||
|
|
||||||
describe('Hooks', () => {
|
describe('Hooks', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } });
|
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } });
|
||||||
client = new RESTClient(config, { serverURL, defaultSlug: transformSlug });
|
client = new RESTClient(config, { serverURL, defaultSlug: transformSlug });
|
||||||
|
apiUrl = `${serverURL}/api`;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@@ -151,6 +154,63 @@ describe('Hooks', () => {
|
|||||||
|
|
||||||
expect(retrievedDocs[0].text).toEqual('ok!!');
|
expect(retrievedDocs[0].text).toEqual('ok!!');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should pass context from beforeChange to afterChange', async () => {
|
||||||
|
const document = await payload.create({
|
||||||
|
collection: contextHooksSlug,
|
||||||
|
data: {
|
||||||
|
value: 'wrongvalue',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const retrievedDoc = await payload.findByID({
|
||||||
|
collection: contextHooksSlug,
|
||||||
|
id: document.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(retrievedDoc.value).toEqual('secret');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass context from local API to hooks', async () => {
|
||||||
|
const document = await payload.create({
|
||||||
|
collection: contextHooksSlug,
|
||||||
|
data: {
|
||||||
|
value: 'wrongvalue',
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
secretValue: 'data from local API',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const retrievedDoc = await payload.findByID({
|
||||||
|
collection: contextHooksSlug,
|
||||||
|
id: document.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(retrievedDoc.value).toEqual('data from local API');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass context from rest API to hooks', async () => {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
context_secretValue: 'data from rest API',
|
||||||
|
});
|
||||||
|
// send context as query params. It will be parsed by the beforeOperation hook
|
||||||
|
const response = await fetch(`${apiUrl}/${contextHooksSlug}?${params.toString()}`, {
|
||||||
|
body: JSON.stringify({
|
||||||
|
value: 'wrongvalue',
|
||||||
|
}),
|
||||||
|
method: 'post',
|
||||||
|
});
|
||||||
|
|
||||||
|
const document = (await response.json()).doc;
|
||||||
|
|
||||||
|
const retrievedDoc = await payload.findByID({
|
||||||
|
collection: contextHooksSlug,
|
||||||
|
id: document.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(retrievedDoc.value).toEqual('data from rest API');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('auth collection hooks', () => {
|
describe('auth collection hooks', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user