chore: start to remove reliance on express specific functionality

This commit is contained in:
Jarrod Flesch
2023-12-08 08:51:23 -05:00
parent 02d95e90b4
commit b651b5cb48
159 changed files with 1196 additions and 503 deletions

22
.vscode/settings.json vendored
View File

@@ -35,5 +35,25 @@
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }], "eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
// Load .git-blame-ignore-revs file // Load .git-blame-ignore-revs file
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"] "gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"],
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#ea59b2",
"activityBar.background": "#ea59b2",
"activityBar.foreground": "#15202b",
"activityBar.inactiveForeground": "#15202b99",
"activityBarBadge.background": "#96e21d",
"activityBarBadge.foreground": "#15202b",
"commandCenter.border": "#e7e7e799",
"sash.hoverBorder": "#ea59b2",
"statusBar.background": "#e42c9d",
"statusBar.foreground": "#e7e7e7",
"statusBarItem.hoverBackground": "#ea59b2",
"statusBarItem.remoteBackground": "#e42c9d",
"statusBarItem.remoteForeground": "#e7e7e7",
"titleBar.activeBackground": "#e42c9d",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveBackground": "#e42c9d99",
"titleBar.inactiveForeground": "#e7e7e799"
},
"peacock.color": "#e42c9d"
} }

View File

@@ -0,0 +1,4 @@
import { login } from '@payloadcms/next/routes/login'
import config from 'payload-config'
export const POST = login({ config })

View File

@@ -0,0 +1,6 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import { login } from '@payloadcms/next/routes/login'
import config from 'payload-config'
export const POST = login({ config })

View File

@@ -0,0 +1,6 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import { me } from '@payloadcms/next/routes/me'
import config from 'payload-config'
export const POST = me({ config })

View File

@@ -0,0 +1,9 @@
import { PayloadRequest, SanitizedConfig } from 'payload/types'
type Args = {
config: SanitizedConfig
req: PayloadRequest
}
export const authenticate = async ({ config, req }: Args): Promise<PayloadRequest> => {
return req
}

View File

@@ -1,17 +1,70 @@
import type { SanitizedConfig, PayloadRequest } from 'payload/types' import type { SanitizedConfig, PayloadRequest, CustomPayloadRequest } from 'payload/types'
import { getAuthenticatedUser } from 'payload/auth'
import { getPayload } from 'payload' import { getPayload } from 'payload'
import { URL } from 'url'
type Args = { type Args = {
request: Request request: Request
config: Promise<SanitizedConfig> config: Promise<SanitizedConfig>
params?: {
collection: string
}
} }
export const createPayloadRequest = async ({ request, config }: Args): Promise<PayloadRequest> => { export const createPayloadRequest = async ({
request,
config,
params,
}: Args): Promise<PayloadRequest> => {
const payload = await getPayload({ config }) const payload = await getPayload({ config })
const req: PayloadRequest = Object.assign(request, { let collection = undefined
if (params?.collection && payload.collections?.[params.collection]) {
collection = payload.collections[params.collection]
}
const { searchParams, pathname } = new URL(request.url)
const isGraphQL =
!payload.config.graphQL.disable && pathname === `/api${payload.config.routes.graphQL}`
const customRequest: CustomPayloadRequest = {
payload, payload,
user: null,
context: {},
collection,
payloadAPI: isGraphQL ? 'GraphQL' : 'REST',
// need to add:
// ------------
// - locale
// - fallbackLocale
// - context
// - transactionID
// - findByID
// - i18n
// - payloadDataLoader
// - payloadUploadSizes
// - t
// - files
}
const req: PayloadRequest = Object.assign(request, customRequest)
req.user = getAuthenticatedUser({
payload,
headers: req.headers,
searchParams,
isGraphQL,
}) })
return req return req
} }
// Express specific functionality
// to search for and replace:
// -------------------------------
// req.params
// req.query
// req.body
// req.files
// express/responses/formatSuccess

View File

@@ -0,0 +1,2 @@
export { init } from '../routes/init'
export { login } from '../routes/login'

View File

