feat(live-preview): expose requestHandler to subscribe.ts (#10947)

### What?
As described in https://github.com/payloadcms/payload/discussions/10946,
allow passing a custom `collectionPopulationRequestHandler` function to
`subscribe`, which passes it along to `handleMessage` and `mergeData`

### Why?
`mergeData` already supports a custom function for this, that
functionality however isn't exposed.
My use case so far was passing along custom Authorization headers.


### How?
Move the functions type defined in `mergeData` to a dedicated
`CollectionPopulationRequestHandler` type, reuse it across `subscribe`,
`handleMessage` and `mergeData`.

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
This commit is contained in:
Janus Reith
2025-04-30 21:08:53 +02:00
committed by GitHub
parent cfe8c97ab7
commit 35c0404817
5 changed files with 59 additions and 46 deletions

View File

@@ -1,6 +1,6 @@
import type { FieldSchemaJSON } from 'payload' import type { FieldSchemaJSON } from 'payload'
import type { LivePreviewMessageEvent } from './types.js' import type { CollectionPopulationRequestHandler, LivePreviewMessageEvent } from './types.js'
import { isLivePreviewEvent } from './isLivePreviewEvent.js' import { isLivePreviewEvent } from './isLivePreviewEvent.js'
import { mergeData } from './mergeData.js' import { mergeData } from './mergeData.js'
@@ -29,9 +29,10 @@ export const handleMessage = async <T extends Record<string, any>>(args: {
depth?: number depth?: number
event: LivePreviewMessageEvent<T> event: LivePreviewMessageEvent<T>
initialData: T initialData: T
requestHandler?: CollectionPopulationRequestHandler
serverURL: string serverURL: string
}): Promise<T> => { }): Promise<T> => {
const { apiRoute, depth, event, initialData, serverURL } = args const { apiRoute, depth, event, initialData, requestHandler, serverURL } = args
if (isLivePreviewEvent(event, serverURL)) { if (isLivePreviewEvent(event, serverURL)) {
const { data, externallyUpdatedRelationship, fieldSchemaJSON, locale } = event.data const { data, externallyUpdatedRelationship, fieldSchemaJSON, locale } = event.data
@@ -57,6 +58,7 @@ export const handleMessage = async <T extends Record<string, any>>(args: {
incomingData: data, incomingData: data,
initialData: _payloadLivePreview?.previousData || initialData, initialData: _payloadLivePreview?.previousData || initialData,
locale, locale,
requestHandler,
serverURL, serverURL,
}) })

View File

@@ -1,6 +1,6 @@
import type { DocumentEvent, FieldSchemaJSON, PaginatedDocs } from 'payload' import type { DocumentEvent, FieldSchemaJSON, PaginatedDocs } from 'payload'
import type { PopulationsByCollection } from './types.js' import type { CollectionPopulationRequestHandler, PopulationsByCollection } from './types.js'
import { traverseFields } from './traverseFields.js' import { traverseFields } from './traverseFields.js'
@@ -29,21 +29,17 @@ let prevLocale: string | undefined
export const mergeData = async <T extends Record<string, any>>(args: { export const mergeData = async <T extends Record<string, any>>(args: {
apiRoute?: string apiRoute?: string
collectionPopulationRequestHandler?: ({ /**
apiPath, * @deprecated Use `requestHandler` instead
endpoint, */
serverURL, collectionPopulationRequestHandler?: CollectionPopulationRequestHandler
}: {
apiPath: string
endpoint: string
serverURL: string
}) => Promise<Response>
depth?: number depth?: number
externallyUpdatedRelationship?: DocumentEvent externallyUpdatedRelationship?: DocumentEvent
fieldSchema: FieldSchemaJSON fieldSchema: FieldSchemaJSON
incomingData: Partial<T> incomingData: Partial<T>
initialData: T initialData: T
locale?: string locale?: string
requestHandler?: CollectionPopulationRequestHandler
returnNumberOfRequests?: boolean returnNumberOfRequests?: boolean
serverURL: string serverURL: string
}): Promise< }): Promise<
@@ -81,7 +77,8 @@ export const mergeData = async <T extends Record<string, any>>(args: {
let res: PaginatedDocs let res: PaginatedDocs
const ids = new Set(populations.map(({ id }) => id)) const ids = new Set(populations.map(({ id }) => id))
const requestHandler = args.collectionPopulationRequestHandler || defaultRequestHandler const requestHandler =
args.collectionPopulationRequestHandler || args.requestHandler || defaultRequestHandler
try { try {
res = await requestHandler({ res = await requestHandler({

View File

@@ -1,3 +1,5 @@
import type { CollectionPopulationRequestHandler } from './types.js'
import { handleMessage } from './handleMessage.js' import { handleMessage } from './handleMessage.js'
export const subscribe = <T extends Record<string, any>>(args: { export const subscribe = <T extends Record<string, any>>(args: {
@@ -5,9 +7,10 @@ export const subscribe = <T extends Record<string, any>>(args: {
callback: (data: T) => void callback: (data: T) => void
depth?: number depth?: number
initialData: T initialData: T
requestHandler?: CollectionPopulationRequestHandler
serverURL: string serverURL: string
}): ((event: MessageEvent) => Promise<void> | void) => { }): ((event: MessageEvent) => Promise<void> | void) => {
const { apiRoute, callback, depth, initialData, serverURL } = args const { apiRoute, callback, depth, initialData, requestHandler, serverURL } = args
const onMessage = async (event: MessageEvent) => { const onMessage = async (event: MessageEvent) => {
const mergedData = await handleMessage<T>({ const mergedData = await handleMessage<T>({
@@ -15,6 +18,7 @@ export const subscribe = <T extends Record<string, any>>(args: {
depth, depth,
event, event,
initialData, initialData,
requestHandler,
serverURL, serverURL,
}) })

View File

@@ -1,5 +1,15 @@
import type { DocumentEvent, FieldSchemaJSON } from 'payload' import type { DocumentEvent, FieldSchemaJSON } from 'payload'
export type CollectionPopulationRequestHandler = ({
apiPath,
endpoint,
serverURL,
}: {
apiPath: string
endpoint: string
serverURL: string
}) => Promise<Response>
export type LivePreviewArgs = {} export type LivePreviewArgs = {}
export type LivePreview = void export type LivePreview = void

View File

@@ -13,9 +13,9 @@ import { fileURLToPath } from 'url'
import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { NextRESTClient } from '../helpers/NextRESTClient.js'
import type { Media, Page, Post, Tenant } from './payload-types.js' import type { Media, Page, Post, Tenant } from './payload-types.js'
import config from './config.js'
import { Pages } from './collections/Pages.js' import { Pages } from './collections/Pages.js'
import config from './config.js'
import { postsSlug, tenantsSlug } from './shared.js' import { postsSlug, tenantsSlug } from './shared.js'
const filename = fileURLToPath(import.meta.url) const filename = fileURLToPath(import.meta.url)
@@ -28,7 +28,7 @@ let restClient: NextRESTClient
import { initPayloadInt } from '../helpers/initPayloadInt.js' import { initPayloadInt } from '../helpers/initPayloadInt.js'
function collectionPopulationRequestHandler({ endpoint }: { endpoint: string }) { function requestHandler({ endpoint }: { endpoint: string }) {
return restClient.GET(`/${endpoint}`) return restClient.GET(`/${endpoint}`)
} }
@@ -170,7 +170,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(mergedData.title).toEqual('Test Page (Changed)') expect(mergedData.title).toEqual('Test Page (Changed)')
@@ -198,7 +198,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(mergedData.arrayOfRelationships).toEqual([]) expect(mergedData.arrayOfRelationships).toEqual([])
@@ -217,7 +217,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(mergedData2.arrayOfRelationships).toEqual([]) expect(mergedData2.arrayOfRelationships).toEqual([])
@@ -243,7 +243,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(mergedData.hero.media).toMatchObject(media) expect(mergedData.hero.media).toMatchObject(media)
@@ -262,7 +262,7 @@ describe('Collections - Live Preview', () => {
}, },
initialData: mergedData, initialData: mergedData,
serverURL, serverURL,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(mergedDataWithoutUpload.hero.media).toBeFalsy() expect(mergedDataWithoutUpload.hero.media).toBeFalsy()
@@ -290,7 +290,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1.richTextSlate).toHaveLength(1) expect(merge1.richTextSlate).toHaveLength(1)
@@ -317,7 +317,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge2.richTextSlate).toHaveLength(1) expect(merge2.richTextSlate).toHaveLength(1)
@@ -377,7 +377,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1.richTextLexical.root.children).toHaveLength(2) expect(merge1.richTextLexical.root.children).toHaveLength(2)
@@ -423,7 +423,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge2.richTextLexical.root.children).toHaveLength(1) expect(merge2.richTextLexical.root.children).toHaveLength(1)
@@ -446,7 +446,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1._numberOfRequests).toEqual(1) expect(merge1._numberOfRequests).toEqual(1)
@@ -468,7 +468,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1._numberOfRequests).toEqual(1) expect(merge1._numberOfRequests).toEqual(1)
@@ -490,7 +490,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1._numberOfRequests).toEqual(1) expect(merge1._numberOfRequests).toEqual(1)
@@ -515,7 +515,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1._numberOfRequests).toEqual(1) expect(merge1._numberOfRequests).toEqual(1)
@@ -545,7 +545,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge2._numberOfRequests).toEqual(0) expect(merge2._numberOfRequests).toEqual(0)
@@ -571,7 +571,7 @@ describe('Collections - Live Preview', () => {
}, },
initialData, initialData,
serverURL, serverURL,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1.tab.relationshipInTab).toMatchObject(testPost) expect(merge1.tab.relationshipInTab).toMatchObject(testPost)
@@ -608,7 +608,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1._numberOfRequests).toEqual(1) expect(merge1._numberOfRequests).toEqual(1)
@@ -665,7 +665,7 @@ describe('Collections - Live Preview', () => {
initialData: merge1, initialData: merge1,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge2._numberOfRequests).toEqual(1) expect(merge2._numberOfRequests).toEqual(1)
@@ -741,7 +741,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1._numberOfRequests).toEqual(2) expect(merge1._numberOfRequests).toEqual(2)
@@ -804,7 +804,7 @@ describe('Collections - Live Preview', () => {
initialData: merge1, initialData: merge1,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge2._numberOfRequests).toEqual(1) expect(merge2._numberOfRequests).toEqual(1)
@@ -870,7 +870,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1._numberOfRequests).toEqual(2) expect(merge1._numberOfRequests).toEqual(2)
@@ -937,7 +937,7 @@ describe('Collections - Live Preview', () => {
initialData: merge1, initialData: merge1,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge2._numberOfRequests).toEqual(1) expect(merge2._numberOfRequests).toEqual(1)
@@ -991,7 +991,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1._numberOfRequests).toEqual(0) expect(merge1._numberOfRequests).toEqual(0)
@@ -1051,7 +1051,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
// Check that the relationship on the first has been removed // Check that the relationship on the first has been removed
@@ -1080,7 +1080,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge1._numberOfRequests).toEqual(1) expect(merge1._numberOfRequests).toEqual(1)
@@ -1126,7 +1126,7 @@ describe('Collections - Live Preview', () => {
externallyUpdatedRelationship, externallyUpdatedRelationship,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
expect(merge2._numberOfRequests).toEqual(1) expect(merge2._numberOfRequests).toEqual(1)
@@ -1183,7 +1183,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
locale: 'es', locale: 'es',
}) })
@@ -1332,7 +1332,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
// Check that the blocks have been reordered // Check that the blocks have been reordered
@@ -1365,7 +1365,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
// Check that the block has been removed // Check that the block has been removed
@@ -1385,7 +1385,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler, requestHandler,
}) })
// Check that the block has been removed // Check that the block has been removed
@@ -1445,7 +1445,7 @@ describe('Collections - Live Preview', () => {
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
collectionPopulationRequestHandler: customRequestHandler, requestHandler: customRequestHandler,
}) })
expect(mergedData.relationshipPolyHasMany).toMatchObject([ expect(mergedData.relationshipPolyHasMany).toMatchObject([