feat: expose data argument in afterChange hook for collections and globals (#12756)

### What

This PR updates the `afterChange` hook for collections and globals to
include the `data` argument.

While the `doc` argument provides the saved version of the document,
having access to the original `data` allows for additional context—such
as detecting omitted fields, raw client input, or conditional logic
based on user-supplied data.

### Changes

- Adds the `data` argument to the `afterChange` hook args.
- Applies to both `collection` and `global` hooks.

### Example

```
afterChange: [
  ({ context, data, doc, operation, previousDoc, req }) => {
    if (data?.customFlag) {
       // Perform logic based on raw input
    }
  },
],
```
This commit is contained in:
Patrik
2025-06-11 09:23:22 -04:00
committed by GitHub
parent d8626adc3b
commit 458a04b77c
11 changed files with 18 additions and 4 deletions

View File

@@ -160,6 +160,7 @@ The following arguments are provided to the `afterChange` hook:
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
| **`context`** | Custom context passed between hooks. [More details](./context). |
| **`data`** | The incoming data passed through the operation. |
| **`doc`** | The resulting Document after changes are applied. |
| **`operation`** | The name of the operation that this hook is running within. |
| **`previousDoc`** | The Document before changes were applied. |

View File

@@ -128,6 +128,7 @@ The following arguments are provided to the `afterChange` hook:
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. |
| **`context`** | Custom context passed between hooks. [More details](./context). |
| **`data`** | The incoming data passed through the operation. |
| **`doc`** | The resulting Document after changes are applied. |
| **`previousDoc`** | The Document before changes were applied. |
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |

View File

@@ -140,6 +140,7 @@ export type AfterChangeHook<T extends TypeWithID = any> = (args: {
/** The collection which this hook is being run on */
collection: SanitizedCollectionConfig
context: RequestContext
data: Partial<T>
doc: T
/**
* Hook operation being performed

View File

@@ -367,6 +367,7 @@ export const createOperation = async <
(await hook({
collection: collectionConfig,
context: req.context,
data,
doc: result,
operation: 'create',
previousDoc: {},

View File

@@ -209,6 +209,7 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
(await hook({
collection: collectionConfig,
context: req.context,
data: result,
doc: result,
operation: 'update',
previousDoc: prevDocWithLocales,

View File

@@ -383,6 +383,7 @@ export const updateDocument = async <
(await hook({
collection: collectionConfig,
context: req.context,
data,
doc: result,
operation: 'update',
previousDoc: originalDoc,

View File

@@ -51,6 +51,7 @@ export type BeforeChangeHook = (args: {
export type AfterChangeHook = (args: {
context: RequestContext
data: any
doc: any
/** The global which this hook is being run on */
global: SanitizedGlobalConfig

View File

@@ -170,6 +170,7 @@ export const restoreVersionOperation = async <T extends TypeWithVersion<T> = any
result =
(await hook({
context: req.context,
data: result,
doc: result,
global: globalConfig,
previousDoc,

View File

@@ -368,6 +368,7 @@ export const updateOperation = async <
result =
(await hook({
context: req.context,
data,
doc: result,
global: globalConfig,
previousDoc: originalDoc,

View File

@@ -134,6 +134,7 @@ export const generateReindexHandler =
for (const doc of docs) {
await syncDocAsSearchIndex({
collection,
data: doc,
doc,
locale: localeToSync,
onSyncError: () => operation === 'create' && aggregateErrors++,

View File

@@ -44,11 +44,15 @@ export const DataHooks: CollectionConfig = {
],
afterOperation: [
({ args, result, collection }) => {
args.req.context['collection_afterOperation_collection'] = JSON.stringify(collection)
if (args.req && args.req.context) {
args.req.context['collection_afterOperation_collection'] = JSON.stringify(collection)
}
for (const contextKey in args.req.context) {
if (contextKey.startsWith('collection_')) {
result[contextKey] = args.req.context[contextKey]
if (args.req && args.req.context) {
for (const contextKey in args.req.context) {
if (contextKey.startsWith('collection_')) {
result[contextKey] = args.req.context[contextKey]
}
}
}
return result