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" }],
"typescript.tsdk": "node_modules/typescript/lib",
// 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 { URL } from 'url'
type Args = {
request: Request
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 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,
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
}
// 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> }) =>
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({
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)

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
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'
export default async function refreshHandler(
@@ -13,11 +13,10 @@ export default async function refreshHandler(
try {
let token
const extractJWT = getExtractJWT(req.payload.config)
token = extractJWT(req)
if (req.body.token) {
token = req.body.token
if (req.body) {
token = req.body.data
}
const result = await refresh({

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,9 @@
// TODO(JARROD): remove reliance on express
import type { NextFunction, Response } from 'express'
import httpStatus from 'http-status'
import type { PayloadRequest } from '../../express/types'
import type { PayloadRequest } from '../../types'
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 { Permissions } from '../types'

View File

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

View File

@@ -1,12 +1,11 @@
import type { GeneratedTypes } from '../../..'
import type { PayloadRequest } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { GeneratedTypes, PayloadT } from '../../..'
import type { PayloadRequest } from '../../../types'
import type { Result } from '../forgotPassword'
import { getDataLoader } from '../../../collections/dataloader'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import forgotPassword from '../forgotPassword'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<T>,
): Promise<Result> {
const {

View File

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

View File

@@ -1,12 +1,12 @@
import type { PayloadT } from '../../..'
import type { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { PayloadRequest } from '../../../types'
import type { Result } from '../resetPassword'
import { getDataLoader } from '../../../collections/dataloader'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import resetPassword from '../resetPassword'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<T>,
): Promise<Result> {
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 { PayloadRequest } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { PayloadRequest } from '../../../types'
import { getDataLoader } from '../../../collections/dataloader'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import unlock from '../unlock'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<T>,
): Promise<boolean> {
const {

View File

@@ -1,10 +1,10 @@
import type { PayloadT } from '../../..'
import type { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { PayloadRequest } from '../../../types'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import verifyEmail from '../verifyEmail'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<T>,
): Promise<boolean> {
const { collection: collectionSlug, req = {} as PayloadRequest, token } = options

View File

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

View File

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

View File

@@ -1,11 +1,11 @@
import jwt from 'jsonwebtoken'
import url from 'url'
import { URL } from 'url'
import type { Collection } from '../../collections/config/types'
import type { PayloadRequest } from '../../express/types'
import type { PayloadRequest } from '../../types'
import type { User } from '../types'
import getExtractJWT from '../getExtractJWT'
import { extractJWT } from '../getExtractJWT'
export type Result = {
collection?: string
@@ -20,13 +20,12 @@ export type Arguments = {
}
async function me({ collection, req }: Arguments): Promise<Result> {
const extractJWT = getExtractJWT(req.payload.config)
let response: Result = {
user: null,
}
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 user = (await req.payload.findByID({

View File

@@ -1,10 +1,11 @@
// TODO(JARROD): remove express Response
import type { Response } from 'express'
import jwt from 'jsonwebtoken'
import url from 'url'
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 { buildAfterOperation } from '../../collections/operations/utils'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,7 @@ import type { BatchLoadFn } from 'dataloader'
import DataLoader from 'dataloader'
import type { PayloadRequest } from '../express/types'
import type { PayloadRequest } from '../types'
import type { TypeWithID } from './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 { GeneratedTypes } from '../../../'
import type { PayloadRequest } from '../../../express/types'
import type { PayloadRequest } from '../../../types'
import type { Collection } from '../../config/types'
import isolateTransactionID from '../../../utilities/isolateTransactionID'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
import type { AccessResult } from '../../config/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 { Collection, TypeWithID } from '../config/types'

View File

@@ -2,7 +2,7 @@
import memoize from 'micro-memoize'
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 executeAccess from '../../auth/executeAccess'

View File

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

View File

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

View File

@@ -1,16 +1,16 @@
import type { UploadedFile } from 'express-fileupload'
import type { MarkOptional } from 'ts-essentials'
import type { PayloadT } from '../../..'
import type { GeneratedTypes } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { PayloadRequest, RequestContext } from '../../../types'
import type { Document } from '../../../types'
import type { File } from '../../../uploads/types'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import getFileByPath from '../../../uploads/getFileByPath'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<TSlug>,
): Promise<GeneratedTypes['collections'][TSlug]> {
const {
@@ -78,7 +78,7 @@ export default async function createLocal<TSlug extends keyof GeneratedTypes['co
req.payload = payload
req.i18n = i18nInit(payload.config.i18n)
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

View File

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

View File

@@ -1,12 +1,11 @@
import type { GeneratedTypes } from '../../../'
import type { GeneratedTypes, PayloadT } from '../../../'
import type { PaginatedDocs } from '../../../database/types'
import type { PayloadRequest, RequestContext } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { PayloadRequest, RequestContext } from '../../../types'
import type { Document, Where } from '../../../types'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<T>,
): Promise<PaginatedDocs<GeneratedTypes['collections'][T]>> {
const {

View File

@@ -1,11 +1,11 @@
import type { GeneratedTypes } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { PayloadT } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../types'
import type { Document } from '../../../types'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<T>,
): Promise<GeneratedTypes['collections'][T]> {
const {

View File

@@ -1,12 +1,11 @@
import type { GeneratedTypes } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { GeneratedTypes, PayloadT } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../types'
import type { Document } from '../../../types'
import type { TypeWithVersion } from '../../../versions/types'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<T>,
): Promise<TypeWithVersion<GeneratedTypes['collections'][T]>> {
const {

View File

@@ -1,13 +1,12 @@
import type { GeneratedTypes } from '../../../'
import type { GeneratedTypes, PayloadT } from '../../../'
import type { PaginatedDocs } from '../../../database/types'
import type { PayloadRequest, RequestContext } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { PayloadRequest, RequestContext } from '../../../types'
import type { Document, Where } from '../../../types'
import type { TypeWithVersion } from '../../../versions/types'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<T>,
): Promise<PaginatedDocs<TypeWithVersion<GeneratedTypes['collections'][T]>>> {
const {

View File

@@ -1,11 +1,10 @@
import type { GeneratedTypes } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../express/types'
import type { Payload } from '../../../payload'
import type { GeneratedTypes, PayloadT } from '../../../'
import type { PayloadRequest, RequestContext } from '../../../types'
import type { Document } from '../../../types'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import { setRequestContext } from '../../../utilities/setRequestContext'
import { getDataLoader } from '../../dataloader'
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']>(
payload: Payload,
payload: PayloadT,
options: Options<T>,
): Promise<GeneratedTypes['collections'][T]> {
const {

View File

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

View File

@@ -2,7 +2,7 @@
import httpStatus from 'http-status'
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 executeAccess from '../../auth/executeAccess'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,6 +11,7 @@ import type { DeepRequired } from 'ts-essentials'
import type { InlineConfig } from 'vite'
import type { Configuration } from 'webpack'
import type { PayloadT } from '..'
import type {
DocumentTab,
DocumentTabComponent,
@@ -26,10 +27,9 @@ import type {
SanitizedCollectionConfig,
} from '../collections/config/types'
import type { BaseDatabaseAdapter } from '../database/types'
import type { PayloadRequest } from '../express/types'
import type { ClientConfigField, Field } from '../fields/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'
type Prettify<T> = {
@@ -114,7 +114,7 @@ export function hasTransportOptions(
export type GraphQLExtension = (
graphQL: typeof GraphQL,
payload: Payload,
payload: PayloadT,
) => Record<string, unknown>
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.
*/
onInit?: (payload: Payload) => Promise<void> | void
onInit?: (payload: PayloadT) => Promise<void> | void
}
/**
@@ -517,7 +517,7 @@ export type Config = {
custom?: Record<string, any>
/** 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. */
debug?: boolean
/**
@@ -634,7 +634,7 @@ export type Config = {
*/
maxDepth?: number
/** 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.
*

View File

@@ -1,5 +1,5 @@
/* 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 { getMigrations } from './getMigrations'

View File

@@ -1,5 +1,5 @@
/* 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 { getMigrations } from './getMigrations'

View File

@@ -1,5 +1,5 @@
/* 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 { getMigrations } from './getMigrations'

View File

@@ -1,5 +1,5 @@
/* 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 { getMigrations } from './getMigrations'

View File

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

View File

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

View File

@@ -1,2 +1,3 @@
export { default as init } from '../auth/operations/init'
export { default as login } from '../auth/operations/login'
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 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 { Props as ErrorProps } from '../../admin/components/forms/Error/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 { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types'
import type { SanitizedConfig } from '../../config/types'
import type { PayloadRequest, RequestContext } from '../../express/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'
export type FieldHookArgs<T extends TypeWithID = any, P = any, S = any> = {
@@ -125,7 +126,7 @@ export type ValidateOptions<TData, TSiblingData, TFieldConfig> = {
data: Partial<TData>
id?: number | string
operation?: Operation
payload?: Payload
payload?: PayloadT
req?: PayloadRequest
siblingData: Partial<TSiblingData>
t: TFunction

View File

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

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-param-reassign */
import type { SanitizedCollectionConfig } from '../../../collections/config/types'
import type { PayloadRequest, RequestContext } from '../../../express/types'
import type { SanitizedGlobalConfig } from '../../../globals/config/types'
import type { PayloadRequest, RequestContext } from '../../../types'
import type { Field, TabAsField } 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