feat!: removed getDataAndFile and getLocales from createPayloadRequest in favour of new utilities addDataAndFileToRequest and addLocalesToRequest (#5999)

This commit is contained in:
Paul
2024-04-24 13:31:54 -03:00
committed by GitHub
parent 5731241a5c
commit 24b18fb0fd
26 changed files with 277 additions and 68 deletions

View File

@@ -1,3 +1,5 @@
export { addDataAndFileToRequest } from '../utilities/addDataAndFileToRequest.js'
export { addLocalesToRequest } from '../utilities/addLocalesToRequest.js'
export { traverseFields } from '../utilities/buildFieldSchemaMap/traverseFields.js'
export { createPayloadRequest } from '../utilities/createPayloadRequest.js'
export { getNextRequestI18n } from '../utilities/getNextRequestI18n.js'

View File

@@ -5,6 +5,7 @@ import { configToSchema } from '@payloadcms/graphql'
import { createHandler } from 'graphql-http/lib/use/fetch'
import httpStatus from 'http-status'
import { addLocalesToRequest } from '../../utilities/addLocalesToRequest.js'
import { createPayloadRequest } from '../../utilities/createPayloadRequest.js'
import { headersWithCors } from '../../utilities/headersWithCors.js'
@@ -86,6 +87,9 @@ export const POST =
config,
request,
})
addLocalesToRequest({ request: req })
const { schema, validationRules } = await getGraphql(config)
const { payload } = req

View File

