chore: pass config to route handlers
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from 'payload-config'
|
||||
import { REST_GET, REST_DELETE, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
|
||||
|
||||
export { GET, POST, DELETE, PATCH } from '@payloadcms/next/routes'
|
||||
export const GET = REST_GET(config)
|
||||
export const POST = REST_POST(config)
|
||||
export const DELETE = REST_DELETE(config)
|
||||
export const PATCH = REST_PATCH(config)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from 'payload-config'
|
||||
import { GET_STATIC_FILE } from '@payloadcms/next/routes'
|
||||
|
||||
export { GET } from '@payloadcms/next/routes/[collection]/file/[filename]/route'
|
||||
export const GET = GET_STATIC_FILE(config)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
|
||||
|
||||
export { GET_GraphQLPlayground as GET } from '@payloadcms/next/routes/graphql'
|
||||
export const GET = GRAPHQL_PLAYGROUND_GET
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from 'payload-config'
|
||||
import { GRAPHQL_POST } from '@payloadcms/next/routes'
|
||||
|
||||
export { POST_GraphQLHandler as POST } from '@payloadcms/next/routes/graphql'
|
||||
export const POST = GRAPHQL_POST(config)
|
||||
|
||||
@@ -35,10 +35,6 @@
|
||||
"./routes": {
|
||||
"import": "./src/routes/index.ts",
|
||||
"require": "./src/routes/index.ts"
|
||||
},
|
||||
"./routes/*": {
|
||||
"import": "./src/routes/*.ts",
|
||||
"require": "./src/routes/*.ts"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -95,11 +91,6 @@
|
||||
"import": "./dist/routes/index.js",
|
||||
"require": "./dist/routes/index.js",
|
||||
"types": "./dist/routes/index.d.ts"
|
||||
},
|
||||
"./routes/*": {
|
||||
"import": "./dist/routes/*.js",
|
||||
"require": "./dist/routes/*.js",
|
||||
"types": "./dist/routes/*.d.ts"
|
||||
}
|
||||
},
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from 'payload-config'
|
||||
import { REST_GET, REST_DELETE, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
|
||||
|
||||
export { GET, POST, DELETE, PATCH } from '@payloadcms/next/routes'
|
||||
export const GET = REST_GET(config)
|
||||
export const POST = REST_POST(config)
|
||||
export const DELETE = REST_DELETE(config)
|
||||
export const PATCH = REST_PATCH(config)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from 'payload-config'
|
||||
import { GET_STATIC_FILE } from '@payloadcms/next/routes'
|
||||
|
||||
export { GET } from '@payloadcms/next/routes/[collection]/file/[filename]/route'
|
||||
export const GET = GET_STATIC_FILE(config)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
|
||||
|
||||
export { GET_GraphQLPlayground as GET } from '@payloadcms/next/routes/graphql'
|
||||
export const GET = GRAPHQL_PLAYGROUND_GET
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from 'payload-config'
|
||||
import { GRAPHQL_POST } from '@payloadcms/next/routes'
|
||||
|
||||
export { POST_GraphQLHandler as POST } from '@payloadcms/next/routes/graphql'
|
||||
export const POST = GRAPHQL_POST(config)
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
import path from 'path'
|
||||
import config from 'payload-config'
|
||||
import { streamFile } from '../../../../next-stream-file'
|
||||
import fsPromises from 'fs/promises'
|
||||
import { Collection, PayloadRequest, Where } from 'payload/types'
|
||||
import executeAccess from 'payload/dist/auth/executeAccess'
|
||||
import { APIError, Forbidden } from 'payload/errors'
|
||||
import { RouteError } from '../../../RouteError'
|
||||
import { createPayloadRequest } from '../../../../utilities/createPayloadRequest'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
async function checkFileAccess({
|
||||
req,
|
||||
filename,
|
||||
collection,
|
||||
}: {
|
||||
req: PayloadRequest
|
||||
filename: string
|
||||
collection: Collection
|
||||
}) {
|
||||
const { config } = collection
|
||||
const accessResult = await executeAccess({ isReadingStaticFile: true, req }, config.access.read)
|
||||
|
||||
if (typeof accessResult === 'object') {
|
||||
const queryToBuild: Where = {
|
||||
and: [
|
||||
{
|
||||
or: [
|
||||
{
|
||||
filename: {
|
||||
equals: filename,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
accessResult,
|
||||
],
|
||||
}
|
||||
|
||||
if (config.upload.imageSizes) {
|
||||
config.upload.imageSizes.forEach(({ name }) => {
|
||||
queryToBuild.and[0].or.push({
|
||||
[`sizes.${name}.filename`]: {
|
||||
equals: filename,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const doc = await req.payload.db.findOne({
|
||||
collection: config.slug,
|
||||
req,
|
||||
where: queryToBuild,
|
||||
})
|
||||
|
||||
if (!doc) {
|
||||
throw new Forbidden(req.t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const GET = async (
|
||||
request: Request,
|
||||
{ params }: { params: { collection: string; filename: string } },
|
||||
) => {
|
||||
const { collection: collectionSlug, filename } = params
|
||||
let req: PayloadRequest
|
||||
let collection: Collection
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: { collection: collectionSlug },
|
||||
})
|
||||
collection = req.payload.collections?.[collectionSlug]
|
||||
|
||||
if (!collection) {
|
||||
throw new APIError(`Media collection not found: ${collectionSlug}`, httpStatus.BAD_REQUEST)
|
||||
}
|
||||
|
||||
if (!collection.config.upload) {
|
||||
throw new APIError(
|
||||
`This collection is not an upload collection: ${collectionSlug}`,
|
||||
httpStatus.BAD_REQUEST,
|
||||
)
|
||||
}
|
||||
|
||||
if (collection.config.upload.disableLocalStorage) {
|
||||
throw new APIError(
|
||||
`This collection has local storage disabled: ${collectionSlug}`,
|
||||
httpStatus.BAD_REQUEST,
|
||||
)
|
||||
}
|
||||
|
||||
await checkFileAccess({
|
||||
req,
|
||||
filename,
|
||||
collection,
|
||||
})
|
||||
|
||||
const fileDir = collection.config.upload?.staticDir || collection.config.slug
|
||||
const filePath = path.resolve(`${fileDir}/${filename}`)
|
||||
const stats = await fsPromises.stat(filePath)
|
||||
const data = streamFile(filePath)
|
||||
return new Response(data, {
|
||||
status: httpStatus.OK,
|
||||
headers: new Headers({
|
||||
'content-length': stats.size + '',
|
||||
}),
|
||||
})
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import config from 'payload-config'
|
||||
import { GraphQLError } from 'graphql'
|
||||
import httpStatus from 'http-status'
|
||||
import { configToSchema } from '@payloadcms/graphql'
|
||||
import type { Payload, CollectionAfterErrorHook } from 'payload/types'
|
||||
import type { Payload, CollectionAfterErrorHook, SanitizedConfig } from 'payload/types'
|
||||
import type { GraphQLFormattedError } from 'graphql'
|
||||
import { createPayloadRequest } from '../../utilities/createPayloadRequest'
|
||||
import { createHandler } from 'graphql-http/lib/use/fetch'
|
||||
@@ -49,7 +48,7 @@ if (!cached) {
|
||||
cached = global._payload_graphql = { graphql: null, promise: null }
|
||||
}
|
||||
|
||||
export const getGraphql = async () => {
|
||||
export const getGraphql = async (config: Promise<SanitizedConfig>) => {
|
||||
if (cached.graphql) {
|
||||
return cached.graphql
|
||||
}
|
||||
@@ -72,13 +71,13 @@ export const getGraphql = async () => {
|
||||
return cached.graphql
|
||||
}
|
||||
|
||||
export const POST = async (request: Request) => {
|
||||
export const POST = (config: Promise<SanitizedConfig>) => async (request: Request) => {
|
||||
const originalRequest = request.clone()
|
||||
const req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
})
|
||||
const { schema, validationRules } = await getGraphql()
|
||||
const { schema, validationRules } = await getGraphql(config)
|
||||
|
||||
const { payload } = req
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export { POST as POST_GraphQLHandler } from './handler'
|
||||
export { GET as GET_GraphQLPlayground } from './playground'
|
||||
export { POST as GRAPHQL_POST } from './handler'
|
||||
|
||||
export { GET as GRAPHQL_PLAYGROUND_GET } from './playground'
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import config from 'payload-config'
|
||||
import { renderPlaygroundPage } from 'graphql-playground-html'
|
||||
import { createPayloadRequest } from '../../utilities/createPayloadRequest'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
export const GET = async (request: Request) => {
|
||||
export const GET = (config: Promise<SanitizedConfig>) => async (request: Request) => {
|
||||
const req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
|
||||
@@ -1,459 +1,10 @@
|
||||
import config from 'payload-config'
|
||||
import httpStatus from 'http-status'
|
||||
import type { Collection, GlobalConfig, PayloadRequest } from 'payload/types'
|
||||
import type { Endpoint } from 'payload/config'
|
||||
import { match } from 'path-to-regexp'
|
||||
export {
|
||||
GET as REST_GET,
|
||||
POST as REST_POST,
|
||||
DELETE as REST_DELETE,
|
||||
PATCH as REST_PATCH,
|
||||
} from './rest'
|
||||
|
||||
import { createPayloadRequest } from '../utilities/createPayloadRequest'
|
||||
import {
|
||||
CollectionRouteHandler,
|
||||
CollectionRouteHandlerWithID,
|
||||
GlobalRouteHandler,
|
||||
GlobalRouteHandlerWithID,
|
||||
} from './types'
|
||||
export { GET as GET_STATIC_FILE } from './rest/[collection]/file/[filename]/route'
|
||||
|
||||
import { me } from './auth/me'
|
||||
import { init } from './auth/init'
|
||||
import { login } from './auth/login'
|
||||
import { unlock } from './auth/unlock'
|
||||
import { access } from './auth/access'
|
||||
import { logout } from './auth/logout'
|
||||
import { refresh } from './auth/refresh'
|
||||
|
||||
import { find } from './collections/find'
|
||||
import { create } from './collections/create'
|
||||
import { update } from './collections/update'
|
||||
import { deleteDoc } from './collections/delete'
|
||||
import { verifyEmail } from './auth/verifyEmail'
|
||||
import { findByID } from './collections/findByID'
|
||||
import { docAccess } from './collections/docAccess'
|
||||
import { resetPassword } from './auth/resetPassword'
|
||||
import { updateByID } from './collections/updateByID'
|
||||
import { deleteByID } from './collections/deleteByID'
|
||||
import { forgotPassword } from './auth/forgotPassword'
|
||||
import { findVersions } from './collections/findVersions'
|
||||
import { registerFirstUser } from './auth/registerFirstUser'
|
||||
import { restoreVersion } from './collections/restoreVersion'
|
||||
import { findVersionByID } from './collections/findVersionByID'
|
||||
|
||||
import { findOne } from './globals/findOne'
|
||||
import { update as updateGlobal } from './globals/update'
|
||||
import { docAccess as docAccessGlobal } from './globals/docAccess'
|
||||
import { findVersions as findVersionsGlobal } from './globals/findVersions'
|
||||
import { restoreVersion as restoreVersionGlobal } from './globals/restoreVersion'
|
||||
import { findVersionByID as findVersionByIdGlobal } from './globals/findVersionByID'
|
||||
import { RouteError } from './RouteError'
|
||||
|
||||
const endpoints = {
|
||||
root: {
|
||||
GET: {
|
||||
access,
|
||||
},
|
||||
},
|
||||
collection: {
|
||||
GET: {
|
||||
init,
|
||||
me,
|
||||
versions: findVersions,
|
||||
find,
|
||||
findByID,
|
||||
'doc-access-by-id': docAccess,
|
||||
'doc-versions-by-id': findVersionByID,
|
||||
},
|
||||
POST: {
|
||||
create,
|
||||
login,
|
||||
logout,
|
||||
unlock,
|
||||
access: docAccess,
|
||||
'first-register': registerFirstUser,
|
||||
'forgot-password': forgotPassword,
|
||||
'reset-password': resetPassword,
|
||||
'refresh-token': refresh,
|
||||
'doc-access-by-id': docAccess,
|
||||
'doc-versions-by-id': restoreVersion,
|
||||
'doc-verify-by-id': verifyEmail,
|
||||
},
|
||||
PATCH: {
|
||||
update,
|
||||
updateByID,
|
||||
},
|
||||
DELETE: {
|
||||
delete: deleteDoc,
|
||||
deleteByID,
|
||||
},
|
||||
},
|
||||
global: {
|
||||
GET: {
|
||||
findOne,
|
||||
'doc-access': docAccessGlobal,
|
||||
'doc-versions': findVersionsGlobal,
|
||||
'doc-versions-by-id': findVersionByIdGlobal,
|
||||
},
|
||||
POST: {
|
||||
update: updateGlobal,
|
||||
'doc-access': docAccessGlobal,
|
||||
'doc-versions-by-id': restoreVersionGlobal,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const handleCustomEndpoints = ({
|
||||
entitySlug,
|
||||
endpoints,
|
||||
payloadRequest,
|
||||
}: {
|
||||
entitySlug?: string
|
||||
endpoints: Endpoint[] | GlobalConfig['endpoints']
|
||||
payloadRequest: PayloadRequest
|
||||
}): Promise<Response> | Response => {
|
||||
if (endpoints && endpoints.length > 0) {
|
||||
let handlerParams = {}
|
||||
const { pathname } = payloadRequest
|
||||
const pathPrefix =
|
||||
payloadRequest.payload.config.routes.api + (entitySlug ? `/${entitySlug}` : '')
|
||||
|
||||
const customEndpoint = endpoints.find((endpoint) => {
|
||||
if (endpoint.method === payloadRequest.method.toLowerCase()) {
|
||||
const pathMatchFn = match(`${pathPrefix}${endpoint.path}`, {
|
||||
decode: decodeURIComponent,
|
||||
})
|
||||
const tempParams = pathMatchFn(pathname)
|
||||
if (tempParams) {
|
||||
handlerParams = tempParams.params
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (customEndpoint) {
|
||||
return customEndpoint.handler({
|
||||
req: payloadRequest,
|
||||
routeParams: handlerParams,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const RouteNotFoundResponse = (slug: string[]) =>
|
||||
Response.json(
|
||||
{
|
||||
message: `Route Not Found: "${slug.join('/')}"`,
|
||||
},
|
||||
{ status: httpStatus.NOT_FOUND },
|
||||
)
|
||||
|
||||
export const GET = async (
|
||||
request: Request,
|
||||
{ params: { slug } }: { params: { slug: string[] } },
|
||||
) => {
|
||||
const [slug1, slug2, slug3, slug4] = slug
|
||||
let req: PayloadRequest
|
||||
let collection: Collection
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: {
|
||||
collection: slug1,
|
||||
},
|
||||
})
|
||||
collection = req.payload.collections?.[slug1]
|
||||
|
||||
if (collection) {
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: slug1,
|
||||
payloadRequest: req,
|
||||
endpoints: collection.config?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 1:
|
||||
// /:collection
|
||||
return endpoints.collection.GET.find({ req, collection })
|
||||
case 2:
|
||||
if (slug2 in endpoints.collection.GET) {
|
||||
// /:collection/init
|
||||
// /:collection/me
|
||||
// /:collection/versions
|
||||
return (endpoints.collection.GET[slug2] as CollectionRouteHandler)({ req, collection })
|
||||
}
|
||||
// /:collection/:id
|
||||
return endpoints.collection.GET.findByID({ req, id: slug2, collection })
|
||||
case 3:
|
||||
if (`doc-${slug2}-by-id` in endpoints.collection.GET) {
|
||||
// /:collection/access/:id
|
||||
// /:collection/versions/:id
|
||||
return (endpoints.collection.GET[`doc-${slug2}-by-id`] as CollectionRouteHandlerWithID)(
|
||||
{ req, id: slug3, collection },
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
} else if (slug1 === 'globals') {
|
||||
const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2)
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: `${slug1}/${slug2}`,
|
||||
payloadRequest: req,
|
||||
endpoints: globalConfig?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 2:
|
||||
// /globals/:slug
|
||||
return endpoints.global.GET.findOne({ req, globalConfig })
|
||||
case 3:
|
||||
if (`doc-${slug3}` in endpoints.global.GET) {
|
||||
// /globals/:slug/access
|
||||
// /globals/:slug/versions
|
||||
return (endpoints.global.GET?.[`doc-${slug3}`] as GlobalRouteHandler)({
|
||||
req,
|
||||
globalConfig,
|
||||
})
|
||||
}
|
||||
break
|
||||
case 4:
|
||||
if (`doc-${slug3}-by-id` in endpoints.global.GET) {
|
||||
// /globals/:slug/versions/:id
|
||||
return (endpoints.global.GET?.[`doc-${slug3}-by-id`] as GlobalRouteHandlerWithID)({
|
||||
req,
|
||||
id: slug4,
|
||||
globalConfig,
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
} else if (slug.length === 1 && slug1 === 'access') {
|
||||
return endpoints.root.GET.access({ req })
|
||||
}
|
||||
|
||||
// root routes
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
payloadRequest: req,
|
||||
endpoints: req.payload.config.endpoints,
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const POST = async (
|
||||
request: Request,
|
||||
{ params: { slug } }: { params: { slug: string[] } },
|
||||
) => {
|
||||
const [slug1, slug2, slug3, slug4] = slug
|
||||
let req: PayloadRequest
|
||||
let collection: Collection
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: { collection: slug1 },
|
||||
})
|
||||
collection = req.payload.collections?.[slug1]
|
||||
|
||||
if (collection) {
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: slug1,
|
||||
payloadRequest: req,
|
||||
endpoints: collection.config?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 1:
|
||||
// /:collection
|
||||
return endpoints.collection.POST.create({ req, collection })
|
||||
case 2:
|
||||
if (slug2 in endpoints.collection.POST) {
|
||||
// /:collection/login
|
||||
// /:collection/logout
|
||||
// /:collection/unlock
|
||||
// /:collection/access
|
||||
// /:collection/first-register
|
||||
// /:collection/forgot-password
|
||||
// /:collection/reset-password
|
||||
// /:collection/refresh-token
|
||||
return (endpoints.collection.POST?.[slug2] as CollectionRouteHandler)({
|
||||
req,
|
||||
collection,
|
||||
})
|
||||
}
|
||||
break
|
||||
case 3:
|
||||
if (`doc-${slug2}-by-id` in endpoints.collection.POST) {
|
||||
// /:collection/access/:id
|
||||
// /:collection/versions/:id
|
||||
// /:collection/verify/:token ("doc-verify-by-id" uses id as token internally)
|
||||
return (
|
||||
endpoints.collection.POST[`doc-${slug2}-by-id`] as CollectionRouteHandlerWithID
|
||||
)({ req, id: slug3, collection })
|
||||
}
|
||||
break
|
||||
}
|
||||
} else if (slug1 === 'globals' && slug2) {
|
||||
const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2)
|
||||
|
||||
switch (slug.length) {
|
||||
case 2:
|
||||
// /globals/:slug
|
||||
return endpoints.global.POST.update({ req, globalConfig })
|
||||
case 3:
|
||||
if (`doc-${slug3}` in endpoints.global.POST) {
|
||||
// /globals/:slug/access
|
||||
return (endpoints.global.POST?.[`doc-${slug3}`] as GlobalRouteHandler)({
|
||||
req,
|
||||
globalConfig,
|
||||
})
|
||||
}
|
||||
break
|
||||
case 4:
|
||||
if (`doc-${slug3}-by-id` in endpoints.global.POST) {
|
||||
// /globals/:slug/versions/:id
|
||||
return (endpoints.global.POST?.[`doc-${slug3}-by-id`] as GlobalRouteHandlerWithID)({
|
||||
req,
|
||||
id: slug4,
|
||||
globalConfig,
|
||||
})
|
||||
}
|
||||
break
|
||||
default:
|
||||
return new Response('Route Not Found', { status: 404 })
|
||||
}
|
||||
}
|
||||
|
||||
// root routes
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
payloadRequest: req,
|
||||
endpoints: req.payload.config.endpoints,
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const DELETE = async (
|
||||
request: Request,
|
||||
{ params: { slug } }: { params: { slug: string[] } },
|
||||
) => {
|
||||
const [slug1, slug2] = slug
|
||||
let req: PayloadRequest
|
||||
let collection: Collection
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: {
|
||||
collection: slug1,
|
||||
},
|
||||
})
|
||||
collection = req.payload.collections?.[slug1]
|
||||
|
||||
if (collection) {
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: slug1,
|
||||
payloadRequest: req,
|
||||
endpoints: collection.config?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 1:
|
||||
// /:collection
|
||||
return endpoints.collection.DELETE.delete({ req, collection })
|
||||
case 2:
|
||||
// /:collection/:id
|
||||
return endpoints.collection.DELETE.deleteByID({ req, id: slug2, collection })
|
||||
}
|
||||
}
|
||||
|
||||
// root routes
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
payloadRequest: req,
|
||||
endpoints: req.payload.config.endpoints,
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const PATCH = async (
|
||||
request: Request,
|
||||
{ params: { slug } }: { params: { slug: string[] } },
|
||||
) => {
|
||||
const [slug1, slug2] = slug
|
||||
let req: PayloadRequest
|
||||
let collection: Collection
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: {
|
||||
collection: slug1,
|
||||
},
|
||||
})
|
||||
collection = req.payload.collections?.[slug1]
|
||||
|
||||
if (collection) {
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: slug1,
|
||||
payloadRequest: req,
|
||||
endpoints: collection.config?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 1:
|
||||
// /:collection
|
||||
return endpoints.collection.PATCH.update({ req, collection })
|
||||
case 2:
|
||||
// /:collection/:id
|
||||
return endpoints.collection.PATCH.updateByID({ req, id: slug2, collection })
|
||||
}
|
||||
}
|
||||
|
||||
// root routes
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
payloadRequest: req,
|
||||
endpoints: req.payload.config.endpoints,
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
})
|
||||
}
|
||||
}
|
||||
export { GRAPHQL_POST, GRAPHQL_PLAYGROUND_GET } from './graphql'
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import path from 'path'
|
||||
import config from 'payload-config'
|
||||
import { streamFile } from '../../../next-stream-file'
|
||||
import { streamFile } from '../../../../../next-stream-file'
|
||||
import fsPromises from 'fs/promises'
|
||||
import { Collection, PayloadRequest, Where } from 'payload/types'
|
||||
import type { Collection, PayloadRequest, SanitizedConfig, Where } from 'payload/types'
|
||||
import executeAccess from 'payload/dist/auth/executeAccess'
|
||||
import { APIError, Forbidden } from 'payload/errors'
|
||||
import { RouteError } from '../../RouteError'
|
||||
import { createPayloadRequest } from '../../../utilities/createPayloadRequest'
|
||||
import { RouteError } from '../../../RouteError'
|
||||
import { createPayloadRequest } from '../../../../../utilities/createPayloadRequest'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
async function checkFileAccess({
|
||||
@@ -60,8 +59,9 @@ async function checkFileAccess({
|
||||
}
|
||||
|
||||
export const GET =
|
||||
(collectionSlug: string) =>
|
||||
async (request: Request, { params }: { params: { filename: string } }) => {
|
||||
(config: Promise<SanitizedConfig>) =>
|
||||
async (request: Request, { params }: { params: { collection: string; filename: string } }) => {
|
||||
const { collection: collectionSlug, filename } = params
|
||||
let req: PayloadRequest
|
||||
let collection: Collection
|
||||
|
||||
@@ -91,14 +91,6 @@ export const GET =
|
||||
)
|
||||
}
|
||||
|
||||
const { filename } = params
|
||||
if (!filename) {
|
||||
throw new APIError(
|
||||
'No filename provided, ensure this route is within a [filename] folder, i.e. staticDir/[filename]/route.ts',
|
||||
httpStatus.BAD_REQUEST,
|
||||
)
|
||||
}
|
||||
|
||||
await checkFileAccess({
|
||||
req,
|
||||
filename,
|
||||
484
packages/next/src/routes/rest/index.ts
Normal file
484
packages/next/src/routes/rest/index.ts
Normal file
@@ -0,0 +1,484 @@
|
||||
import httpStatus from 'http-status'
|
||||
import type { Collection, GlobalConfig, PayloadRequest, SanitizedConfig } from 'payload/types'
|
||||
import type { Endpoint } from 'payload/config'
|
||||
import { match } from 'path-to-regexp'
|
||||
|
||||
import { createPayloadRequest } from '../../utilities/createPayloadRequest'
|
||||
import {
|
||||
CollectionRouteHandler,
|
||||
CollectionRouteHandlerWithID,
|
||||
GlobalRouteHandler,
|
||||
GlobalRouteHandlerWithID,
|
||||
} from './types'
|
||||
|
||||
import { me } from './auth/me'
|
||||
import { init } from './auth/init'
|
||||
import { login } from './auth/login'
|
||||
import { unlock } from './auth/unlock'
|
||||
import { access } from './auth/access'
|
||||
import { logout } from './auth/logout'
|
||||
import { refresh } from './auth/refresh'
|
||||
|
||||
import { find } from './collections/find'
|
||||
import { create } from './collections/create'
|
||||
import { update } from './collections/update'
|
||||
import { deleteDoc } from './collections/delete'
|
||||
import { verifyEmail } from './auth/verifyEmail'
|
||||
import { findByID } from './collections/findByID'
|
||||
import { docAccess } from './collections/docAccess'
|
||||
import { resetPassword } from './auth/resetPassword'
|
||||
import { updateByID } from './collections/updateByID'
|
||||
import { deleteByID } from './collections/deleteByID'
|
||||
import { forgotPassword } from './auth/forgotPassword'
|
||||
import { findVersions } from './collections/findVersions'
|
||||
import { registerFirstUser } from './auth/registerFirstUser'
|
||||
import { restoreVersion } from './collections/restoreVersion'
|
||||
import { findVersionByID } from './collections/findVersionByID'
|
||||
|
||||
import { findOne } from './globals/findOne'
|
||||
import { update as updateGlobal } from './globals/update'
|
||||
import { docAccess as docAccessGlobal } from './globals/docAccess'
|
||||
import { findVersions as findVersionsGlobal } from './globals/findVersions'
|
||||
import { restoreVersion as restoreVersionGlobal } from './globals/restoreVersion'
|
||||
import { findVersionByID as findVersionByIdGlobal } from './globals/findVersionByID'
|
||||
import { RouteError } from './RouteError'
|
||||
|
||||
const endpoints = {
|
||||
root: {
|
||||
GET: {
|
||||
access,
|
||||
},
|
||||
},
|
||||
collection: {
|
||||
GET: {
|
||||
init,
|
||||
me,
|
||||
versions: findVersions,
|
||||
find,
|
||||
findByID,
|
||||
'doc-access-by-id': docAccess,
|
||||
'doc-versions-by-id': findVersionByID,
|
||||
},
|
||||
POST: {
|
||||
create,
|
||||
login,
|
||||
logout,
|
||||
unlock,
|
||||
access: docAccess,
|
||||
'first-register': registerFirstUser,
|
||||
'forgot-password': forgotPassword,
|
||||
'reset-password': resetPassword,
|
||||
'refresh-token': refresh,
|
||||
'doc-access-by-id': docAccess,
|
||||
'doc-versions-by-id': restoreVersion,
|
||||
'doc-verify-by-id': verifyEmail,
|
||||
},
|
||||
PATCH: {
|
||||
update,
|
||||
updateByID,
|
||||
},
|
||||
DELETE: {
|
||||
delete: deleteDoc,
|
||||
deleteByID,
|
||||
},
|
||||
},
|
||||
global: {
|
||||
GET: {
|
||||
findOne,
|
||||
'doc-access': docAccessGlobal,
|
||||
'doc-versions': findVersionsGlobal,
|
||||
'doc-versions-by-id': findVersionByIdGlobal,
|
||||
},
|
||||
POST: {
|
||||
update: updateGlobal,
|
||||
'doc-access': docAccessGlobal,
|
||||
'doc-versions-by-id': restoreVersionGlobal,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const handleCustomEndpoints = ({
|
||||
entitySlug,
|
||||
endpoints,
|
||||
payloadRequest,
|
||||
}: {
|
||||
entitySlug?: string
|
||||
endpoints: Endpoint[] | GlobalConfig['endpoints']
|
||||
payloadRequest: PayloadRequest
|
||||
}): Promise<Response> | Response => {
|
||||
if (endpoints && endpoints.length > 0) {
|
||||
let handlerParams = {}
|
||||
const { pathname } = payloadRequest
|
||||
const pathPrefix =
|
||||
payloadRequest.payload.config.routes.api + (entitySlug ? `/${entitySlug}` : '')
|
||||
|
||||
const customEndpoint = endpoints.find((endpoint) => {
|
||||
if (endpoint.method === payloadRequest.method.toLowerCase()) {
|
||||
const pathMatchFn = match(`${pathPrefix}${endpoint.path}`, {
|
||||
decode: decodeURIComponent,
|
||||
})
|
||||
const tempParams = pathMatchFn(pathname)
|
||||
if (tempParams) {
|
||||
handlerParams = tempParams.params
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (customEndpoint) {
|
||||
return customEndpoint.handler({
|
||||
req: payloadRequest,
|
||||
routeParams: handlerParams,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const RouteNotFoundResponse = (slug: string[]) =>
|
||||
Response.json(
|
||||
{
|
||||
message: `Route Not Found: "${slug.join('/')}"`,
|
||||
},
|
||||
{ status: httpStatus.NOT_FOUND },
|
||||
)
|
||||
|
||||
export const GET =
|
||||
(config: Promise<SanitizedConfig>) =>
|
||||
async (request: Request, { params: { slug } }: { params: { slug: string[] } }) => {
|
||||
const [slug1, slug2, slug3, slug4] = slug
|
||||
let req: PayloadRequest
|
||||
let res: Response
|
||||
let collection: Collection
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: {
|
||||
collection: slug1,
|
||||
},
|
||||
})
|
||||
|
||||
collection = req.payload.collections?.[slug1]
|
||||
|
||||
if (collection) {
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: slug1,
|
||||
payloadRequest: req,
|
||||
endpoints: collection.config?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 1:
|
||||
// /:collection
|
||||
res = await endpoints.collection.GET.find({ req, collection })
|
||||
break
|
||||
case 2:
|
||||
if (slug2 in endpoints.collection.GET) {
|
||||
// /:collection/init
|
||||
// /:collection/me
|
||||
// /:collection/versions
|
||||
res = await (endpoints.collection.GET[slug2] as CollectionRouteHandler)({
|
||||
req,
|
||||
collection,
|
||||
})
|
||||
} else {
|
||||
// /:collection/:id
|
||||
res = await endpoints.collection.GET.findByID({ req, id: slug2, collection })
|
||||
}
|
||||
break
|
||||
case 3:
|
||||
if (`doc-${slug2}-by-id` in endpoints.collection.GET) {
|
||||
// /:collection/access/:id
|
||||
// /:collection/versions/:id
|
||||
res = await (
|
||||
endpoints.collection.GET[`doc-${slug2}-by-id`] as CollectionRouteHandlerWithID
|
||||
)({ req, id: slug3, collection })
|
||||
}
|
||||
break
|
||||
}
|
||||
} else if (slug1 === 'globals') {
|
||||
const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2)
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: `${slug1}/${slug2}`,
|
||||
payloadRequest: req,
|
||||
endpoints: globalConfig?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 2:
|
||||
// /globals/:slug
|
||||
res = await endpoints.global.GET.findOne({ req, globalConfig })
|
||||
break
|
||||
case 3:
|
||||
if (`doc-${slug3}` in endpoints.global.GET) {
|
||||
// /globals/:slug/access
|
||||
// /globals/:slug/versions
|
||||
res = await (endpoints.global.GET?.[`doc-${slug3}`] as GlobalRouteHandler)({
|
||||
req,
|
||||
globalConfig,
|
||||
})
|
||||
}
|
||||
break
|
||||
case 4:
|
||||
if (`doc-${slug3}-by-id` in endpoints.global.GET) {
|
||||
// /globals/:slug/versions/:id
|
||||
res = await (
|
||||
endpoints.global.GET?.[`doc-${slug3}-by-id`] as GlobalRouteHandlerWithID
|
||||
)({
|
||||
req,
|
||||
id: slug4,
|
||||
globalConfig,
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
} else if (slug.length === 1 && slug1 === 'access') {
|
||||
res = await endpoints.root.GET.access({ req })
|
||||
}
|
||||
|
||||
if (res instanceof Response) return res
|
||||
|
||||
// root routes
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
payloadRequest: req,
|
||||
endpoints: req.payload.config.endpoints,
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const POST =
|
||||
(config: Promise<SanitizedConfig>) =>
|
||||
async (request: Request, { params: { slug } }: { params: { slug: string[] } }) => {
|
||||
const [slug1, slug2, slug3, slug4] = slug
|
||||
let req: PayloadRequest
|
||||
let res: Response
|
||||
let collection: Collection
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: { collection: slug1 },
|
||||
})
|
||||
collection = req.payload.collections?.[slug1]
|
||||
|
||||
if (collection) {
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: slug1,
|
||||
payloadRequest: req,
|
||||
endpoints: collection.config?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 1:
|
||||
// /:collection
|
||||
res = await endpoints.collection.POST.create({ req, collection })
|
||||
break
|
||||
case 2:
|
||||
if (slug2 in endpoints.collection.POST) {
|
||||
// /:collection/login
|
||||
// /:collection/logout
|
||||
// /:collection/unlock
|
||||
// /:collection/access
|
||||
// /:collection/first-register
|
||||
// /:collection/forgot-password
|
||||
// /:collection/reset-password
|
||||
// /:collection/refresh-token
|
||||
res = await (endpoints.collection.POST?.[slug2] as CollectionRouteHandler)({
|
||||
req,
|
||||
collection,
|
||||
})
|
||||
}
|
||||
break
|
||||
case 3:
|
||||
if (`doc-${slug2}-by-id` in endpoints.collection.POST) {
|
||||
// /:collection/access/:id
|
||||
// /:collection/versions/:id
|
||||
// /:collection/verify/:token ("doc-verify-by-id" uses id as token internally)
|
||||
res = await (
|
||||
endpoints.collection.POST[`doc-${slug2}-by-id`] as CollectionRouteHandlerWithID
|
||||
)({ req, id: slug3, collection })
|
||||
}
|
||||
break
|
||||
}
|
||||
} else if (slug1 === 'globals' && slug2) {
|
||||
const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2)
|
||||
|
||||
switch (slug.length) {
|
||||
case 2:
|
||||
// /globals/:slug
|
||||
res = await endpoints.global.POST.update({ req, globalConfig })
|
||||
break
|
||||
case 3:
|
||||
if (`doc-${slug3}` in endpoints.global.POST) {
|
||||
// /globals/:slug/access
|
||||
res = await (endpoints.global.POST?.[`doc-${slug3}`] as GlobalRouteHandler)({
|
||||
req,
|
||||
globalConfig,
|
||||
})
|
||||
}
|
||||
break
|
||||
case 4:
|
||||
if (`doc-${slug3}-by-id` in endpoints.global.POST) {
|
||||
// /globals/:slug/versions/:id
|
||||
res = await (
|
||||
endpoints.global.POST?.[`doc-${slug3}-by-id`] as GlobalRouteHandlerWithID
|
||||
)({
|
||||
req,
|
||||
id: slug4,
|
||||
globalConfig,
|
||||
})
|
||||
}
|
||||
break
|
||||
default:
|
||||
res = new Response('Route Not Found', { status: 404 })
|
||||
}
|
||||
}
|
||||
|
||||
if (res instanceof Response) return res
|
||||
|
||||
// root routes
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
payloadRequest: req,
|
||||
endpoints: req.payload.config.endpoints,
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const DELETE =
|
||||
(config: Promise<SanitizedConfig>) =>
|
||||
async (request: Request, { params: { slug } }: { params: { slug: string[] } }) => {
|
||||
const [slug1, slug2] = slug
|
||||
let req: PayloadRequest
|
||||
let res: Response
|
||||
let collection: Collection
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: {
|
||||
collection: slug1,
|
||||
},
|
||||
})
|
||||
collection = req.payload.collections?.[slug1]
|
||||
|
||||
if (collection) {
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: slug1,
|
||||
payloadRequest: req,
|
||||
endpoints: collection.config?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 1:
|
||||
// /:collection
|
||||
res = await endpoints.collection.DELETE.delete({ req, collection })
|
||||
break
|
||||
case 2:
|
||||
// /:collection/:id
|
||||
res = await endpoints.collection.DELETE.deleteByID({ req, id: slug2, collection })
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (res instanceof Response) return res
|
||||
|
||||
// root routes
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
payloadRequest: req,
|
||||
endpoints: req.payload.config.endpoints,
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const PATCH =
|
||||
(config: Promise<SanitizedConfig>) =>
|
||||
async (request: Request, { params: { slug } }: { params: { slug: string[] } }) => {
|
||||
const [slug1, slug2] = slug
|
||||
let req: PayloadRequest
|
||||
let res: Response
|
||||
let collection: Collection
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: {
|
||||
collection: slug1,
|
||||
},
|
||||
})
|
||||
collection = req.payload.collections?.[slug1]
|
||||
|
||||
if (collection) {
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
entitySlug: slug1,
|
||||
payloadRequest: req,
|
||||
endpoints: collection.config?.endpoints || [],
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
switch (slug.length) {
|
||||
case 1:
|
||||
// /:collection
|
||||
res = await endpoints.collection.PATCH.update({ req, collection })
|
||||
break
|
||||
case 2:
|
||||
// /:collection/:id
|
||||
res = await endpoints.collection.PATCH.updateByID({ req, id: slug2, collection })
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (res instanceof Response) return res
|
||||
|
||||
// root routes
|
||||
const customEndpointResponse = await handleCustomEndpoints({
|
||||
payloadRequest: req,
|
||||
endpoints: req.payload.config.endpoints,
|
||||
})
|
||||
if (customEndpointResponse) return customEndpointResponse
|
||||
|
||||
return RouteNotFoundResponse(slug)
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user