@@ -4,7 +4,7 @@ import { createPayloadRequest } from '../createPayloadRequest'
export const init = ({ config }: { config: Promise<SanitizedConfig> }) => export const init = ({ config }: { config: Promise<SanitizedConfig> }) =>
async function (request: Request, { params }: { params: { collection: string } }) { async function (request: Request, { params }: { params: { collection: string } }) {
const req = await createPayloadRequest({ request, config }) const req = await createPayloadRequest({ request, config, params })
const initialized = await initOperation({ const initialized = await initOperation({
collection: params.collection, collection: params.collection,

View File

@@ -0,0 +1,27 @@
import { login as loginOperation } from 'payload/operations'
import { createPayloadRequest } from '../createPayloadRequest'
import { SanitizedConfig } from 'payload/types'
export const login = ({ config }: { config: Promise<SanitizedConfig> }) =>
async function (request: Request, { params }: { params: { collection: string } }) {
const data = await request.json()
const req = await createPayloadRequest({ request, config })
const collection = req.payload.collections[params.collection]
const result = await loginOperation({
collection,
data,
// TODO: get searchParams a different way
// depth: searchParams.get('depth')
// ? parseInt(String(searchParams.get('depth')), 10)
// : undefined,
req,
})
return Response.json({
exp: result.exp,
message: 'Auth Passed',
token: result.token,
user: result.user,
})
}

View File

@@ -1,3 +1,3 @@
import type { PayloadRequest } from '../express/types' import type { PayloadRequest } from '../types'
export default ({ req: { user } }: { req: PayloadRequest }): boolean => Boolean(user) export default ({ req: { user } }: { req: PayloadRequest }): boolean => Boolean(user)

View File

@@ -0,0 +1,13 @@
import type { AuthStrategyFunctionArgs, User } from '.'
export const getAuthenticatedUser = async (
args: AuthStrategyFunctionArgs,
): Promise<User | null> => {
return args.payload.authStrategies.reduce(async (accumulatorPromise, strategy) => {
const authUser = await accumulatorPromise
if (!authUser) {
return strategy.authenticate(args)
}
return authUser
}, Promise.resolve(null))
}

View File

@@ -1,7 +1,9 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import { URL } from 'url'
import type { SanitizedCollectionConfig } from '../collections/config/types' import type { SanitizedCollectionConfig } from '../collections/config/types'
import type { PayloadRequest } from '../express/types' import type { PayloadRequest } from '../types'
import type { Where } from '../types' import type { Where } from '../types'
import { Forbidden } from '../errors' import { Forbidden } from '../errors'
@@ -15,14 +17,15 @@ const getExecuteStaticAccess =
} }
try { try {
if (req.path) { const { pathname } = new URL(req.url)
if (pathname) {
const accessResult = await executeAccess( const accessResult = await executeAccess(
{ isReadingStaticFile: true, req }, { isReadingStaticFile: true, req },
config.access.read, config.access.read,
) )
if (typeof accessResult === 'object') { if (typeof accessResult === 'object') {
const filename = decodeURI(req.path).replace(/^\/|\/$/g, '') const filename = decodeURI(pathname).replace(/^\/|\/$/g, '')
const queryToBuild: Where = { const queryToBuild: Where = {
and: [ and: [

View File

@@ -1,40 +1,35 @@
import type { Request } from 'express' import type { AuthStrategyFunctionArgs } from '.'
import type { SanitizedConfig } from '../config/types'
import parseCookies from '../utilities/parseCookies' import parseCookies from '../utilities/parseCookies'
const getExtractJWT = export const extractJWT = (
(config: SanitizedConfig) => args: Pick<AuthStrategyFunctionArgs, 'headers' | 'payload'>,
(req: Request): null | string => { ): null | string => {
if (!req?.get) { const { headers, payload } = args
return null
}
const jwtFromHeader = req.get('Authorization') const jwtFromHeader = headers.get('Authorization')
const origin = req.get('Origin') const origin = headers.get('Origin')
if (jwtFromHeader?.indexOf('JWT ') === 0) { if (jwtFromHeader?.startsWith('JWT ')) {
return jwtFromHeader.replace('JWT ', '') return jwtFromHeader.replace('JWT ', '')
} }
// allow RFC6750 OAuth 2.0 compliant Bearer tokens // allow RFC6750 OAuth 2.0 compliant Bearer tokens
// in addition to the payload default JWT format // in addition to the payload default JWT format
if (jwtFromHeader?.indexOf('Bearer ') === 0) { if (jwtFromHeader?.startsWith('Bearer ')) {
return jwtFromHeader.replace('Bearer ', '') return jwtFromHeader.replace('Bearer ', '')
} }
const cookies = parseCookies(req) const cookies = parseCookies(headers)
const tokenCookieName = `${config.cookiePrefix}-token` const tokenCookieName = `${payload.config.cookiePrefix}-token`
const cookieToken = cookies.get(tokenCookieName)
if (!cookies?.[tokenCookieName]) {
return null
}
if (!origin || config.csrf.length === 0 || config.csrf.indexOf(origin) > -1) {
return cookies[tokenCookieName]
}
if (!cookieToken) {
return null return null
} }
export default getExtractJWT if (!origin || payload.config.csrf.length === 0 || payload.config.csrf.indexOf(origin) > -1) {
return cookieToken
}
return null
}

View File

@@ -1,14 +1,13 @@
import type { Collection } from '../../../collections/config/types' import type { Collection } from '../../../collections/config/types'
import isolateTransactionID from '../../../utilities/isolateTransactionID' import isolateTransactionID from '../../../utilities/isolateTransactionID'
import getExtractJWT from '../../getExtractJWT' import { extractJWT } from '../../getExtractJWT'
import refresh from '../../operations/refresh' import refresh from '../../operations/refresh'
function refreshResolver(collection: Collection) { function refreshResolver(collection: Collection) {
async function resolver(_, args, context) { async function resolver(_, args, context) {
let token let token
const extractJWT = getExtractJWT(context.req.payload.config)
token = extractJWT(context.req) token = extractJWT(context.req)
if (args.token) { if (args.token) {

View File

@@ -2,7 +2,7 @@ import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Permissions } from '../types' import type { Permissions } from '../types'
import access from '../operations/access' import access from '../operations/access'

View File

@@ -2,7 +2,7 @@ import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import forgotPassword from '../operations/forgotPassword' import forgotPassword from '../operations/forgotPassword'
@@ -14,6 +14,7 @@ export default async function forgotPasswordHandler(
try { try {
await forgotPassword({ await forgotPassword({
collection: req.collection, collection: req.collection,
// TODO(JARROD): remove reliance on express body parsing
data: { email: req.body.email }, data: { email: req.body.email },
disableEmail: req.body.disableEmail, disableEmail: req.body.disableEmail,
expiration: req.body.expiration, expiration: req.body.expiration,

View File

@@ -1,10 +1,12 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { URL } from 'url'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Result } from '../operations/login' import type { Result } from '../operations/login'
import { isNumber } from '../../utilities/isNumber'
import login from '../operations/login' import login from '../operations/login'
export default async function loginHandler( export default async function loginHandler(
@@ -13,10 +15,14 @@ export default async function loginHandler(
next: NextFunction, next: NextFunction,
): Promise<Response<Result & { message: string }> | void> { ): Promise<Response<Result & { message: string }> | void> {
try { try {
const searchParams = new URL(req.url).searchParams
const depth = searchParams.get('depth')
const result = await login({ const result = await login({
collection: req.collection, collection: req.collection,
// TODO(JARROD): remove reliance on express body parsing
data: req.body, data: req.body,
depth: parseInt(String(req.query.depth), 10), depth: isNumber(depth) ? depth : undefined,
req, req,
res, res,
}) })

View File

@@ -2,7 +2,7 @@ import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import logout from '../operations/logout' import logout from '../operations/logout'

View File

@@ -1,6 +1,6 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import me from '../operations/me' import me from '../operations/me'

View File

@@ -1,8 +1,8 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import getExtractJWT from '../getExtractJWT' import { extractJWT } from '../getExtractJWT'
import refresh from '../operations/refresh' import refresh from '../operations/refresh'
export default async function refreshHandler( export default async function refreshHandler(
@@ -13,11 +13,10 @@ export default async function refreshHandler(
try { try {
let token let token
const extractJWT = getExtractJWT(req.payload.config)
token = extractJWT(req) token = extractJWT(req)
if (req.body.token) { if (req.body) {
token = req.body.token token = req.body.data
} }
const result = await refresh({ const result = await refresh({

View File

@@ -1,6 +1,6 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import registerFirstUser from '../operations/registerFirstUser' import registerFirstUser from '../operations/registerFirstUser'
@@ -12,6 +12,7 @@ export default async function registerFirstUserHandler(
try { try {
const firstUser = await registerFirstUser({ const firstUser = await registerFirstUser({
collection: req.collection, collection: req.collection,
// TODO(JARROD): remove reliance on express body parsing
data: req.body, data: req.body,
req, req,
res, res,

View File

@@ -2,7 +2,7 @@ import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import resetPassword from '../operations/resetPassword' import resetPassword from '../operations/resetPassword'
@@ -14,6 +14,7 @@ async function resetPasswordHandler(
try { try {
const result = await resetPassword({ const result = await resetPassword({
collection: req.collection, collection: req.collection,
// TODO(JARROD): remove reliance on express body parsing
data: req.body, data: req.body,
req, req,
res, res,

View File

@@ -2,7 +2,7 @@ import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import unlock from '../operations/unlock' import unlock from '../operations/unlock'
@@ -14,6 +14,7 @@ export default async function unlockHandler(
try { try {
await unlock({ await unlock({
collection: req.collection, collection: req.collection,
// TODO(JARROD): remove reliance on express body parsing
data: { email: req.body.email }, data: { email: req.body.email },
req, req,
}) })

View File

@@ -1,8 +1,9 @@
// TODO(JARROD): remove reliance on express
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import verifyEmail from '../operations/verifyEmail' import verifyEmail from '../operations/verifyEmail'

View File

@@ -1,4 +1,4 @@
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { AllOperations } from '../../types' import type { AllOperations } from '../../types'
import type { Permissions } from '../types' import type { Permissions } from '../types'

View File

@@ -1,7 +1,8 @@
import crypto from 'crypto' import crypto from 'crypto'
import { URL } from 'url'
import type { Collection } from '../../collections/config/types' import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import { buildAfterOperation } from '../../collections/operations/utils' import { buildAfterOperation } from '../../collections/operations/utils'
import { APIError } from '../../errors' import { APIError } from '../../errors'
@@ -97,10 +98,11 @@ async function forgotPassword(incomingArgs: Arguments): Promise<null | string> {
}) })
if (!disableEmail) { if (!disableEmail) {
const protocol = new URL(req.url).protocol
const serverURL = const serverURL =
config.serverURL !== null && config.serverURL !== '' config.serverURL !== null && config.serverURL !== ''
? config.serverURL ? config.serverURL
: `${req.protocol}://${req.get('host')}` : `${protocol}://${req.headers.get('host')}`
let html = `${t('authentication:youAreReceivingResetPassword')} let html = `${t('authentication:youAreReceivingResetPassword')}
<a href="${serverURL}${config.routes.admin}/reset/${token}"> <a href="${serverURL}${config.routes.admin}/reset/${token}">

View File

@@ -1,12 +1,11 @@
import type { GeneratedTypes } from '../../..' import type { GeneratedTypes, PayloadT } from '../../..'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Payload } from '../../../payload'
import type { Result } from '../forgotPassword' import type { Result } from '../forgotPassword'
import { getDataLoader } from '../../../collections/dataloader' import { getDataLoader } from '../../../collections/dataloader'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import forgotPassword from '../forgotPassword' import forgotPassword from '../forgotPassword'
export type Options<T extends keyof GeneratedTypes['collections']> = { export type Options<T extends keyof GeneratedTypes['collections']> = {
@@ -20,7 +19,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
} }
async function localForgotPassword<T extends keyof GeneratedTypes['collections']>( async function localForgotPassword<T extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<T>, options: Options<T>,
): Promise<Result> { ): Promise<Result> {
const { const {

View File

@@ -1,14 +1,14 @@
import type { Response } from 'express' import type { Response } from 'express'
import type { PayloadRequest } from '../../../express/types' import type { PayloadT } from '../../..'
import type { GeneratedTypes } from '../../../index' import type { GeneratedTypes } from '../../../index'
import type { Payload } from '../../../payload' import type { PayloadRequest } from '../../../types'
import type { Result } from '../login' import type { Result } from '../login'
import { getDataLoader } from '../../../collections/dataloader' import { getDataLoader } from '../../../collections/dataloader'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import login from '../login' import login from '../login'
export type Options<TSlug extends keyof GeneratedTypes['collections']> = { export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
@@ -27,7 +27,7 @@ export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
} }
async function localLogin<TSlug extends keyof GeneratedTypes['collections']>( async function localLogin<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<TSlug>, options: Options<TSlug>,
): Promise<Result & { user: GeneratedTypes['collections'][TSlug] }> { ): Promise<Result & { user: GeneratedTypes['collections'][TSlug] }> {
const { const {

View File

@@ -1,12 +1,12 @@
import type { PayloadT } from '../../..'
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Payload } from '../../../payload'
import type { Result } from '../resetPassword' import type { Result } from '../resetPassword'
import { getDataLoader } from '../../../collections/dataloader' import { getDataLoader } from '../../../collections/dataloader'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import resetPassword from '../resetPassword' import resetPassword from '../resetPassword'
export type Options<T extends keyof GeneratedTypes['collections']> = { export type Options<T extends keyof GeneratedTypes['collections']> = {
@@ -20,7 +20,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
} }
async function localResetPassword<T extends keyof GeneratedTypes['collections']>( async function localResetPassword<T extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<T>, options: Options<T>,
): Promise<Result> { ): Promise<Result> {
const { collection: collectionSlug, data, overrideAccess, req = {} as PayloadRequest } = options const { collection: collectionSlug, data, overrideAccess, req = {} as PayloadRequest } = options

View File

@@ -1,11 +1,11 @@
import type { PayloadT } from '../../..'
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Payload } from '../../../payload'
import { getDataLoader } from '../../../collections/dataloader' import { getDataLoader } from '../../../collections/dataloader'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import unlock from '../unlock' import unlock from '../unlock'
export type Options<T extends keyof GeneratedTypes['collections']> = { export type Options<T extends keyof GeneratedTypes['collections']> = {
@@ -18,7 +18,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
} }
async function localUnlock<T extends keyof GeneratedTypes['collections']>( async function localUnlock<T extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<T>, options: Options<T>,
): Promise<boolean> { ): Promise<boolean> {
const { const {

View File

@@ -1,10 +1,10 @@
import type { PayloadT } from '../../..'
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Payload } from '../../../payload'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import verifyEmail from '../verifyEmail' import verifyEmail from '../verifyEmail'
export type Options<T extends keyof GeneratedTypes['collections']> = { export type Options<T extends keyof GeneratedTypes['collections']> = {
@@ -14,7 +14,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
} }
async function localVerifyEmail<T extends keyof GeneratedTypes['collections']>( async function localVerifyEmail<T extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<T>, options: Options<T>,
): Promise<boolean> { ): Promise<boolean> {
const { collection: collectionSlug, req = {} as PayloadRequest, token } = options const { collection: collectionSlug, req = {} as PayloadRequest, token } = options

View File

@@ -4,7 +4,7 @@ import jwt from 'jsonwebtoken'
import type { GeneratedTypes } from '../../' import type { GeneratedTypes } from '../../'
import type { Collection } from '../../collections/config/types' import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { User } from '../types' import type { User } from '../types'
import { buildAfterOperation } from '../../collections/operations/utils' import { buildAfterOperation } from '../../collections/operations/utils'

View File

@@ -1,9 +1,10 @@
// TODO(JARROD): remove express Response
import type { Response } from 'express' import type { Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { Collection } from '../../collections/config/types' import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import { APIError } from '../../errors' import { APIError } from '../../errors'

View File

@@ -1,11 +1,11 @@
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import url from 'url' import { URL } from 'url'
import type { Collection } from '../../collections/config/types' import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { User } from '../types' import type { User } from '../types'
import getExtractJWT from '../getExtractJWT' import { extractJWT } from '../getExtractJWT'
export type Result = { export type Result = {
collection?: string collection?: string
@@ -20,13 +20,12 @@ export type Arguments = {
} }
async function me({ collection, req }: Arguments): Promise<Result> { async function me({ collection, req }: Arguments): Promise<Result> {
const extractJWT = getExtractJWT(req.payload.config)
let response: Result = { let response: Result = {
user: null, user: null,
} }
if (req.user) { if (req.user) {
const parsedURL = url.parse(req.originalUrl) const parsedURL = new URL(req.url)
const isGraphQL = parsedURL.pathname === `/api${req.payload.config.routes.graphQL}` const isGraphQL = parsedURL.pathname === `/api${req.payload.config.routes.graphQL}`
const user = (await req.payload.findByID({ const user = (await req.payload.findByID({

View File

@@ -1,10 +1,11 @@
// TODO(JARROD): remove express Response
import type { Response } from 'express' import type { Response } from 'express'
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import url from 'url' import url from 'url'
import type { BeforeOperationHook, Collection } from '../../collections/config/types' import type { BeforeOperationHook, Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Document } from '../../types' import type { Document } from '../../types'
import { buildAfterOperation } from '../../collections/operations/utils' import { buildAfterOperation } from '../../collections/operations/utils'

View File

@@ -1,9 +1,10 @@
// TODO(JARROD): remove express Response
import type { Response } from 'express' import type { Response } from 'express'
import type { MarkOptional } from 'ts-essentials' import type { MarkOptional } from 'ts-essentials'
import type { GeneratedTypes } from '../../' import type { GeneratedTypes } from '../../'
import type { Collection } from '../../collections/config/types' import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import { Forbidden } from '../../errors' import { Forbidden } from '../../errors'
import { commitTransaction } from '../../utilities/commitTransaction' import { commitTransaction } from '../../utilities/commitTransaction'
@@ -17,6 +18,7 @@ export type Arguments<T extends { [field: number | string | symbol]: unknown }>
password: string password: string
} }
req: PayloadRequest req: PayloadRequest
// TODO(JARROD): remove express Response
res: Response res: Response
} }

View File

@@ -1,9 +1,10 @@
// TODO(JARROD): remove express Response
import type { Response } from 'express' import type { Response } from 'express'
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import type { Collection } from '../../collections/config/types' import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import { APIError } from '../../errors' import { APIError } from '../../errors'
import { commitTransaction } from '../../utilities/commitTransaction' import { commitTransaction } from '../../utilities/commitTransaction'
@@ -28,6 +29,7 @@ export type Arguments = {
depth?: number depth?: number
overrideAccess?: boolean overrideAccess?: boolean
req: PayloadRequest req: PayloadRequest
// TODO(JARROD): remove express Response
res?: Response res?: Response
} }

View File

@@ -1,5 +1,5 @@
import type { Collection } from '../../collections/config/types' import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import { APIError } from '../../errors' import { APIError } from '../../errors'
import { commitTransaction } from '../../utilities/commitTransaction' import { commitTransaction } from '../../utilities/commitTransaction'

View File

@@ -1,7 +1,7 @@
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { Collection } from '../../collections/config/types' import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import { APIError } from '../../errors' import { APIError } from '../../errors'
import { commitTransaction } from '../../utilities/commitTransaction' import { commitTransaction } from '../../utilities/commitTransaction'

View File

@@ -1,7 +1,9 @@
import { URL } from 'url'
import type { PayloadT } from '..'
import type { Collection } from '../collections/config/types' import type { Collection } from '../collections/config/types'
import type { EmailOptions, SanitizedConfig } from '../config/types' import type { EmailOptions, SanitizedConfig } from '../config/types'
import type { PayloadRequest } from '../express/types' import type { PayloadRequest } from '../types'
import type { Payload } from '../payload'
import type { User, VerifyConfig } from './types' import type { User, VerifyConfig } from './types'
type Args = { type Args = {
@@ -10,7 +12,7 @@ type Args = {
disableEmail: boolean disableEmail: boolean
emailOptions: EmailOptions emailOptions: EmailOptions
req: PayloadRequest req: PayloadRequest
sendEmail: Payload['sendEmail'] sendEmail: PayloadT['sendEmail']
token: string token: string
user: User user: User
} }
@@ -29,10 +31,11 @@ async function sendVerificationEmail(args: Args): Promise<void> {
} = args } = args
if (!disableEmail) { if (!disableEmail) {
const protocol = new URL(req.url).protocol
const serverURL = const serverURL =
config.serverURL !== null && config.serverURL !== '' config.serverURL !== null && config.serverURL !== ''
? config.serverURL ? config.serverURL
: `${req.protocol}://${req.get('host')}` : `${protocol}://${req.headers.get('host')}`
const verificationURL = `${serverURL}${config.routes.admin}/${collectionConfig.slug}/verify/${token}` const verificationURL = `${serverURL}${config.routes.admin}/${collectionConfig.slug}/verify/${token}`

View File

@@ -1,63 +1,59 @@
import crypto from 'crypto' import crypto from 'crypto'
import PassportAPIKey from 'passport-headerapikey'
import type { AuthStrategyFunction, User } from '..'
import type { SanitizedCollectionConfig } from '../../collections/config/types' import type { SanitizedCollectionConfig } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types' import type { Where } from '../../exports/types'
import type { Payload } from '../../payload'
import find from '../../collections/operations/find' export const APIKeyAuthentication =
(collectionConfig: SanitizedCollectionConfig): AuthStrategyFunction =>
async ({ headers, payload }) => {
const authHeader = headers.get('Authorization')
export default (payload: Payload, config: SanitizedCollectionConfig): PassportAPIKey => { if (authHeader.startsWith(`${collectionConfig.slug} API-Key `)) {
const { secret } = payload const apiKey = authHeader.replace(`${collectionConfig.slug} API-Key `, '')
const opts = { const apiKeyIndex = crypto.createHmac('sha1', payload.secret).update(apiKey).digest('hex')
header: 'Authorization',
prefix: `${config.slug} API-Key `,
}
return new PassportAPIKey(opts, true, async (apiKey, done, req) => { try {
const apiKeyIndex = crypto.createHmac('sha1', secret).update(apiKey).digest('hex') const where: Where = {}
if (collectionConfig.auth?.verify) {
try { where.and = [
const where: { [key: string]: any } = {} {
if (config.auth.verify) { apiKeyIndex: {
where.and = [ equals: apiKeyIndex,
{ },
// TODO: Search for index
apiKeyIndex: {
equals: apiKeyIndex,
}, },
}, {
{ _verified: {
_verified: { not_equals: false,
not_equals: false, },
}, },
}, ]
] } else {
} else { where.apiKeyIndex = {
where.apiKeyIndex = { equals: apiKeyIndex,
equals: apiKeyIndex, }
} }
}
const userQuery = await find({
collection: {
config,
},
depth: config.auth.depth,
overrideAccess: true,
req: req as PayloadRequest,
where,
})
if (userQuery.docs && userQuery.docs.length > 0) { const userQuery = await payload.find({
const user = userQuery.docs[0] collection: collectionConfig.slug,
user.collection = config.slug depth: collectionConfig.auth.depth,
user._strategy = 'api-key' overrideAccess: true,
done(null, user) // TODO(JAMES)(REVIEW): had to remove with new pattern
} else { // req,
done(null, false) where,
})
if (userQuery.docs && userQuery.docs.length > 0) {
const user = userQuery.docs[0]
user.collection = collectionConfig.slug
user._strategy = 'api-key'
return user as User
}
} catch (err) {
return null
} }
} catch (err) {
done(null, false)
} }
})
} return null
}

View File

@@ -1,49 +1,41 @@
import type { StrategyOptions } from 'passport-jwt' import jwt from 'jsonwebtoken'
import type { Strategy as PassportStrategy } from 'passport-strategy'
import passportJwt from 'passport-jwt' import type { AuthStrategyFunction, User } from '..'
import url from 'url'
import type { Payload } from '../../payload' import { extractJWT } from '../getExtractJWT'
import getExtractJWT from '../getExtractJWT' type JWTToken = {
collection: string
const JwtStrategy = passportJwt.Strategy id: string
}
export default ({ collections, config, secret }: Payload): PassportStrategy => {
const opts: StrategyOptions = { export const JWTAuthentication: AuthStrategyFunction = async ({
jwtFromRequest: getExtractJWT(config), headers,
passReqToCallback: true, isGraphQL = false,
secretOrKey: secret, payload,
} }) => {
try {
return new JwtStrategy(opts, async (req, token, done) => { const token = extractJWT({ headers, payload })
if (req.user) { const decodedPayload = jwt.verify(token, payload.secret) as jwt.JwtPayload & JWTToken
done(null, req.user)
} const collection = payload.collections[decodedPayload.collection]
try { const user = await payload.findByID({
const collection = collections[token.collection] id: decodedPayload.id,
collection: decodedPayload.collection,
const parsedURL = url.parse(req.originalUrl) depth: isGraphQL ? 0 : collection.config.auth.depth,
const isGraphQL = parsedURL.pathname === `/api${req.payload.config.routes.graphQL}` // TODO(JAMES)(REVIEW): had to remove with new pattern
// req,
const user = await req.payload.findByID({ })
id: token.id,
collection: token.collection, if (user && (!collection.config.auth.verify || user._verified)) {
depth: isGraphQL ? 0 : collection.config.auth.depth, user.collection = collection.config.slug
req, user._strategy = 'local-jwt'
}) return user as User
} else {
if (user && (!collection.config.auth.verify || user._verified)) { return null
user.collection = collection.config.slug }
user._strategy = 'local-jwt' } catch (error) {
done(null, user) return null
} else { }
done(null, false)
}
} catch (err) {
done(null, false)
}
})
} }

View File

@@ -1,11 +1,11 @@
import type { Payload } from '../../..' import type { PayloadT } from '../../..'
import type { SanitizedCollectionConfig, TypeWithID } from '../../../collections/config/types' import type { SanitizedCollectionConfig, TypeWithID } from '../../../collections/config/types'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
type Args = { type Args = {
collection: SanitizedCollectionConfig collection: SanitizedCollectionConfig
doc: TypeWithID & Record<string, unknown> doc: TypeWithID & Record<string, unknown>
payload: Payload payload: PayloadT
req: PayloadRequest req: PayloadRequest
} }

View File

@@ -1,6 +1,6 @@
import type { Payload } from '../../..' import type { PayloadT } from '../../..'
import type { SanitizedCollectionConfig } from '../../../collections/config/types' import type { SanitizedCollectionConfig } from '../../../collections/config/types'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import { ValidationError } from '../../../errors' import { ValidationError } from '../../../errors'
import { generatePasswordSaltHash } from './generatePasswordSaltHash' import { generatePasswordSaltHash } from './generatePasswordSaltHash'
@@ -9,7 +9,7 @@ type Args = {
collection: SanitizedCollectionConfig collection: SanitizedCollectionConfig
doc: Record<string, unknown> doc: Record<string, unknown>
password: string password: string
payload: Payload payload: PayloadT
req: PayloadRequest req: PayloadRequest
} }

View File

@@ -1,11 +1,11 @@
import type { Payload } from '../../..' import type { PayloadT } from '../../..'
import type { SanitizedCollectionConfig, TypeWithID } from '../../../collections/config/types' import type { SanitizedCollectionConfig, TypeWithID } from '../../../collections/config/types'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
type Args = { type Args = {
collection: SanitizedCollectionConfig collection: SanitizedCollectionConfig
doc: TypeWithID & Record<string, unknown> doc: TypeWithID & Record<string, unknown>
payload: Payload payload: PayloadT
req: PayloadRequest req: PayloadRequest
} }

View File

@@ -1,9 +1,7 @@
import type { Strategy } from 'passport'
import type { DeepRequired } from 'ts-essentials' import type { DeepRequired } from 'ts-essentials'
import type { PayloadRequest } from '../express/types' import type { PayloadT } from '../'
import type { Payload } from '../payload' import type { PayloadRequest, Where } from '../types'
import type { Where } from '../types'
export type Permission = { export type Permission = {
permission: boolean permission: boolean
@@ -91,7 +89,22 @@ type GenerateForgotPasswordEmailSubject = (args?: {
user?: any user?: any
}) => Promise<string> | string }) => Promise<string> | string
type AuthStrategy = ((ctx: Payload) => Strategy) | Strategy export type AuthStrategyFunctionArgs = {
headers: Request['headers']
isGraphQL?: boolean
payload: PayloadT
searchParams: URLSearchParams
}
export type AuthStrategyFunction = ({
headers,
isGraphQL,
payload,
searchParams,
}: AuthStrategyFunctionArgs) => Promise<User | null> | User | null
export type AuthStrategy = {
authenticate: AuthStrategyFunction
name: string
}
export interface IncomingAuthType { export interface IncomingAuthType {
cookies?: { cookies?: {
@@ -108,10 +121,7 @@ export interface IncomingAuthType {
lockTime?: number lockTime?: number
maxLoginAttempts?: number maxLoginAttempts?: number
removeTokenFromResponses?: true removeTokenFromResponses?: true
strategies?: { strategies?: AuthStrategy[]
name?: string
strategy: AuthStrategy
}[]
tokenExpiration?: number tokenExpiration?: number
useAPIKey?: boolean useAPIKey?: boolean
verify?: verify?:

View File

@@ -1,16 +1,16 @@
import type { Endpoint } from '../config/types' import type { Endpoint } from '../config/types'
import type { SanitizedCollectionConfig } from './config/types' import type { SanitizedCollectionConfig } from './config/types'
import forgotPasswordHandler from '../auth/requestHandlers/forgotPassword' import forgotPasswordHandler from '../auth/handlers/forgotPassword'
import initHandler from '../auth/requestHandlers/init' import initHandler from '../auth/handlers/init'
import loginHandler from '../auth/requestHandlers/login' import loginHandler from '../auth/handlers/login'
import logoutHandler from '../auth/requestHandlers/logout' import logoutHandler from '../auth/handlers/logout'
import meHandler from '../auth/requestHandlers/me' import meHandler from '../auth/handlers/me'
import refreshHandler from '../auth/requestHandlers/refresh' import refreshHandler from '../auth/handlers/refresh'
import registerFirstUserHandler from '../auth/requestHandlers/registerFirstUser' import registerFirstUserHandler from '../auth/handlers/registerFirstUser'
import resetPassword from '../auth/requestHandlers/resetPassword' import resetPassword from '../auth/handlers/resetPassword'
import unlock from '../auth/requestHandlers/unlock' import unlock from '../auth/handlers/unlock'
import verifyEmail from '../auth/requestHandlers/verifyEmail' import verifyEmail from '../auth/handlers/verifyEmail'
import create from './requestHandlers/create' import create from './requestHandlers/create'
import deleteHandler from './requestHandlers/delete' import deleteHandler from './requestHandlers/delete'
import deleteByID from './requestHandlers/deleteByID' import deleteByID from './requestHandlers/deleteByID'

View File

@@ -137,6 +137,10 @@ const sanitizeCollection = (
} }
} }
if (!sanitized.auth.strategies) {
sanitized.auth.strategies = []
}
sanitized.fields = mergeBaseFields(sanitized.fields, authFields) sanitized.fields = mergeBaseFields(sanitized.fields, authFields)
} }

View File

@@ -21,8 +21,8 @@ import type {
GeneratePreviewURL, GeneratePreviewURL,
LivePreviewConfig, LivePreviewConfig,
} from '../../config/types' } from '../../config/types'
import type { PayloadRequest, RequestContext } from '../../express/types'
import type { Field } from '../../fields/config/types' import type { Field } from '../../fields/config/types'
import type { PayloadRequest, RequestContext } from '../../types'
import type { IncomingUploadType, Upload } from '../../uploads/types' import type { IncomingUploadType, Upload } from '../../uploads/types'
import type { IncomingCollectionVersions, SanitizedCollectionVersions } from '../../versions/types' import type { IncomingCollectionVersions, SanitizedCollectionVersions } from '../../versions/types'
import type { AfterOperationArg, AfterOperationMap } from '../operations/utils' import type { AfterOperationArg, AfterOperationMap } from '../operations/utils'

View File

@@ -2,7 +2,7 @@ import type { BatchLoadFn } from 'dataloader'
import DataLoader from 'dataloader' import DataLoader from 'dataloader'
import type { PayloadRequest } from '../express/types' import type { PayloadRequest } from '../types'
import type { TypeWithID } from './config/types' import type { TypeWithID } from './config/types'
import { fieldAffectsData } from '../fields/config/types' import { fieldAffectsData } from '../fields/config/types'

View File

@@ -3,7 +3,7 @@ import type { Response } from 'express'
import type { MarkOptional } from 'ts-essentials' import type { MarkOptional } from 'ts-essentials'
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Collection } from '../../config/types' import type { Collection } from '../../config/types'
import isolateTransactionID from '../../../utilities/isolateTransactionID' import isolateTransactionID from '../../../utilities/isolateTransactionID'

View File

@@ -2,7 +2,7 @@
import type { Response } from 'express' import type { Response } from 'express'
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Collection } from '../../config/types' import type { Collection } from '../../config/types'
import isolateTransactionID from '../../../utilities/isolateTransactionID' import isolateTransactionID from '../../../utilities/isolateTransactionID'

View File

@@ -1,5 +1,5 @@
import type { CollectionPermission, GlobalPermission } from '../../../auth' import type { CollectionPermission, GlobalPermission } from '../../../auth'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import isolateTransactionID from '../../../utilities/isolateTransactionID' import isolateTransactionID from '../../../utilities/isolateTransactionID'
import { docAccess } from '../../operations/docAccess' import { docAccess } from '../../operations/docAccess'

View File

@@ -1,6 +1,6 @@
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
import type { PaginatedDocs } from '../../../database/types' import type { PaginatedDocs } from '../../../database/types'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Where } from '../../../types' import type { Where } from '../../../types'
import type { Collection } from '../../config/types' import type { Collection } from '../../config/types'

View File

@@ -1,5 +1,5 @@
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Collection } from '../../config/types' import type { Collection } from '../../config/types'
import isolateTransactionID from '../../../utilities/isolateTransactionID' import isolateTransactionID from '../../../utilities/isolateTransactionID'

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
import type { Response } from 'express' import type { Response } from 'express'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { TypeWithVersion } from '../../../versions/types' import type { TypeWithVersion } from '../../../versions/types'
import type { Collection, TypeWithID } from '../../config/types' import type { Collection, TypeWithID } from '../../config/types'

View File

@@ -3,7 +3,7 @@
import type { Response } from 'express' import type { Response } from 'express'
import type { PaginatedDocs } from '../../../database/types' import type { PaginatedDocs } from '../../../database/types'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Where } from '../../../types' import type { Where } from '../../../types'
import type { Collection } from '../../config/types' import type { Collection } from '../../config/types'

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
import type { Response } from 'express' import type { Response } from 'express'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Collection } from '../../config/types' import type { Collection } from '../../config/types'
import isolateTransactionID from '../../../utilities/isolateTransactionID' import isolateTransactionID from '../../../utilities/isolateTransactionID'

View File

@@ -2,7 +2,7 @@
import type { Response } from 'express' import type { Response } from 'express'
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types' import type { PayloadRequest } from '../../../types'
import type { Collection } from '../../config/types' import type { Collection } from '../../config/types'
import isolateTransactionID from '../../../utilities/isolateTransactionID' import isolateTransactionID from '../../../utilities/isolateTransactionID'

View File

@@ -5,7 +5,7 @@ import fs from 'fs'
import { promisify } from 'util' import { promisify } from 'util'
import type { GeneratedTypes } from '../../' import type { GeneratedTypes } from '../../'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Document } from '../../types' import type { Document } from '../../types'
import type { import type {
AfterChangeHook, AfterChangeHook,

View File

@@ -2,7 +2,7 @@ import httpStatus from 'http-status'
import type { GeneratedTypes } from '../../' import type { GeneratedTypes } from '../../'
import type { AccessResult } from '../../config/types' import type { AccessResult } from '../../config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Where } from '../../types' import type { Where } from '../../types'
import type { BeforeOperationHook, Collection } from '../config/types' import type { BeforeOperationHook, Collection } from '../config/types'

View File

@@ -1,5 +1,5 @@
import type { GeneratedTypes } from '../../' import type { GeneratedTypes } from '../../'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Document } from '../../types' import type { Document } from '../../types'
import type { BeforeOperationHook, Collection } from '../config/types' import type { BeforeOperationHook, Collection } from '../config/types'

View File

@@ -1,5 +1,5 @@
import type { CollectionPermission } from '../../auth' import type { CollectionPermission } from '../../auth'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { AllOperations } from '../../types' import type { AllOperations } from '../../types'
import { commitTransaction } from '../../utilities/commitTransaction' import { commitTransaction } from '../../utilities/commitTransaction'

View File

@@ -1,6 +1,6 @@
import type { AccessResult } from '../../config/types' import type { AccessResult } from '../../config/types'
import type { PaginatedDocs } from '../../database/types' import type { PaginatedDocs } from '../../database/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Where } from '../../types' import type { Where } from '../../types'
import type { Collection, TypeWithID } from '../config/types' import type { Collection, TypeWithID } from '../config/types'

View File

@@ -2,7 +2,7 @@
import memoize from 'micro-memoize' import memoize from 'micro-memoize'
import type { FindOneArgs } from '../../database/types' import type { FindOneArgs } from '../../database/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Collection, TypeWithID } from '../config/types' import type { Collection, TypeWithID } from '../config/types'
import executeAccess from '../../auth/executeAccess' import executeAccess from '../../auth/executeAccess'

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-underscore-dangle */ /* eslint-disable no-underscore-dangle */
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { TypeWithVersion } from '../../versions/types' import type { TypeWithVersion } from '../../versions/types'
import type { Collection, TypeWithID } from '../config/types' import type { Collection, TypeWithID } from '../config/types'

View File

@@ -1,5 +1,5 @@
import type { PaginatedDocs } from '../../database/types' import type { PaginatedDocs } from '../../database/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Where } from '../../types' import type { Where } from '../../types'
import type { TypeWithVersion } from '../../versions/types' import type { TypeWithVersion } from '../../versions/types'
import type { Collection } from '../config/types' import type { Collection } from '../config/types'

View File

@@ -1,16 +1,16 @@
import type { UploadedFile } from 'express-fileupload' import type { UploadedFile } from 'express-fileupload'
import type { MarkOptional } from 'ts-essentials' import type { MarkOptional } from 'ts-essentials'
import type { PayloadT } from '../../..'
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types' import type { PayloadRequest, RequestContext } from '../../../types'
import type { Payload } from '../../../payload'
import type { Document } from '../../../types' import type { Document } from '../../../types'
import type { File } from '../../../uploads/types' import type { File } from '../../../uploads/types'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import getFileByPath from '../../../uploads/getFileByPath' import getFileByPath from '../../../uploads/getFileByPath'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader' import { getDataLoader } from '../../dataloader'
import create from '../create' import create from '../create'
@@ -39,7 +39,7 @@ export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
} }
export default async function createLocal<TSlug extends keyof GeneratedTypes['collections']>( export default async function createLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<TSlug>, options: Options<TSlug>,
): Promise<GeneratedTypes['collections'][TSlug]> { ): Promise<GeneratedTypes['collections'][TSlug]> {
const { const {
@@ -78,7 +78,7 @@ export default async function createLocal<TSlug extends keyof GeneratedTypes['co
req.payload = payload req.payload = payload
req.i18n = i18nInit(payload.config.i18n) req.i18n = i18nInit(payload.config.i18n)
req.files = { req.files = {
file: (file ?? (await getFileByPath(filePath))) as UploadedFile, file: (file ?? (await getFileByPath(filePath))) as UploadedFile, // TODO(NATIVE_REQUEST): fix this type
} }
if (typeof user !== 'undefined') req.user = user if (typeof user !== 'undefined') req.user = user

View File

@@ -1,12 +1,12 @@
import type { PayloadT } from '../../..'
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types' import type { PayloadRequest, RequestContext } from '../../../types'
import type { Payload } from '../../../payload'
import type { Document, Where } from '../../../types' import type { Document, Where } from '../../../types'
import type { BulkOperationResult } from '../../config/types' import type { BulkOperationResult } from '../../config/types'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader' import { getDataLoader } from '../../dataloader'
import deleteOperation from '../delete' import deleteOperation from '../delete'
import deleteByID from '../deleteByID' import deleteByID from '../deleteByID'
@@ -41,19 +41,19 @@ export type Options<TSlug extends keyof GeneratedTypes['collections']> =
| ManyOptions<TSlug> | ManyOptions<TSlug>
async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>( async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: ByIDOptions<TSlug>, options: ByIDOptions<TSlug>,
): Promise<GeneratedTypes['collections'][TSlug]> ): Promise<GeneratedTypes['collections'][TSlug]>
async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>( async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: ManyOptions<TSlug>, options: ManyOptions<TSlug>,
): Promise<BulkOperationResult<TSlug>> ): Promise<BulkOperationResult<TSlug>>
async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>( async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<TSlug>, options: Options<TSlug>,
): Promise<BulkOperationResult<TSlug> | GeneratedTypes['collections'][TSlug]> ): Promise<BulkOperationResult<TSlug> | GeneratedTypes['collections'][TSlug]>
async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>( async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<TSlug>, options: Options<TSlug>,
): Promise<BulkOperationResult<TSlug> | GeneratedTypes['collections'][TSlug]> { ): Promise<BulkOperationResult<TSlug> | GeneratedTypes['collections'][TSlug]> {
const { const {

View File

@@ -1,12 +1,11 @@
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes, PayloadT } from '../../../'
import type { PaginatedDocs } from '../../../database/types' import type { PaginatedDocs } from '../../../database/types'
import type { PayloadRequest, RequestContext } from '../../../express/types' import type { PayloadRequest, RequestContext } from '../../../types'
import type { Payload } from '../../../payload'
import type { Document, Where } from '../../../types' import type { Document, Where } from '../../../types'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader' import { getDataLoader } from '../../dataloader'
import find from '../find' import find from '../find'
@@ -34,7 +33,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
} }
export default async function findLocal<T extends keyof GeneratedTypes['collections']>( export default async function findLocal<T extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<T>, options: Options<T>,
): Promise<PaginatedDocs<GeneratedTypes['collections'][T]>> { ): Promise<PaginatedDocs<GeneratedTypes['collections'][T]>> {
const { const {

View File

@@ -1,11 +1,11 @@
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types' import type { PayloadT } from '../../../'
import type { Payload } from '../../../payload' import type { PayloadRequest, RequestContext } from '../../../types'
import type { Document } from '../../../types' import type { Document } from '../../../types'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader' import { getDataLoader } from '../../dataloader'
import findByID from '../findByID' import findByID from '../findByID'
@@ -29,7 +29,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
} }
export default async function findByIDLocal<T extends keyof GeneratedTypes['collections']>( export default async function findByIDLocal<T extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<T>, options: Options<T>,
): Promise<GeneratedTypes['collections'][T]> { ): Promise<GeneratedTypes['collections'][T]> {
const { const {

View File

@@ -1,12 +1,11 @@
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes, PayloadT } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types' import type { PayloadRequest, RequestContext } from '../../../types'
import type { Payload } from '../../../payload'
import type { Document } from '../../../types' import type { Document } from '../../../types'
import type { TypeWithVersion } from '../../../versions/types' import type { TypeWithVersion } from '../../../versions/types'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader' import { getDataLoader } from '../../dataloader'
import findVersionByID from '../findVersionByID' import findVersionByID from '../findVersionByID'
@@ -29,7 +28,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
} }
export default async function findVersionByIDLocal<T extends keyof GeneratedTypes['collections']>( export default async function findVersionByIDLocal<T extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<T>, options: Options<T>,
): Promise<TypeWithVersion<GeneratedTypes['collections'][T]>> { ): Promise<TypeWithVersion<GeneratedTypes['collections'][T]>> {
const { const {

View File

@@ -1,13 +1,12 @@
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes, PayloadT } from '../../../'
import type { PaginatedDocs } from '../../../database/types' import type { PaginatedDocs } from '../../../database/types'
import type { PayloadRequest, RequestContext } from '../../../express/types' import type { PayloadRequest, RequestContext } from '../../../types'
import type { Payload } from '../../../payload'
import type { Document, Where } from '../../../types' import type { Document, Where } from '../../../types'
import type { TypeWithVersion } from '../../../versions/types' import type { TypeWithVersion } from '../../../versions/types'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader' import { getDataLoader } from '../../dataloader'
import findVersions from '../findVersions' import findVersions from '../findVersions'
@@ -32,7 +31,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
} }
export default async function findVersionsLocal<T extends keyof GeneratedTypes['collections']>( export default async function findVersionsLocal<T extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<T>, options: Options<T>,
): Promise<PaginatedDocs<TypeWithVersion<GeneratedTypes['collections'][T]>>> { ): Promise<PaginatedDocs<TypeWithVersion<GeneratedTypes['collections'][T]>>> {
const { const {

View File

@@ -1,11 +1,10 @@
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes, PayloadT } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types' import type { PayloadRequest, RequestContext } from '../../../types'
import type { Payload } from '../../../payload'
import type { Document } from '../../../types' import type { Document } from '../../../types'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader' import { getDataLoader } from '../../dataloader'
import restoreVersion from '../restoreVersion' import restoreVersion from '../restoreVersion'
@@ -27,7 +26,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
} }
export default async function restoreVersionLocal<T extends keyof GeneratedTypes['collections']>( export default async function restoreVersionLocal<T extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<T>, options: Options<T>,
): Promise<GeneratedTypes['collections'][T]> { ): Promise<GeneratedTypes['collections'][T]> {
const { const {

View File

@@ -1,16 +1,15 @@
import type { DeepPartial } from 'ts-essentials' import type { DeepPartial } from 'ts-essentials'
import type { GeneratedTypes } from '../../../' import type { GeneratedTypes, PayloadT } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types' import type { PayloadRequest, RequestContext } from '../../../types'
import type { Payload } from '../../../payload'
import type { Document, Where } from '../../../types' import type { Document, Where } from '../../../types'
import type { File } from '../../../uploads/types' import type { File } from '../../../uploads/types'
import type { BulkOperationResult } from '../../config/types' import type { BulkOperationResult } from '../../config/types'
import { APIError } from '../../../errors' import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init' import { i18nInit } from '../../../translations/init'
import getFileByPath from '../../../uploads/getFileByPath' import getFileByPath from '../../../uploads/getFileByPath'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader' import { getDataLoader } from '../../dataloader'
import update from '../update' import update from '../update'
import updateByID from '../updateByID' import updateByID from '../updateByID'
@@ -51,19 +50,19 @@ export type Options<TSlug extends keyof GeneratedTypes['collections']> =
| ManyOptions<TSlug> | ManyOptions<TSlug>
async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>( async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: ByIDOptions<TSlug>, options: ByIDOptions<TSlug>,
): Promise<GeneratedTypes['collections'][TSlug]> ): Promise<GeneratedTypes['collections'][TSlug]>
async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>( async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: ManyOptions<TSlug>, options: ManyOptions<TSlug>,
): Promise<BulkOperationResult<TSlug>> ): Promise<BulkOperationResult<TSlug>>
async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>( async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<TSlug>, options: Options<TSlug>,
): Promise<BulkOperationResult<TSlug> | GeneratedTypes['collections'][TSlug]> ): Promise<BulkOperationResult<TSlug> | GeneratedTypes['collections'][TSlug]>
async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>( async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload, payload: PayloadT,
options: Options<TSlug>, options: Options<TSlug>,
): Promise<BulkOperationResult<TSlug> | GeneratedTypes['collections'][TSlug]> { ): Promise<BulkOperationResult<TSlug> | GeneratedTypes['collections'][TSlug]> {
const { const {
@@ -109,7 +108,7 @@ async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>(
payloadAPI: 'local', payloadAPI: 'local',
transactionID: incomingReq?.transactionID, transactionID: incomingReq?.transactionID,
user, user,
} as PayloadRequest } as unknown as PayloadRequest
setRequestContext(req, context) setRequestContext(req, context)
if (!req.t) req.t = req.i18n.t if (!req.t) req.t = req.i18n.t

View File

@@ -2,7 +2,7 @@
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { FindOneArgs } from '../../database/types' import type { FindOneArgs } from '../../database/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Collection, TypeWithID } from '../config/types' import type { Collection, TypeWithID } from '../config/types'
import executeAccess from '../../auth/executeAccess' import executeAccess from '../../auth/executeAccess'

View File

@@ -4,7 +4,7 @@ import httpStatus from 'http-status'
import type { GeneratedTypes } from '../../' import type { GeneratedTypes } from '../../'
import type { AccessResult } from '../../config/types' import type { AccessResult } from '../../config/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Where } from '../../types' import type { Where } from '../../types'
import type { BulkOperationResult, Collection } from '../config/types' import type { BulkOperationResult, Collection } from '../config/types'
import type { CreateUpdateType } from './create' import type { CreateUpdateType } from './create'

View File

@@ -3,8 +3,8 @@ import type { DeepPartial } from 'ts-essentials'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { FindOneArgs } from '../../database/types' import type { FindOneArgs } from '../../database/types'
import type { PayloadRequest } from '../../express/types'
import type { GeneratedTypes } from '../../index' import type { GeneratedTypes } from '../../index'
import type { PayloadRequest } from '../../types'
import type { Collection } from '../config/types' import type { Collection } from '../config/types'
import executeAccess from '../../auth/executeAccess' import executeAccess from '../../auth/executeAccess'

View File

@@ -1,12 +1,14 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { URL } from 'url'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Document } from '../../types' import type { Document } from '../../types'
import formatSuccessResponse from '../../express/responses/formatSuccess' import formatSuccessResponse from '../../express/responses/formatSuccess'
import { getTranslation } from '../../utilities/getTranslation' import { getTranslation } from '../../utilities/getTranslation'
import { isNumber } from '../../utilities/isNumber'
import create from '../operations/create' import create from '../operations/create'
export type CreateResult = { export type CreateResult = {
@@ -20,14 +22,17 @@ export default async function createHandler(
next: NextFunction, next: NextFunction,
): Promise<Response<CreateResult> | void> { ): Promise<Response<CreateResult> | void> {
try { try {
const autosave = req.query.autosave === 'true' const { searchParams } = new URL(req.url)
const draft = req.query.draft === 'true' const autosave = searchParams.get('autosave') === 'true'
const draft = searchParams.get('draft') === 'true'
const depth = searchParams.get('depth')
const doc = await create({ const doc = await create({
autosave, autosave,
collection: req.collection, collection: req.collection,
// TODO(JARROD): remove reliance on express body parsing
data: req.body, data: req.body,
depth: Number(req.query.depth), depth: isNumber(depth) ? depth : undefined,
draft, draft,
req, req,
}) })

View File

@@ -1,12 +1,14 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { URL } from 'url'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Document, Where } from '../../types' import type { Document, Where } from '../../types'
import formatSuccessResponse from '../../express/responses/formatSuccess' import formatSuccessResponse from '../../express/responses/formatSuccess'
import { getTranslation } from '../../utilities/getTranslation' import { getTranslation } from '../../utilities/getTranslation'
import { isNumber } from '../../utilities/isNumber'
import deleteOperation from '../operations/delete' import deleteOperation from '../operations/delete'
export type DeleteResult = { export type DeleteResult = {
@@ -20,11 +22,15 @@ export default async function deleteHandler(
next: NextFunction, next: NextFunction,
): Promise<Response<DeleteResult> | void> { ): Promise<Response<DeleteResult> | void> {
try { try {
const { searchParams } = new URL(req.url)
const depth = searchParams.get('depth')
const where = searchParams.get('where')
const result = await deleteOperation({ const result = await deleteOperation({
collection: req.collection, collection: req.collection,
depth: parseInt(String(req.query.depth), 10), depth: isNumber(depth) ? depth : undefined,
req, req,
where: req.query.where as Where, where: where ? (JSON.parse(where) as Where) : {},
}) })
if (result.errors.length === 0) { if (result.errors.length === 0) {

View File

@@ -1,11 +1,13 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { URL } from 'url'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Document } from '../../types' import type { Document } from '../../types'
import { NotFound } from '../../errors' import { NotFound } from '../../errors'
import { isNumber } from '../../utilities/isNumber'
import deleteByID from '../operations/deleteByID' import deleteByID from '../operations/deleteByID'
export type DeleteResult = { export type DeleteResult = {
@@ -19,10 +21,12 @@ export default async function deleteByIDHandler(
next: NextFunction, next: NextFunction,
): Promise<Response<DeleteResult> | void> { ): Promise<Response<DeleteResult> | void> {
try { try {
const { searchParams } = new URL(req.url)
const depth = searchParams.get('depth')
const doc = await deleteByID({ const doc = await deleteByID({
id: req.params.id, id: req.params.id,
collection: req.collection, collection: req.collection,
depth: parseInt(String(req.query.depth), 10), depth: isNumber(depth) ? depth : undefined,
req, req,
}) })

View File

@@ -3,7 +3,7 @@ import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import type { CollectionPermission, GlobalPermission } from '../../auth' import type { CollectionPermission, GlobalPermission } from '../../auth'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import { docAccess } from '../operations/docAccess' import { docAccess } from '../operations/docAccess'

View File

@@ -1,10 +1,10 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { URL } from 'url'
import type { PaginatedDocs } from '../../database/types' import type { PaginatedDocs } from '../../database/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Where } from '../../types'
import type { TypeWithID } from '../config/types' import type { TypeWithID } from '../config/types'
import { isNumber } from '../../utilities/isNumber' import { isNumber } from '../../utilities/isNumber'
@@ -17,25 +17,21 @@ export default async function findHandler<T extends TypeWithID = any>(
next: NextFunction, next: NextFunction,
): Promise<Response<PaginatedDocs<T>> | void> { ): Promise<Response<PaginatedDocs<T>> | void> {
try { try {
let page: number | undefined const { searchParams } = new URL(req.url)
const depth = searchParams.get('depth')
if (typeof req.query.page === 'string') { const limit = searchParams.get('limit')
const parsedPage = parseInt(req.query.page, 10) const page = searchParams.get('page')
const where = searchParams.get('where')
if (!Number.isNaN(parsedPage)) {
page = parsedPage
}
}
const result = await find({ const result = await find({
collection: req.collection, collection: req.collection,
depth: isNumber(req.query.depth) ? Number(req.query.depth) : undefined, depth: isNumber(depth) ? Number(depth) : undefined,
draft: req.query.draft === 'true', draft: searchParams.get('draft') === 'true',
limit: isNumber(req.query.limit) ? Number(req.query.limit) : undefined, limit: isNumber(limit) ? Number(limit) : undefined,
page, page: isNumber(page) ? Number(page) : undefined,
req, req,
sort: req.query.sort as string, sort: searchParams.get('sort'),
where: req.query.where as Where, // This is a little shady where: where ? JSON.parse(where) : undefined,
}) })
return res.status(httpStatus.OK).json(result) return res.status(httpStatus.OK).json(result)

View File

@@ -1,8 +1,11 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import type { PayloadRequest } from '../../express/types' import { URL } from 'url'
import type { PayloadRequest } from '../../types'
import type { Document } from '../../types' import type { Document } from '../../types'
import { isNumber } from '../../utilities/isNumber'
import findByID from '../operations/findByID' import findByID from '../operations/findByID'
export type FindByIDResult = { export type FindByIDResult = {
@@ -16,11 +19,14 @@ export default async function findByIDHandler(
next: NextFunction, next: NextFunction,
): Promise<Response<FindByIDResult> | void> { ): Promise<Response<FindByIDResult> | void> {
try { try {
const { searchParams } = new URL(req.url)
const depth = searchParams.get('depth')
const doc = await findByID({ const doc = await findByID({
id: req.params.id, id: req.params.id,
collection: req.collection, collection: req.collection,
depth: Number(req.query.depth), depth: isNumber(depth) ? Number(depth) : undefined,
draft: req.query.draft === 'true', draft: searchParams.get('draft') === 'true',
req, req,
}) })
return res.json(doc) return res.json(doc)

View File

@@ -1,8 +1,11 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import type { PayloadRequest } from '../../express/types' import { URL } from 'url'
import type { PayloadRequest } from '../../types'
import type { Document } from '../../types' import type { Document } from '../../types'
import { isNumber } from '../../utilities/isNumber'
import findVersionByID from '../operations/findVersionByID' import findVersionByID from '../operations/findVersionByID'
export type FindByIDResult = { export type FindByIDResult = {
@@ -15,10 +18,13 @@ export default async function findVersionByIDHandler(
res: Response, res: Response,
next: NextFunction, next: NextFunction,
): Promise<Response<FindByIDResult> | void> { ): Promise<Response<FindByIDResult> | void> {
const { searchParams } = new URL(req.url)
const depth = searchParams.get('depth')
const options = { const options = {
id: req.params.id, id: req.params.id,
collection: req.collection, collection: req.collection,
depth: parseInt(String(req.query.depth), 10), depth: isNumber(depth) ? Number(depth) : undefined,
payload: req.payload, payload: req.payload,
req, req,
} }

View File

@@ -1,9 +1,10 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { URL } from 'url'
import type { PaginatedDocs } from '../../database/types' import type { PaginatedDocs } from '../../database/types'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Where } from '../../types' import type { Where } from '../../types'
import type { TypeWithID } from '../config/types' import type { TypeWithID } from '../config/types'
@@ -16,25 +17,22 @@ export default async function findVersionsHandler<T extends TypeWithID = any>(
next: NextFunction, next: NextFunction,
): Promise<Response<PaginatedDocs<T>> | void> { ): Promise<Response<PaginatedDocs<T>> | void> {
try { try {
let page: number | undefined const { searchParams } = new URL(req.url)
const page = searchParams.get('page')
if (typeof req.query.page === 'string') { const depth = searchParams.get('depth')
const parsedPage = parseInt(req.query.page, 10) const limit = searchParams.get('limit')
const where = searchParams.get('where')
if (!Number.isNaN(parsedPage)) { const sort = searchParams.get('sort')
page = parsedPage
}
}
const options = { const options = {
collection: req.collection, collection: req.collection,
depth: isNumber(req.query.depth) ? Number(req.query.depth) : undefined, depth: isNumber(depth) ? Number(depth) : undefined,
limit: isNumber(req.query.limit) ? Number(req.query.limit) : undefined, limit: isNumber(limit) ? Number(limit) : undefined,
page, page: isNumber(page) ? Number(page) : undefined,
payload: req.payload, payload: req.payload,
req, req,
sort: req.query.sort as string, sort: sort,
where: req.query.where as Where, // This is a little shady, where: where ? (JSON.parse(where) as Where) : undefined,
} }
const result = await findVersions(options) const result = await findVersions(options)

View File

@@ -1,11 +1,13 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { URL } from 'url'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Document } from '../../types' import type { Document } from '../../types'
import formatSuccessResponse from '../../express/responses/formatSuccess' import formatSuccessResponse from '../../express/responses/formatSuccess'
import { isNumber } from '../../utilities/isNumber'
import restoreVersion from '../operations/restoreVersion' import restoreVersion from '../operations/restoreVersion'
export type RestoreResult = { export type RestoreResult = {
@@ -18,10 +20,13 @@ export default async function restoreVersionHandler(
res: Response, res: Response,
next: NextFunction, next: NextFunction,
): Promise<Response<RestoreResult> | void> { ): Promise<Response<RestoreResult> | void> {
const { searchParams } = new URL(req.url)
const depth = searchParams.get('depth')
const options = { const options = {
id: req.params.id, id: req.params.id,
collection: req.collection, collection: req.collection,
depth: Number(req.query.depth), depth: isNumber(depth) ? Number(depth) : undefined,
payload: req.payload, payload: req.payload,
req, req,
} }

View File

@@ -1,12 +1,14 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { URL } from 'url'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { Document, Where } from '../../types' import type { Document, Where } from '../../types'
import formatSuccessResponse from '../../express/responses/formatSuccess' import formatSuccessResponse from '../../express/responses/formatSuccess'
import { getTranslation } from '../../utilities/getTranslation' import { getTranslation } from '../../utilities/getTranslation'
import { isNumber } from '../../utilities/isNumber'
import update from '../operations/update' import update from '../operations/update'
export type UpdateResult = { export type UpdateResult = {
@@ -20,15 +22,17 @@ export default async function updateHandler(
next: NextFunction, next: NextFunction,
): Promise<Response<UpdateResult> | void> { ): Promise<Response<UpdateResult> | void> {
try { try {
const draft = req.query.draft === 'true' const { searchParams } = new URL(req.url)
const depth = searchParams.get('depth')
const where = searchParams.get('where')
const result = await update({ const result = await update({
collection: req.collection, collection: req.collection,
data: req.body, data: req.body,
depth: parseInt(String(req.query.depth), 10), depth: isNumber(depth) ? Number(depth) : undefined,
draft, draft: searchParams.get('draft') === 'true',
req, req,
where: req.query.where as Where, where: where ? (JSON.parse(where) as Where) : undefined,
}) })
if (result.errors.length === 0) { if (result.errors.length === 0) {

View File

@@ -1,10 +1,12 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { URL } from 'url'
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import formatSuccessResponse from '../../express/responses/formatSuccess' import formatSuccessResponse from '../../express/responses/formatSuccess'
import { isNumber } from '../../utilities/isNumber'
import updateByID from '../operations/updateByID' import updateByID from '../operations/updateByID'
export type UpdateResult = { export type UpdateResult = {
@@ -30,15 +32,17 @@ export default async function updateByIDHandler(
next: NextFunction, next: NextFunction,
): Promise<Response<UpdateResult> | void> { ): Promise<Response<UpdateResult> | void> {
try { try {
const draft = req.query.draft === 'true' const { searchParams } = new URL(req.url)
const autosave = req.query.autosave === 'true' const depth = searchParams.get('depth')
const autosave = searchParams.get('autosave') === 'true'
const draft = searchParams.get('draft') === 'true'
const doc = await updateByID({ const doc = await updateByID({
id: req.params.id, id: req.params.id,
autosave, autosave,
collection: req.collection, collection: req.collection,
data: req.body, data: req.body,
depth: parseInt(String(req.query.depth), 10), depth: isNumber(depth) ? Number(depth) : undefined,
draft, draft,
req, req,
}) })

View File

@@ -11,6 +11,7 @@ import type { DeepRequired } from 'ts-essentials'
import type { InlineConfig } from 'vite' import type { InlineConfig } from 'vite'
import type { Configuration } from 'webpack' import type { Configuration } from 'webpack'
import type { PayloadT } from '..'
import type { import type {
DocumentTab, DocumentTab,
DocumentTabComponent, DocumentTabComponent,
@@ -26,10 +27,9 @@ import type {
SanitizedCollectionConfig, SanitizedCollectionConfig,
} from '../collections/config/types' } from '../collections/config/types'
import type { BaseDatabaseAdapter } from '../database/types' import type { BaseDatabaseAdapter } from '../database/types'
import type { PayloadRequest } from '../express/types'
import type { ClientConfigField, Field } from '../fields/config/types' import type { ClientConfigField, Field } from '../fields/config/types'
import type { GlobalConfig, SanitizedGlobalConfig } from '../globals/config/types' import type { GlobalConfig, SanitizedGlobalConfig } from '../globals/config/types'
import type { Payload } from '../payload' import type { PayloadRequest } from '../types'
import type { Where } from '../types' import type { Where } from '../types'
type Prettify<T> = { type Prettify<T> = {
@@ -114,7 +114,7 @@ export function hasTransportOptions(
export type GraphQLExtension = ( export type GraphQLExtension = (
graphQL: typeof GraphQL, graphQL: typeof GraphQL,
payload: Payload, payload: PayloadT,
) => Record<string, unknown> ) => Record<string, unknown>
export type InitOptions = { export type InitOptions = {
@@ -163,7 +163,7 @@ export type InitOptions = {
/** /**
* A function that is called immediately following startup that receives the Payload instance as it's only argument. * A function that is called immediately following startup that receives the Payload instance as it's only argument.
*/ */
onInit?: (payload: Payload) => Promise<void> | void onInit?: (payload: PayloadT) => Promise<void> | void
} }
/** /**
@@ -517,7 +517,7 @@ export type Config = {
custom?: Record<string, any> custom?: Record<string, any>
/** Pass in a database adapter for use on this project. */ /** Pass in a database adapter for use on this project. */
db: (args: { payload: Payload }) => BaseDatabaseAdapter db: (args: { payload: PayloadT }) => BaseDatabaseAdapter
/** Enable to expose more detailed error information. */ /** Enable to expose more detailed error information. */
debug?: boolean debug?: boolean
/** /**
@@ -634,7 +634,7 @@ export type Config = {
*/ */
maxDepth?: number maxDepth?: number
/** A function that is called immediately following startup that receives the Payload instance as its only argument. */ /** A function that is called immediately following startup that receives the Payload instance as its only argument. */
onInit?: (payload: Payload) => Promise<void> | void onInit?: (payload: PayloadT) => Promise<void> | void
/** /**
* An array of Payload plugins. * An array of Payload plugins.
* *

View File

@@ -1,5 +1,5 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */ /* eslint-disable no-restricted-syntax, no-await-in-loop */
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { BaseDatabaseAdapter } from '../types' import type { BaseDatabaseAdapter } from '../types'
import { getMigrations } from './getMigrations' import { getMigrations } from './getMigrations'

View File

@@ -1,5 +1,5 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */ /* eslint-disable no-restricted-syntax, no-await-in-loop */
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { BaseDatabaseAdapter } from '../types' import type { BaseDatabaseAdapter } from '../types'
import { getMigrations } from './getMigrations' import { getMigrations } from './getMigrations'

View File

@@ -1,5 +1,5 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */ /* eslint-disable no-restricted-syntax, no-await-in-loop */
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { BaseDatabaseAdapter } from '../types' import type { BaseDatabaseAdapter } from '../types'
import { getMigrations } from './getMigrations' import { getMigrations } from './getMigrations'

View File

@@ -1,5 +1,5 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */ /* eslint-disable no-restricted-syntax, no-await-in-loop */
import type { PayloadRequest } from '../../express/types' import type { PayloadRequest } from '../../types'
import type { BaseDatabaseAdapter } from '../types' import type { BaseDatabaseAdapter } from '../types'
import { getMigrations } from './getMigrations' import { getMigrations } from './getMigrations'

View File

@@ -1,7 +1,7 @@
import type { SanitizedCollectionConfig } from '../../collections/config/types' import type { SanitizedCollectionConfig } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types'
import type { Field } from '../../fields/config/types' import type { Field } from '../../fields/config/types'
import type { SanitizedGlobalConfig } from '../../globals/config/types' import type { SanitizedGlobalConfig } from '../../globals/config/types'
import type { PayloadRequest } from '../../types'
import type { EntityPolicies, PathToQuery } from './types' import type { EntityPolicies, PathToQuery } from './types'
import { fieldAffectsData } from '../../fields/config/types' import { fieldAffectsData } from '../../fields/config/types'

View File

@@ -1,4 +1,7 @@
export { getAuthenticatedUser } from '../auth/getAuthenticatedUser'
export type { export type {
AuthStrategyFunctionArgs,
CollectionPermission, CollectionPermission,
FieldPermissions, FieldPermissions,
GlobalPermission, GlobalPermission,

View File

@@ -1,2 +1,3 @@
export { default as init } from '../auth/operations/init' export { default as init } from '../auth/operations/init'
export { default as login } from '../auth/operations/login'
export { default as me } from '../auth/operations/me' export { default as me } from '../auth/operations/me'

View File

@@ -6,6 +6,8 @@ import type { CSSProperties } from 'react'
import monacoeditor from 'monaco-editor' // IMPORTANT - DO NOT REMOVE: This is required for pnpm's default isolated mode to work - even though the import is not used. This is due to a typescript bug: https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189. (tsbugisolatedmode) import monacoeditor from 'monaco-editor' // IMPORTANT - DO NOT REMOVE: This is required for pnpm's default isolated mode to work - even though the import is not used. This is due to a typescript bug: https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189. (tsbugisolatedmode)
import type React from 'react' import type React from 'react'
import type { PayloadT } from '../../'
// TODO(JAKE): fix admin component imports since fields moved
import type { ConditionalDateProps } from '../../admin/components/elements/DatePicker/types' import type { ConditionalDateProps } from '../../admin/components/elements/DatePicker/types'
import type { Props as ErrorProps } from '../../admin/components/forms/Error/types' import type { Props as ErrorProps } from '../../admin/components/forms/Error/types'
import type { Description } from '../../admin/components/forms/FieldDescription/types' import type { Description } from '../../admin/components/forms/FieldDescription/types'
@@ -15,9 +17,8 @@ import type { RichTextAdapter } from '../../admin/components/forms/field-types/R
import type { User } from '../../auth' import type { User } from '../../auth'
import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types' import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types'
import type { SanitizedConfig } from '../../config/types' import type { SanitizedConfig } from '../../config/types'
import type { PayloadRequest, RequestContext } from '../../express/types'
import type { SanitizedGlobalConfig } from '../../globals/config/types' import type { SanitizedGlobalConfig } from '../../globals/config/types'
import type { Payload } from '../../payload' import type { PayloadRequest, RequestContext } from '../../types'
import type { Operation, Where } from '../../types' import type { Operation, Where } from '../../types'
export type FieldHookArgs<T extends TypeWithID = any, P = any, S = any> = { export type FieldHookArgs<T extends TypeWithID = any, P = any, S = any> = {
@@ -125,7 +126,7 @@ export type ValidateOptions<TData, TSiblingData, TFieldConfig> = {
data: Partial<TData> data: Partial<TData>
id?: number | string id?: number | string
operation?: Operation operation?: Operation
payload?: Payload payload?: PayloadT
req?: PayloadRequest req?: PayloadRequest
siblingData: Partial<TSiblingData> siblingData: Partial<TSiblingData>
t: TFunction t: TFunction

View File

@@ -1,6 +1,6 @@
import type { SanitizedCollectionConfig } from '../../../collections/config/types' import type { SanitizedCollectionConfig } from '../../../collections/config/types'
import type { PayloadRequest, RequestContext } from '../../../express/types'
import type { SanitizedGlobalConfig } from '../../../globals/config/types' import type { SanitizedGlobalConfig } from '../../../globals/config/types'
import type { PayloadRequest, RequestContext } from '../../../types'
import { deepCopyObject } from '../../../utilities/deepCopyObject' import { deepCopyObject } from '../../../utilities/deepCopyObject'
import { traverseFields } from './traverseFields' import { traverseFields } from './traverseFields'

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
import type { SanitizedCollectionConfig } from '../../../collections/config/types' import type { SanitizedCollectionConfig } from '../../../collections/config/types'
import type { PayloadRequest, RequestContext } from '../../../express/types'
import type { SanitizedGlobalConfig } from '../../../globals/config/types' import type { SanitizedGlobalConfig } from '../../../globals/config/types'
import type { PayloadRequest, RequestContext } from '../../../types'
import type { Field, TabAsField } from '../../config/types' import type { Field, TabAsField } from '../../config/types'
import { fieldAffectsData, tabHasName } from '../../config/types' import { fieldAffectsData, tabHasName } from '../../config/types'

Some files were not shown because too many files have changed in this diff Show More