@@ -2,6 +2,7 @@ import type { SanitizedConfig } from 'payload/types'
import { renderPlaygroundPage } from 'graphql-playground-html'
import { addLocalesToRequest } from '../../utilities/addLocalesToRequest.js'
import { createPayloadRequest } from '../../utilities/createPayloadRequest.js'
export const GET = (config: Promise<SanitizedConfig>) => async (request: Request) => {
@@ -10,6 +11,8 @@ export const GET = (config: Promise<SanitizedConfig>) => async (request: Request
request,
})
addLocalesToRequest({ request: req })
if (
(!req.payload.config.graphQL.disable &&
!req.payload.config.graphQL.disablePlaygroundInProduction &&

View File

@@ -11,6 +11,8 @@ import type {
GlobalRouteHandlerWithID,
} from './types.js'
import { addDataAndFileToRequest } from '../../utilities/addDataAndFileToRequest.js'
import { addLocalesToRequest } from '../../utilities/addLocalesToRequest.js'
import { createPayloadRequest } from '../../utilities/createPayloadRequest.js'
import { headersWithCors } from '../../utilities/headersWithCors.js'
import { access } from './auth/access.js'
@@ -230,7 +232,12 @@ export const GET =
entitySlug: slug1,
payloadRequest: req,
})
if (customEndpointResponse) return customEndpointResponse
if (customEndpointResponse) {
return customEndpointResponse
} else {
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
}
switch (slug.length) {
case 1:
@@ -288,7 +295,12 @@ export const GET =
payloadRequest: req,
})
if (customEndpointResponse) return customEndpointResponse
if (customEndpointResponse) {
return customEndpointResponse
} else {
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
}
switch (slug.length) {
case 2:
@@ -326,6 +338,8 @@ export const GET =
break
}
} else if (slug.length === 1 && slug1 in endpoints.root.GET) {
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
res = await endpoints.root.GET[slug1]({ req })
}
@@ -389,7 +403,12 @@ export const POST =
payloadRequest: req,
})
if (customEndpointResponse) return customEndpointResponse
if (customEndpointResponse) {
return customEndpointResponse
} else {
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
}
switch (slug.length) {
case 1:
@@ -440,7 +459,13 @@ export const POST =
entitySlug: `${slug1}/${slug2}`,
payloadRequest: req,
})
if (customEndpointResponse) return customEndpointResponse
if (customEndpointResponse) {
return customEndpointResponse
} else {
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
}
switch (slug.length) {
case 2:
@@ -472,6 +497,8 @@ export const POST =
res = new Response('Route Not Found', { status: 404 })
}
} else if (slug.length === 1 && slug1 in endpoints.root.POST) {
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
res = await endpoints.root.POST[slug1]({ req })
}
@@ -534,7 +561,12 @@ export const DELETE =
entitySlug: slug1,
payloadRequest: req,
})
if (customEndpointResponse) return customEndpointResponse
if (customEndpointResponse) {
return customEndpointResponse
} else {
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
}
switch (slug.length) {
case 1:
@@ -607,7 +639,13 @@ export const PATCH =
entitySlug: slug1,
payloadRequest: req,
})
if (customEndpointResponse) return customEndpointResponse
if (customEndpointResponse) {
return customEndpointResponse
} else {
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
}
switch (slug.length) {
case 1:

View File

@@ -0,0 +1,70 @@
import type { CustomPayloadRequest, PayloadRequest } from 'payload/types'
import type { NextFileUploadOptions } from '../next-fileupload/index.js'
import { nextFileUpload } from '../next-fileupload/index.js'
type AddDataAndFileToRequest = (args: { request: PayloadRequest }) => Promise<void>
/**
* Mutates the Request to contain 'data' and 'file' if present
*/
export const addDataAndFileToRequest: AddDataAndFileToRequest = async ({
request: incomingRequest,
}) => {
const config = incomingRequest.payload.config
let data: Record<string, any> | undefined = undefined
let file: CustomPayloadRequest['file'] = undefined
if (
incomingRequest.method &&
['PATCH', 'POST', 'PUT'].includes(incomingRequest.method.toUpperCase()) &&
incomingRequest.body
) {
// @ts-expect-error todo: fix type
const request = new Request(incomingRequest)
const [contentType] = (request.headers.get('Content-Type') || '').split(';')
if (contentType === 'application/json') {
const bodyByteSize = parseInt(request.headers.get('Content-Length') || '0', 10)
const upperByteLimit =
typeof config.upload?.limits?.fieldSize === 'number'
? config.upload.limits.fields
: undefined
if ((upperByteLimit && bodyByteSize <= upperByteLimit) || upperByteLimit === undefined) {
try {
data = await request.json()
} catch (error) {
data = {}
}
} else {
throw new Error('Request body size exceeds the limit')
}
} else {
if (request.headers.has('Content-Length') && request.headers.get('Content-Length') !== '0') {
const { error, fields, files } = await nextFileUpload({
options: config.upload as NextFileUploadOptions,
request,
})
if (error) {
throw new Error(error.message)
}
if (files?.file) {
file = files.file
}
if (fields?._payload && typeof fields._payload === 'string') {
data = JSON.parse(fields._payload)
}
}
}
}
if (data) {
incomingRequest.data = data
incomingRequest.json = () => Promise.resolve(data)
}
if (file) incomingRequest.file = file
}

View File

@@ -0,0 +1,45 @@
import type { PayloadRequest } from 'payload/types'
type AddLocalesToRequestArgs = {
request: PayloadRequest
}
/**
* Mutates the Request to contain 'locale' and 'fallbackLocale' based on data or searchParams
*/
export function addLocalesToRequest({ request }: AddLocalesToRequestArgs): void {
const {
data,
payload: { config },
} = request
const { localization } = config
const urlProperties = new URL(request.url)
const { searchParams } = urlProperties
let locale = searchParams.get('locale')
let fallbackLocale = searchParams.get('fallback-locale')
if (data) {
if (data?.locale && typeof data.locale === 'string') {
locale = data.locale
}
if (data?.['fallback-locale'] && typeof data?.['fallback-locale'] === 'string') {
fallbackLocale = data['fallback-locale']
}
}
if (fallbackLocale === 'none') {
fallbackLocale = 'null'
} else if (localization && !localization.localeCodes.includes(fallbackLocale)) {
fallbackLocale = localization.defaultLocale
}
if (locale === '*') {
locale = 'all'
} else if (localization && !localization.localeCodes.includes(locale)) {
locale = localization.defaultLocale
}
if (locale) request.locale = locale
if (fallbackLocale) request.fallbackLocale = fallbackLocale
}

View File

@@ -12,10 +12,8 @@ import { getDataLoader } from 'payload/utilities'
import qs from 'qs'
import { URL } from 'url'
import { getDataAndFile } from './getDataAndFile.js'
import { getPayloadHMR } from './getPayloadHMR.js'
import { getRequestLanguage } from './getRequestLanguage.js'
import { getRequestLocales } from './getRequestLocales.js'
type Args = {
config: Promise<SanitizedConfig> | SanitizedConfig
@@ -41,30 +39,11 @@ export const createPayloadRequest = async ({
}
const urlProperties = new URL(request.url)
const { pathname, searchParams } = urlProperties
const { pathname } = urlProperties
const isGraphQL =
!config.graphQL.disable && pathname === `${config.routes.api}${config.routes.graphQL}`
const { data, file } = await getDataAndFile({
collection,
config,
request,
})
let requestFallbackLocale
let requestLocale
if (config.localization) {
const locales = getRequestLocales({
data,
localization: config.localization,
searchParams,
})
requestLocale = locales.locale
requestFallbackLocale = locales.fallbackLocale
}
const language = getRequestLanguage({
config,
cookies,
@@ -79,14 +58,10 @@ export const createPayloadRequest = async ({
const customRequest: CustomPayloadRequest = {
context: {},
data,
fallbackLocale: requestFallbackLocale,
file,
hash: urlProperties.hash,
host: urlProperties.host,
href: urlProperties.href,
i18n,
locale: requestLocale,
origin: urlProperties.origin,
pathname: urlProperties.pathname,
payload,
@@ -112,7 +87,6 @@ export const createPayloadRequest = async ({
const req: PayloadRequest = Object.assign(request, customRequest)
if (data) req.json = () => Promise.resolve(data)
req.payloadDataLoader = getDataLoader(req)
req.user = await executeAuthStrategies({

View File

@@ -5,6 +5,21 @@ import type { PayloadHandler } from '../../config/types.js'
import deleteOperation from '../operations/delete.js'
export const deleteHandler: PayloadHandler = async (req): Promise<Response> => {
// We cannot import the addDataAndFileToRequest utility here from the 'next' package because of dependency issues
// However that utility should be used where possible instead of manually appending the data
let data
try {
data = await req.json()
} catch (error) {
data = {}
}
if (data) {
req.data = data
req.json = () => Promise.resolve(data)
}
const result = await deleteOperation({
key: req.routeParams?.key as string,
req,

View File

@@ -5,6 +5,21 @@ import type { PayloadHandler } from '../../config/types.js'
import findOne from '../operations/findOne.js'
export const findByIDHandler: PayloadHandler = async (req): Promise<Response> => {
// We cannot import the addDataAndFileToRequest utility here from the 'next' package because of dependency issues
// However that utility should be used where possible instead of manually appending the data
let data
try {
data = await req.json()
} catch (error) {
data = {}
}
if (data) {
req.data = data
req.json = () => Promise.resolve(data)
}
const result = await findOne({
key: req.routeParams?.key as string,
req,

View File

@@ -5,6 +5,21 @@ import type { PayloadHandler } from '../../config/types.js'
import update from '../operations/update.js'
export const updateHandler: PayloadHandler = async (req) => {
// We cannot import the addDataAndFileToRequest utility here from the 'next' package because of dependency issues
// However that utility should be used where possible instead of manually appending the data
let data
try {
data = await req.json()
} catch (error) {
data = {}
}
if (data) {
req.data = data
req.json = () => Promise.resolve(data)
}
const payloadRequest = req
const doc = await update({

View File

@@ -44,6 +44,7 @@
"payload": "workspace:*",
"@payloadcms/translations": "workspace:*",
"@payloadcms/ui": "workspace:*",
"@payloadcms/next": "workspace:*",
"react": "^18.0.0"
},
"exports": {

View File

@@ -1,6 +1,7 @@
import type { Config } from 'payload/config'
import type { Field, GroupField, TabsField, TextField } from 'payload/types'
import { addDataAndFileToRequest } from '@payloadcms/next/utilities'
import { deepMerge } from 'payload/utilities'
import React from 'react'
@@ -197,6 +198,7 @@ const seo =
...(config.endpoints ?? []),
{
handler: async (req) => {
await addDataAndFileToRequest({ request: req })
const args: Parameters<GenerateTitle>[0] =
req.data as unknown as Parameters<GenerateTitle>[0]
const result = pluginConfig.generateTitle ? await pluginConfig.generateTitle(args) : ''
@@ -207,6 +209,7 @@ const seo =
},
{
handler: async (req) => {
await addDataAndFileToRequest({ request: req })
const args: Parameters<GenerateDescription>[0] =
req.data as unknown as Parameters<GenerateDescription>[0]
const result = pluginConfig.generateDescription
@@ -219,6 +222,7 @@ const seo =
},
{
handler: async (req) => {
await addDataAndFileToRequest({ request: req })
const args: Parameters<GenerateURL>[0] =
req.data as unknown as Parameters<GenerateURL>[0]
const result = pluginConfig.generateURL ? await pluginConfig.generateURL(args) : ''
@@ -229,6 +233,7 @@ const seo =
},
{
handler: async (req) => {
await addDataAndFileToRequest({ request: req })
const args: Parameters<GenerateImage>[0] =
req.data as unknown as Parameters<GenerateImage>[0]
const result = pluginConfig.generateImage ? await pluginConfig.generateImage(args) : ''

View File

@@ -20,5 +20,5 @@
"src/**/*.spec.tsx"
],
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.json"],
"references": [{ "path": "../payload" }, { "path": "../ui" }]
"references": [{ "path": "../payload" }, { "path": "../ui" }, { "path": "../next" }]
}

3
pnpm-lock.yaml generated
View File

@@ -1179,6 +1179,9 @@ importers:
'@payloadcms/eslint-config':
specifier: workspace:*
version: link:../eslint-config-payload
'@payloadcms/next':
specifier: workspace:*
version: link:../next
'@payloadcms/translations':
specifier: workspace:*
version: link:../translations

View File

@@ -60,7 +60,7 @@ import { fileURLToPath } from 'url'
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
import { reInitializeDB } from '../helpers/reInit.js'
import { reInitializeDB } from '../helpers/reInitializeDB.js'
import { POLL_TOPASS_TIMEOUT } from '../playwright.config.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)

View File

@@ -27,7 +27,17 @@ export const collectionEndpoints: CollectionConfig['endpoints'] = [
{
path: '/whoami',
method: 'post',
handler: (req) => {
handler: async (req) => {
let data
try {
data = await req.json()
} catch (error) {
data = {}
}
if (data) req.data = data
return Response.json({
name: req.data.name,
age: req.data.age,

View File

@@ -15,7 +15,7 @@ import {
} from '../../../helpers.js'
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js'
import { reInitializeDB } from '../../../helpers/reInit.js'
import { reInitializeDB } from '../../../helpers/reInitializeDB.js'
import { RESTClient } from '../../../helpers/rest.js'
const filename = fileURLToPath(import.meta.url)

View File

@@ -11,7 +11,7 @@ import {
} from '../../../helpers.js'
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js'
import { reInitializeDB } from '../../../helpers/reInit.js'
import { reInitializeDB } from '../../../helpers/reInitializeDB.js'
import { RESTClient } from '../../../helpers/rest.js'
const filename = fileURLToPath(import.meta.url)

View File

@@ -5,7 +5,7 @@ import type { SerializedEditorState, SerializedParagraphNode, SerializedTextNode
import { expect, test } from '@playwright/test'
import { initPayloadE2ENoConfig } from 'helpers/initPayloadE2ENoConfig.js'
import { reInitializeDB } from 'helpers/reInit.js'
import { reInitializeDB } from 'helpers/reInitializeDB.js'
import path from 'path'
import { wait } from 'payload/utilities'
import { fileURLToPath } from 'url'

View File

@@ -18,7 +18,7 @@ import {
} from '../../../helpers.js'
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js'
import { reInitializeDB } from '../../../helpers/reInit.js'
import { reInitializeDB } from '../../../helpers/reInitializeDB.js'
import { RESTClient } from '../../../helpers/rest.js'
import { POLL_TOPASS_TIMEOUT } from '../../../playwright.config.js'
import { relationshipFieldsSlug, textFieldsSlug } from '../../slugs.js'

View File

@@ -12,7 +12,7 @@ import {
} from '../../../helpers.js'
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js'
import { reInitializeDB } from '../../../helpers/reInit.js'
import { reInitializeDB } from '../../../helpers/reInitializeDB.js'
import { RESTClient } from '../../../helpers/rest.js'
const filename = fileURLToPath(import.meta.url)

View File

@@ -18,7 +18,7 @@ import {
} from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { reInitializeDB } from '../helpers/reInit.js'
import { reInitializeDB } from '../helpers/reInitializeDB.js'
import { RESTClient } from '../helpers/rest.js'
import { POLL_TOPASS_TIMEOUT } from '../playwright.config.js'
import { jsonDoc } from './collections/JSON/shared.js'

View File

@@ -1,12 +1,17 @@
import type { Endpoint } from 'payload/config'
import type { PayloadRequest } from 'payload/types'
import { addDataAndFileToRequest, addLocalesToRequest } from '@payloadcms/next/utilities'
import httpStatus from 'http-status'
import { path } from './reInitializeDB.js'
import { seedDB } from './seed.js'
const handler = async ({ data, payload }: PayloadRequest) => {
const handler = async (req: PayloadRequest) => {
process.env.SEED_IN_CONFIG_ONINIT = 'true'
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
const { data, payload } = req
try {
await seedDB({
@@ -33,31 +38,8 @@ const handler = async ({ data, payload }: PayloadRequest) => {
}
}
const path = '/re-initialize'
export const reInitEndpoint: Endpoint = {
path,
method: 'post',
handler,
}
export const reInitializeDB = async ({
serverURL,
snapshotKey,
uploadsDir,
}: {
serverURL: string
snapshotKey: string
uploadsDir?: string
}) => {
await fetch(`${serverURL}/api${path}`, {
method: 'post',
body: JSON.stringify({
snapshotKey,
uploadsDir,
}),
headers: {
'Content-Type': 'application/json',
},
})
}

View File

@@ -0,0 +1,22 @@
export const path = '/re-initialize'
export const reInitializeDB = async ({
serverURL,
snapshotKey,
uploadsDir,
}: {
serverURL: string
snapshotKey: string
uploadsDir?: string
}) => {
await fetch(`${serverURL}/api${path}`, {
method: 'post',
body: JSON.stringify({
snapshotKey,
uploadsDir,
}),
headers: {
'Content-Type': 'application/json',
},
})
}

View File

@@ -1,8 +1,13 @@
import type { Endpoint, PayloadHandler } from 'payload/config'
import { addDataAndFileToRequest, addLocalesToRequest } from '@payloadcms/next/utilities'
import httpStatus from 'http-status'
export const handler: PayloadHandler = async ({ payload, data, user }) => {
export const handler: PayloadHandler = async (req) => {
await addDataAndFileToRequest({ request: req })
addLocalesToRequest({ request: req })
const { data, payload, user } = req
const operation = String(data.operation)
if (typeof payload[operation] === 'function') {

View File

@@ -43,7 +43,7 @@ import {
} from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { reInitializeDB } from '../helpers/reInit.js'
import { reInitializeDB } from '../helpers/reInitializeDB.js'
import { POLL_TOPASS_TIMEOUT } from '../playwright.config.js'
import { titleToDelete } from './shared.js'
import {