feat(3.0): next route handlers (#4590)
This commit is contained in:
@@ -1,6 +1,4 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
/* 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 GET = me({ config })
|
export { GET, POST, DELETE, PATCH } from '@payloadcms/next/dist/routes/index'
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
|
||||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
|
||||||
import { init } from '@payloadcms/next/routes/init'
|
|
||||||
import config from 'payload-config'
|
|
||||||
|
|
||||||
export const GET = init({ config })
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/* 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 })
|
|
||||||
15
packages/next/.swcrc
Normal file
15
packages/next/.swcrc
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/swcrc",
|
||||||
|
"sourceMaps": "inline",
|
||||||
|
"jsc": {
|
||||||
|
"target": "esnext",
|
||||||
|
"parser": {
|
||||||
|
"syntax": "typescript",
|
||||||
|
"tsx": true,
|
||||||
|
"dts": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"module": {
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,18 +30,24 @@
|
|||||||
"import": "./src/routes/*.ts",
|
"import": "./src/routes/*.ts",
|
||||||
"require": "./src/routes/*.ts",
|
"require": "./src/routes/*.ts",
|
||||||
"types": "./src/routes/*.ts"
|
"types": "./src/routes/*.ts"
|
||||||
}
|
},
|
||||||
|
"./dist/routes/*": "./dist/routes/*.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@payloadcms/ui": "workspace:*",
|
|
||||||
"@payloadcms/eslint-config": "workspace:*",
|
"@payloadcms/eslint-config": "workspace:*",
|
||||||
|
"@payloadcms/ui": "workspace:*",
|
||||||
"payload": "workspace:*",
|
"payload": "workspace:*",
|
||||||
"sass": "^1.69.5"
|
"sass": "^1.69.5"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jsonwebtoken": "9.0.1",
|
||||||
|
"path-to-regexp": "^6.2.1"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"payload": "^2.0.0",
|
"http-status": "1.6.2",
|
||||||
|
"i18next": "22.5.1",
|
||||||
"next": "^14.0.0",
|
"next": "^14.0.0",
|
||||||
"i18next": "22.5.1"
|
"payload": "^2.0.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"exports": {
|
"exports": {
|
||||||
@@ -60,6 +66,11 @@
|
|||||||
"require": "./dist/pages/*.js",
|
"require": "./dist/pages/*.js",
|
||||||
"types": "./dist/pages/*.d.ts"
|
"types": "./dist/pages/*.d.ts"
|
||||||
},
|
},
|
||||||
|
"./app/*": {
|
||||||
|
"import": "./dist/app/*.js",
|
||||||
|
"require": "./dist/app/*.js",
|
||||||
|
"types": "./dist/app/*.d.ts"
|
||||||
|
},
|
||||||
"./routes/*": {
|
"./routes/*": {
|
||||||
"import": "./dist/routes/*.js",
|
"import": "./dist/routes/*.js",
|
||||||
"require": "./dist/routes/*.js",
|
"require": "./dist/routes/*.js",
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
/* 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 GET = me({ config })
|
export { GET, POST, DELETE, PATCH } from '@payloadcms/next/dist/routes/index'
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
|
||||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
|
||||||
import { init } from '@payloadcms/next/routes/init'
|
|
||||||
import config from 'payload-config'
|
|
||||||
|
|
||||||
export const GET = init({ config })
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/* 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 })
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { PayloadRequest, SanitizedConfig } from 'payload/types'
|
|
||||||
|
|
||||||
type Args = {
|
|
||||||
config: SanitizedConfig
|
|
||||||
req: PayloadRequest
|
|
||||||
}
|
|
||||||
export const authenticate = async ({ config, req }: Args): Promise<PayloadRequest> => {
|
|
||||||
return req
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export { init } from '../routes/init'
|
|
||||||
export { login } from '../routes/login'
|
|
||||||
14
packages/next/src/routes/auth/access.ts
Normal file
14
packages/next/src/routes/auth/access.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
import { accessOperation } from 'payload/operations'
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const access = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const results = await accessOperation({
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(results, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
25
packages/next/src/routes/auth/forgotPassword.ts
Normal file
25
packages/next/src/routes/auth/forgotPassword.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { forgotPasswordOperation } from 'payload/operations'
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const forgotPassword = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
await forgotPasswordOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
data: {
|
||||||
|
email: req.data.email as string,
|
||||||
|
},
|
||||||
|
disableEmail: Boolean(req.data?.disableEmail),
|
||||||
|
expiration: typeof req.data.expiration === 'number' ? req.data.expiration : undefined,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
11
packages/next/src/routes/auth/init.ts
Normal file
11
packages/next/src/routes/auth/init.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import type { PayloadRequest } from 'payload/types'
|
||||||
|
import { init as initOperation } from 'payload/operations'
|
||||||
|
|
||||||
|
export const init = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const initialized = await initOperation({
|
||||||
|
collection: req.collection.config.slug,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json({ initialized })
|
||||||
|
}
|
||||||
42
packages/next/src/routes/auth/login.ts
Normal file
42
packages/next/src/routes/auth/login.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
import { loginOperation } from 'payload/operations'
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
import { generatePayloadCookie } from '../../utilities/cookies'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const login = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
|
||||||
|
const result = await loginOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
data: {
|
||||||
|
email: typeof req.data?.email === 'string' ? req.data.email : '',
|
||||||
|
password: typeof req.data?.password === 'string' ? req.data.password : '',
|
||||||
|
},
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
const cookie = generatePayloadCookie({
|
||||||
|
token: result.token,
|
||||||
|
payload: req.payload,
|
||||||
|
collectionConfig: req.collection.config,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
exp: result.exp,
|
||||||
|
message: 'Auth Passed',
|
||||||
|
token: result.token,
|
||||||
|
user: result.user,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: new Headers({
|
||||||
|
'Set-Cookie': cookie,
|
||||||
|
}),
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
40
packages/next/src/routes/auth/logout.ts
Normal file
40
packages/next/src/routes/auth/logout.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
import { logoutOperation } from 'payload/operations'
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
import { generateExpiredPayloadCookie } from '../../utilities/cookies'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const logout = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const result = logoutOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Logout failed.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.BAD_REQUEST,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expiredCookie = generateExpiredPayloadCookie({
|
||||||
|
collectionConfig: req.collection.config,
|
||||||
|
payload: req.payload,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Logout successful.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: new Headers({
|
||||||
|
'Set-Cookie': expiredCookie,
|
||||||
|
}),
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
25
packages/next/src/routes/auth/me.ts
Normal file
25
packages/next/src/routes/auth/me.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
import type { PayloadRequest } from 'payload/types'
|
||||||
|
import { meOperation } from 'payload/operations'
|
||||||
|
import { extractJWT } from '../../utilities/jwt'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const me = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const currentToken = extractJWT(req)
|
||||||
|
|
||||||
|
const result = await meOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
req,
|
||||||
|
currentToken,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
...result,
|
||||||
|
message: 'Successfully retrieved me user.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
48
packages/next/src/routes/auth/refresh.ts
Normal file
48
packages/next/src/routes/auth/refresh.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { extractJWT } from '../../utilities/jwt'
|
||||||
|
import { refreshOperation } from 'payload/operations'
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
import httpStatus from 'http-status'
|
||||||
|
import { generatePayloadCookie } from '../../utilities/cookies'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const refresh = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const token = typeof req.data?.token === 'string' ? req.data.token : extractJWT(req)
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Token not provided.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.UNAUTHORIZED,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await refreshOperation({
|
||||||
|
token,
|
||||||
|
req,
|
||||||
|
collection: req.collection,
|
||||||
|
})
|
||||||
|
|
||||||
|
const cookie = generatePayloadCookie({
|
||||||
|
token: result.refreshedToken,
|
||||||
|
payload: req.payload,
|
||||||
|
collectionConfig: req.collection.config,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
exp: result.exp,
|
||||||
|
message: 'Token refresh successful',
|
||||||
|
token: result.refreshedToken,
|
||||||
|
user: result.user,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: new Headers({
|
||||||
|
'Set-Cookie': cookie,
|
||||||
|
}),
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
37
packages/next/src/routes/auth/registerFirstUser.ts
Normal file
37
packages/next/src/routes/auth/registerFirstUser.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
import { registerFirstUserOperation } from 'payload/operations'
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
import { generatePayloadCookie } from '../../utilities/cookies'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const registerFirstUser = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const result = await registerFirstUserOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
data: {
|
||||||
|
email: typeof req.data?.email === 'string' ? req.data.email : '',
|
||||||
|
password: typeof req.data?.password === 'string' ? req.data.password : '',
|
||||||
|
},
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
const cookie = generatePayloadCookie({
|
||||||
|
token: result.token,
|
||||||
|
payload: req.payload,
|
||||||
|
collectionConfig: req.collection.config,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
exp: result.exp,
|
||||||
|
message: 'Successfully registered first user.',
|
||||||
|
token: result.token,
|
||||||
|
user: result.user,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: new Headers({
|
||||||
|
'Set-Cookie': cookie,
|
||||||
|
}),
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
41
packages/next/src/routes/auth/resetPassword.ts
Normal file
41
packages/next/src/routes/auth/resetPassword.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import { resetPasswordOperation } from 'payload/operations'
|
||||||
|
import { generatePayloadCookie } from '../../utilities/cookies'
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const resetPassword = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
|
||||||
|
const result = await resetPasswordOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
data: {
|
||||||
|
password: typeof req.data?.password === 'string' ? req.data.password : '',
|
||||||
|
token: typeof req.data?.token === 'string' ? req.data.token : '',
|
||||||
|
},
|
||||||
|
depth: depth ? Number(depth) : undefined,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
const cookie = generatePayloadCookie({
|
||||||
|
token: result.token,
|
||||||
|
payload: req.payload,
|
||||||
|
collectionConfig: req.collection.config,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Password reset successfully.',
|
||||||
|
token: result.token,
|
||||||
|
user: result.user,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: new Headers({
|
||||||
|
'Set-Cookie': cookie,
|
||||||
|
}),
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
22
packages/next/src/routes/auth/unlock.ts
Normal file
22
packages/next/src/routes/auth/unlock.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import { unlockOperation } from 'payload/operations'
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const unlock = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
await unlockOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
data: { email: req.data.email as string },
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
27
packages/next/src/routes/auth/verifyEmail.ts
Normal file
27
packages/next/src/routes/auth/verifyEmail.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import { verifyEmailOperation } from 'payload/operations'
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
export const verifyEmail = async ({
|
||||||
|
req,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
await verifyEmailOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
req,
|
||||||
|
token: id,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Email verified successfully.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
33
packages/next/src/routes/collections/create.ts
Normal file
33
packages/next/src/routes/collections/create.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
import { createOperation } from 'payload/operations'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const create = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
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 createOperation({
|
||||||
|
autosave,
|
||||||
|
collection: req.collection,
|
||||||
|
data: req.data,
|
||||||
|
depth: isNumber(depth) ? depth : undefined,
|
||||||
|
draft,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ...formatSuccessResponse(
|
||||||
|
// req.t('general:successfullyCreated', {
|
||||||
|
// label: getTranslation(req.collection.config.labels.singular, req.i18n),
|
||||||
|
// }),
|
||||||
|
// 'message',
|
||||||
|
// )
|
||||||
|
return Response.json(doc, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
62
packages/next/src/routes/collections/delete.ts
Normal file
62
packages/next/src/routes/collections/delete.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest, Where } from 'payload/types'
|
||||||
|
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
import { deleteOperation } from 'payload/operations'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const deleteDoc = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
const where = searchParams.get('where')
|
||||||
|
|
||||||
|
const result = await deleteOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
depth: isNumber(depth) ? depth : undefined,
|
||||||
|
req,
|
||||||
|
where: where ? (JSON.parse(where) as Where) : {},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result.errors.length === 0) {
|
||||||
|
// const message = req.t('general:deletedCountSuccessfully', {
|
||||||
|
// count: result.docs.length,
|
||||||
|
// label: getTranslation(
|
||||||
|
// req.collection.config.labels[result.docs.length > 1 ? 'plural' : 'singular'],
|
||||||
|
// req.i18n,
|
||||||
|
// ),
|
||||||
|
// })
|
||||||
|
|
||||||
|
// res.status(httpStatus.OK).json({
|
||||||
|
// ...formatSuccessResponse(message, 'message'),
|
||||||
|
// ...result,
|
||||||
|
// })
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// const total = result.docs.length + result.errors.length
|
||||||
|
// const message = req.t('error:unableToDeleteCount', {
|
||||||
|
// count: result.errors.length,
|
||||||
|
// label: getTranslation(
|
||||||
|
// req.collection.config.labels[total > 1 ? 'plural' : 'singular'],
|
||||||
|
// req.i18n,
|
||||||
|
// ),
|
||||||
|
// total,
|
||||||
|
// })
|
||||||
|
|
||||||
|
// res.status(httpStatus.BAD_REQUEST).json({
|
||||||
|
// message,
|
||||||
|
// ...result,
|
||||||
|
// })
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
...result,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.BAD_REQUEST,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
45
packages/next/src/routes/collections/deleteByID.ts
Normal file
45
packages/next/src/routes/collections/deleteByID.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
import { deleteByIDOperation } from 'payload/operations'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const deleteByID = async ({
|
||||||
|
req,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
const doc = await deleteByIDOperation({
|
||||||
|
id,
|
||||||
|
collection: req.collection,
|
||||||
|
depth: isNumber(depth) ? depth : undefined,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Not Found',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.NOT_FOUND,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
...doc,
|
||||||
|
// ...formatSuccessResponse(req.t('general:successfullyDeleted'), 'message'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
23
packages/next/src/routes/collections/docAccess.ts
Normal file
23
packages/next/src/routes/collections/docAccess.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
import { docAccessOperation } from 'payload/operations'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const docAccess = async ({
|
||||||
|
req,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const result = await docAccessOperation({
|
||||||
|
id,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
31
packages/next/src/routes/collections/find.ts
Normal file
31
packages/next/src/routes/collections/find.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
import { findOperation } from 'payload/operations'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const find = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
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 findOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
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: searchParams.get('sort'),
|
||||||
|
where: where ? JSON.parse(where) : undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
29
packages/next/src/routes/collections/findByID.ts
Normal file
29
packages/next/src/routes/collections/findByID.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
import { findByIDOperation } from 'payload/operations'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const findByID = async ({
|
||||||
|
req,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
|
||||||
|
const result = await findByIDOperation({
|
||||||
|
id,
|
||||||
|
collection: req.collection,
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
draft: searchParams.get('draft') === 'true',
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
28
packages/next/src/routes/collections/findVersionByID.ts
Normal file
28
packages/next/src/routes/collections/findVersionByID.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
import { findVersionByIDOperation } from 'payload/operations'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const findVersionByID = async ({
|
||||||
|
req,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
|
||||||
|
const result = await findVersionByIDOperation({
|
||||||
|
id,
|
||||||
|
collection: req.collection,
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
35
packages/next/src/routes/collections/findVersions.ts
Normal file
35
packages/next/src/routes/collections/findVersions.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import { PayloadRequest, Where } from 'payload/types'
|
||||||
|
import { findVersionsOperation } from 'payload/operations'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const findVersions = async ({
|
||||||
|
req,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
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 result = await findVersionsOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
limit: isNumber(limit) ? Number(limit) : undefined,
|
||||||
|
page: isNumber(page) ? Number(page) : undefined,
|
||||||
|
req,
|
||||||
|
sort: sort,
|
||||||
|
where: where ? (JSON.parse(where) as Where) : undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
34
packages/next/src/routes/collections/restoreVersion.ts
Normal file
34
packages/next/src/routes/collections/restoreVersion.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import { PayloadRequest } from 'payload/types'
|
||||||
|
import { restoreVersionOperation } from 'payload/operations'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const restoreVersion = async ({
|
||||||
|
req,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
|
||||||
|
const result = await restoreVersionOperation({
|
||||||
|
id,
|
||||||
|
collection: req.collection,
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
...result,
|
||||||
|
// ...formatSuccessResponse(req.t('version:restoredSuccessfully'), 'message'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
63
packages/next/src/routes/collections/update.ts
Normal file
63
packages/next/src/routes/collections/update.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest, Where } from 'payload/types'
|
||||||
|
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
import { updateOperation } from 'payload/operations'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const update = async ({ req }: { req: PayloadRequest }): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
const where = searchParams.get('where')
|
||||||
|
|
||||||
|
const result = await updateOperation({
|
||||||
|
collection: req.collection,
|
||||||
|
data: req.data,
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
draft: searchParams.get('draft') === 'true',
|
||||||
|
req,
|
||||||
|
where: where ? (JSON.parse(where) as Where) : undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result.errors.length === 0) {
|
||||||
|
// const message = req.t('general:updatedCountSuccessfully', {
|
||||||
|
// count: result.docs.length,
|
||||||
|
// label: getTranslation(
|
||||||
|
// req.collection.config.labels[result.docs.length > 1 ? 'plural' : 'singular'],
|
||||||
|
// req.i18n,
|
||||||
|
// ),
|
||||||
|
// })
|
||||||
|
|
||||||
|
// res.status(httpStatus.OK).json({
|
||||||
|
// ...formatSuccessResponse(message, 'message'),
|
||||||
|
// ...result,
|
||||||
|
// })
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// const total = result.docs.length + result.errors.length
|
||||||
|
// const message = req.t('error:unableToUpdateCount', {
|
||||||
|
// count: result.errors.length,
|
||||||
|
// label: getTranslation(
|
||||||
|
// req.collection.config.labels[total > 1 ? 'plural' : 'singular'],
|
||||||
|
// req.i18n,
|
||||||
|
// ),
|
||||||
|
// total,
|
||||||
|
// })
|
||||||
|
|
||||||
|
// res.status(httpStatus.BAD_REQUEST).json({
|
||||||
|
// ...formatSuccessResponse(message, 'message'),
|
||||||
|
// ...result,
|
||||||
|
// })
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
...result,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.BAD_REQUEST,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
45
packages/next/src/routes/collections/updateByID.ts
Normal file
45
packages/next/src/routes/collections/updateByID.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
import { updateByIDOperation } from 'payload/operations'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const updateByID = async ({
|
||||||
|
req,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
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 updateByIDOperation({
|
||||||
|
id,
|
||||||
|
autosave,
|
||||||
|
collection: req.collection,
|
||||||
|
data: req.data,
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
draft,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
let message = req.t('general:updatedSuccessfully')
|
||||||
|
|
||||||
|
if (draft) message = req.t('version:draftSavedSuccessfully')
|
||||||
|
if (autosave) message = req.t('version:autosavedSuccessfully')
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
// ...formatSuccessResponse(message, 'message'),
|
||||||
|
doc,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: httpStatus.OK,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
23
packages/next/src/routes/globals/docAccess.ts
Normal file
23
packages/next/src/routes/globals/docAccess.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest, SanitizedGlobalConfig } from 'payload/types'
|
||||||
|
|
||||||
|
import { docAccessOperationGlobal } from 'payload/operations'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const docAccess = async ({
|
||||||
|
req,
|
||||||
|
globalConfig,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
globalConfig: SanitizedGlobalConfig
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const result = await docAccessOperationGlobal({
|
||||||
|
globalConfig,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
30
packages/next/src/routes/globals/findOne.ts
Normal file
30
packages/next/src/routes/globals/findOne.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest, SanitizedGlobalConfig } from 'payload/types'
|
||||||
|
|
||||||
|
import { findOneOperation } from 'payload/operations'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const findOne = async ({
|
||||||
|
req,
|
||||||
|
globalConfig,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
globalConfig: SanitizedGlobalConfig
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
|
||||||
|
const result = await findOneOperation({
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
draft: searchParams.get('draft') === 'true',
|
||||||
|
globalConfig,
|
||||||
|
req,
|
||||||
|
slug: globalConfig.slug,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
31
packages/next/src/routes/globals/findVersionByID.ts
Normal file
31
packages/next/src/routes/globals/findVersionByID.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest, SanitizedGlobalConfig } from 'payload/types'
|
||||||
|
|
||||||
|
import { findVersionByIDOperationGlobal } from 'payload/operations'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const findVersionByID = async ({
|
||||||
|
req,
|
||||||
|
globalConfig,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
globalConfig: SanitizedGlobalConfig
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
|
||||||
|
const result = await findVersionByIDOperationGlobal({
|
||||||
|
id,
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
globalConfig,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
35
packages/next/src/routes/globals/findVersions.ts
Normal file
35
packages/next/src/routes/globals/findVersions.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest, SanitizedGlobalConfig, Where } from 'payload/types'
|
||||||
|
|
||||||
|
import { findVersionsOperationGlobal } from 'payload/operations'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const findVersions = async ({
|
||||||
|
req,
|
||||||
|
globalConfig,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
globalConfig: SanitizedGlobalConfig
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const page = searchParams.get('page')
|
||||||
|
const limit = searchParams.get('limit')
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
const where = searchParams.get('where')
|
||||||
|
|
||||||
|
const result = await findVersionsOperationGlobal({
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
globalConfig,
|
||||||
|
limit: isNumber(limit) ? Number(limit) : undefined,
|
||||||
|
page: isNumber(page) ? Number(page) : undefined,
|
||||||
|
req,
|
||||||
|
sort: searchParams.get('sort'),
|
||||||
|
where: where ? (JSON.parse(where) as Where) : undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
32
packages/next/src/routes/globals/restoreVersion.ts
Normal file
32
packages/next/src/routes/globals/restoreVersion.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest, SanitizedGlobalConfig } from 'payload/types'
|
||||||
|
|
||||||
|
import { restoreVersionOperationGlobal } from 'payload/operations'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const restoreVersion = async ({
|
||||||
|
req,
|
||||||
|
globalConfig,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
globalConfig: SanitizedGlobalConfig
|
||||||
|
id: string
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
|
||||||
|
const doc = await restoreVersionOperationGlobal({
|
||||||
|
id,
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
globalConfig,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ...formatSuccessResponse(req.t('version:restoredSuccessfully'), 'message'),
|
||||||
|
return Response.json(doc, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
39
packages/next/src/routes/globals/update.ts
Normal file
39
packages/next/src/routes/globals/update.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import httpStatus from 'http-status'
|
||||||
|
|
||||||
|
import type { PayloadRequest, SanitizedGlobalConfig } from 'payload/types'
|
||||||
|
|
||||||
|
import { updateOperationGlobal } from 'payload/operations'
|
||||||
|
import { isNumber } from 'payload/utilities'
|
||||||
|
|
||||||
|
// TODO(JARROD): pattern to catch errors and return correct Response
|
||||||
|
export const update = async ({
|
||||||
|
req,
|
||||||
|
globalConfig,
|
||||||
|
}: {
|
||||||
|
req: PayloadRequest
|
||||||
|
globalConfig: SanitizedGlobalConfig
|
||||||
|
}): Promise<Response> => {
|
||||||
|
const { searchParams } = new URL(req.url)
|
||||||
|
const depth = searchParams.get('depth')
|
||||||
|
const draft = searchParams.get('draft') === 'true'
|
||||||
|
const autosave = searchParams.get('autosave') === 'true'
|
||||||
|
|
||||||
|
const result = await updateOperationGlobal({
|
||||||
|
autosave,
|
||||||
|
data: req.data,
|
||||||
|
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||||
|
draft,
|
||||||
|
globalConfig,
|
||||||
|
req,
|
||||||
|
slug: globalConfig.slug,
|
||||||
|
})
|
||||||
|
|
||||||
|
let message = req.t('general:updatedSuccessfully')
|
||||||
|
|
||||||
|
if (draft) message = req.t('version:draftSavedSuccessfully')
|
||||||
|
if (autosave) message = req.t('version:autosavedSuccessfully')
|
||||||
|
|
||||||
|
return Response.json(result, {
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
}
|
||||||
258
packages/next/src/routes/index.ts
Normal file
258
packages/next/src/routes/index.ts
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
import config from 'payload-config'
|
||||||
|
import { createPayloadRequest } from '../utilities/createPayloadRequest'
|
||||||
|
|
||||||
|
import { me } from './auth/me'
|
||||||
|
import { init } from './auth/init'
|
||||||
|
import { login } from './auth/login'
|
||||||
|
import { unlock } from './auth/unlock'
|
||||||
|
import { access } from './auth/access'
|
||||||
|
import { logout } from './auth/logout'
|
||||||
|
import { refresh } from './auth/refresh'
|
||||||
|
|
||||||
|
import { find } from './collections/find'
|
||||||
|
import { create } from './collections/create'
|
||||||
|
import { update } from './collections/update'
|
||||||
|
import { deleteDoc } from './collections/delete'
|
||||||
|
import { verifyEmail } from './auth/verifyEmail'
|
||||||
|
import { findByID } from './collections/findByID'
|
||||||
|
import { docAccess } from './collections/docAccess'
|
||||||
|
import { resetPassword } from './auth/resetPassword'
|
||||||
|
import { updateByID } from './collections/updateByID'
|
||||||
|
import { deleteByID } from './collections/deleteByID'
|
||||||
|
import { forgotPassword } from './auth/forgotPassword'
|
||||||
|
import { findVersions } from './collections/findVersions'
|
||||||
|
import { registerFirstUser } from './auth/registerFirstUser'
|
||||||
|
import { restoreVersion } from './collections/restoreVersion'
|
||||||
|
import { findVersionByID } from './collections/findVersionByID'
|
||||||
|
|
||||||
|
import { findOne } from './globals/findOne'
|
||||||
|
import { update as updateGlobal } from './globals/update'
|
||||||
|
import { docAccess as docAccessGlobal } from './globals/docAccess'
|
||||||
|
import { findVersions as findVersionsGlobal } from './globals/findVersions'
|
||||||
|
import { restoreVersion as restoreVersionGlobal } from './globals/restoreVersion'
|
||||||
|
import { findVersionByID as findVersionByIdGlobal } from './globals/findVersionByID'
|
||||||
|
|
||||||
|
const endpoints = {
|
||||||
|
root: {
|
||||||
|
GET: {
|
||||||
|
access,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
collection: {
|
||||||
|
GET: {
|
||||||
|
init,
|
||||||
|
me,
|
||||||
|
versions: findVersions,
|
||||||
|
find,
|
||||||
|
findByID,
|
||||||
|
'doc-access-by-id': docAccess,
|
||||||
|
'doc-versions-by-id': findVersionByID,
|
||||||
|
},
|
||||||
|
POST: {
|
||||||
|
create,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
unlock,
|
||||||
|
access: docAccess,
|
||||||
|
'first-register': registerFirstUser,
|
||||||
|
'forgot-password': forgotPassword,
|
||||||
|
'reset-password': resetPassword,
|
||||||
|
'refresh-token': refresh,
|
||||||
|
'doc-access-by-id': docAccess,
|
||||||
|
'doc-versions-by-id': restoreVersion,
|
||||||
|
'doc-verify-by-id': verifyEmail,
|
||||||
|
},
|
||||||
|
PATCH: {
|
||||||
|
update,
|
||||||
|
updateByID,
|
||||||
|
},
|
||||||
|
DELETE: {
|
||||||
|
delete: deleteDoc,
|
||||||
|
deleteByID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
GET: {
|
||||||
|
findOne,
|
||||||
|
'doc-access': docAccessGlobal,
|
||||||
|
'doc-versions': findVersionsGlobal,
|
||||||
|
'doc-versions-by-id': findVersionByIdGlobal,
|
||||||
|
},
|
||||||
|
POST: {
|
||||||
|
update: updateGlobal,
|
||||||
|
'doc-access': docAccessGlobal,
|
||||||
|
'doc-versions-by-id': restoreVersionGlobal,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
request: Request,
|
||||||
|
{ params: { slug } }: { params: { slug: string[] } },
|
||||||
|
) => {
|
||||||
|
const [slug1, slug2, slug3, slug4] = slug
|
||||||
|
|
||||||
|
const req = await createPayloadRequest({
|
||||||
|
request,
|
||||||
|
config,
|
||||||
|
params: {
|
||||||
|
collection: slug1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (slug.length === 1 && slug1 === 'access') {
|
||||||
|
return endpoints.root.GET.access({ req })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req?.collection) {
|
||||||
|
switch (slug.length) {
|
||||||
|
case 1:
|
||||||
|
// /:collection
|
||||||
|
return endpoints.collection.GET.find({ req })
|
||||||
|
case 2:
|
||||||
|
if (slug2 in endpoints.collection.GET) {
|
||||||
|
// /:collection/init
|
||||||
|
// /:collection/me
|
||||||
|
// /:collection/versions
|
||||||
|
return endpoints.collection.GET?.[slug2]({ req })
|
||||||
|
} else if (req.collection.config.endpoints && req.collection.config.endpoints.length > 0) {
|
||||||
|
// /:collection/:id
|
||||||
|
}
|
||||||
|
return endpoints.collection.GET.findByID({ req, id: slug2 })
|
||||||
|
case 3:
|
||||||
|
// /:collection/access/:id
|
||||||
|
// /:collection/versions/:id
|
||||||
|
const key = `doc-${slug2}-by-id`
|
||||||
|
if (key in endpoints.collection.GET) {
|
||||||
|
return endpoints.collection.GET[key]({ req, id: slug3 })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return new Response('Route Not Found', { status: 404 })
|
||||||
|
}
|
||||||
|
} else if (slug1 === 'globals') {
|
||||||
|
const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2)
|
||||||
|
|
||||||
|
switch (slug.length) {
|
||||||
|
case 2:
|
||||||
|
// /globals/:slug
|
||||||
|
return endpoints.global.GET.findOne({ req, globalConfig })
|
||||||
|
case 3:
|
||||||
|
// /globals/:slug/access
|
||||||
|
// /globals/:slug/versions
|
||||||
|
return endpoints.global.GET?.[`doc-${slug3}`]({ req, globalConfig })
|
||||||
|
case 4:
|
||||||
|
// /globals/:slug/versions/:id
|
||||||
|
return endpoints.global.GET?.[`doc-${slug3}-by-id`]({ req, id: slug4, globalConfig })
|
||||||
|
default:
|
||||||
|
return new Response('Route Not Found', { status: 404 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
request: Request,
|
||||||
|
{ params: { slug } }: { params: { slug: string[] } },
|
||||||
|
) => {
|
||||||
|
const [slug1, slug2, slug3, slug4] = slug
|
||||||
|
|
||||||
|
const req = await createPayloadRequest({ request, config, params: { collection: slug1 } })
|
||||||
|
|
||||||
|
if (req?.collection) {
|
||||||
|
switch (slug.length) {
|
||||||
|
case 1:
|
||||||
|
// /:collection
|
||||||
|
return endpoints.collection.POST.create({ req })
|
||||||
|
case 2:
|
||||||
|
if (slug2 in endpoints.collection.POST) {
|
||||||
|
// /:collection/login
|
||||||
|
// /:collection/logout
|
||||||
|
// /:collection/unlock
|
||||||
|
// /:collection/access
|
||||||
|
// /:collection/first-register
|
||||||
|
// /:collection/forgot-password
|
||||||
|
// /:collection/reset-password
|
||||||
|
// /:collection/refresh-token
|
||||||
|
return endpoints.collection.POST[slug2]({ req })
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
// /:collection/access/:id
|
||||||
|
// /:collection/versions/:id
|
||||||
|
// /:collection/verify/:token ("doc-verify-by-id" uses id as token internally)
|
||||||
|
return endpoints.collection.POST?.[`doc-${slug2}-by-id`]({ req, id: slug3 })
|
||||||
|
default:
|
||||||
|
return new Response('Route Not Found', { status: 404 })
|
||||||
|
}
|
||||||
|
} else if (slug1 === 'globals') {
|
||||||
|
const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2)
|
||||||
|
switch (slug.length) {
|
||||||
|
case 2:
|
||||||
|
// /globals/:slug
|
||||||
|
return endpoints.global.POST.update({ req, globalConfig })
|
||||||
|
case 3:
|
||||||
|
// /globals/:slug/access
|
||||||
|
return endpoints.global.POST?.[`doc-${slug3}`]({ req, globalConfig })
|
||||||
|
case 4:
|
||||||
|
// /globals/:slug/versions/:id
|
||||||
|
return endpoints.global.POST?.[`doc-${slug3}-by-id`]({ req, id: slug4, globalConfig })
|
||||||
|
default:
|
||||||
|
return new Response('Route Not Found', { status: 404 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DELETE = async (
|
||||||
|
request: Request,
|
||||||
|
{ params: { slug } }: { params: { slug: string[] } },
|
||||||
|
) => {
|
||||||
|
const [slug1, slug2] = slug
|
||||||
|
|
||||||
|
const req = await createPayloadRequest({
|
||||||
|
request,
|
||||||
|
config,
|
||||||
|
params: {
|
||||||
|
collection: slug1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (req?.collection) {
|
||||||
|
switch (slug.length) {
|
||||||
|
case 1:
|
||||||
|
// /:collection
|
||||||
|
return endpoints.collection.DELETE.delete({ req })
|
||||||
|
case 2:
|
||||||
|
// /:collection/:id
|
||||||
|
return endpoints.collection.DELETE.deleteByID({ req, id: slug2 })
|
||||||
|
default:
|
||||||
|
return new Response('Route Not Found', { status: 404 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PATCH = async (
|
||||||
|
request: Request,
|
||||||
|
{ params: { slug } }: { params: { slug: string[] } },
|
||||||
|
) => {
|
||||||
|
const [slug1, slug2] = slug
|
||||||
|
|
||||||
|
const req = await createPayloadRequest({
|
||||||
|
request,
|
||||||
|
config,
|
||||||
|
params: {
|
||||||
|
collection: slug1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (req?.collection) {
|
||||||
|
switch (slug.length) {
|
||||||
|
case 1:
|
||||||
|
// /:collection
|
||||||
|
return endpoints.collection.PATCH.update({ req })
|
||||||
|
case 2:
|
||||||
|
// /:collection/:id
|
||||||
|
return endpoints.collection.PATCH.updateByID({ req, id: slug2 })
|
||||||
|
default:
|
||||||
|
return new Response('Route Not Found', { status: 404 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import type { SanitizedConfig } from 'payload/types'
|
|
||||||
import { init as initOperation } from 'payload/operations'
|
|
||||||
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, params })
|
|
||||||
|
|
||||||
const initialized = await initOperation({
|
|
||||||
collection: params.collection,
|
|
||||||
req,
|
|
||||||
})
|
|
||||||
|
|
||||||
return Response.json({ initialized })
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import { login as loginOperation } from 'payload/operations'
|
|
||||||
import { createPayloadRequest } from '../createPayloadRequest'
|
|
||||||
import { SanitizedConfig } from 'payload/types'
|
|
||||||
import { isNumber } from 'payload/utilities'
|
|
||||||
|
|
||||||
export const login = ({ config }: { config: Promise<SanitizedConfig> }) =>
|
|
||||||
async function (request: Request, { params }: { params: { collection: string } }) {
|
|
||||||
const req = await createPayloadRequest({ request, config })
|
|
||||||
const collection = req.payload.collections[params.collection]
|
|
||||||
|
|
||||||
const { searchParams } = new URL(request.url)
|
|
||||||
const depth = searchParams.get('depth')
|
|
||||||
let responseOptions = {
|
|
||||||
headers: new Headers(),
|
|
||||||
}
|
|
||||||
const result = await loginOperation({
|
|
||||||
collection,
|
|
||||||
data: {
|
|
||||||
email: typeof req.data?.email === 'string' ? req.data.email : '',
|
|
||||||
password: typeof req.data?.password === 'string' ? req.data.password : '',
|
|
||||||
},
|
|
||||||
depth: isNumber(depth) ? Number(depth) : undefined,
|
|
||||||
req,
|
|
||||||
responseOptions,
|
|
||||||
})
|
|
||||||
|
|
||||||
return Response.json(
|
|
||||||
{
|
|
||||||
exp: result.exp,
|
|
||||||
message: 'Auth Passed',
|
|
||||||
token: result.token,
|
|
||||||
user: result.user,
|
|
||||||
},
|
|
||||||
responseOptions,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import type { SanitizedConfig } from 'payload/types'
|
|
||||||
import { me as meOperation } from 'payload/operations'
|
|
||||||
import { createPayloadRequest } from '../createPayloadRequest'
|
|
||||||
|
|
||||||
export const me = ({ config }: { config: Promise<SanitizedConfig> }) =>
|
|
||||||
async function (request: Request, { params }: { params: { collection: string } }) {
|
|
||||||
const req = await createPayloadRequest({ request, config })
|
|
||||||
const collection = req.payload.collections[params.collection]
|
|
||||||
const meRes = await meOperation({
|
|
||||||
collection,
|
|
||||||
req,
|
|
||||||
})
|
|
||||||
|
|
||||||
return Response.json(meRes)
|
|
||||||
}
|
|
||||||
146
packages/next/src/utilities/cookies.ts
Normal file
146
packages/next/src/utilities/cookies.ts
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
import type { PayloadT, SanitizedCollectionConfig } from 'payload/types'
|
||||||
|
|
||||||
|
type CookieOptions = {
|
||||||
|
domain?: string
|
||||||
|
expires?: Date
|
||||||
|
httpOnly?: boolean
|
||||||
|
maxAge?: number
|
||||||
|
name: string
|
||||||
|
path?: string
|
||||||
|
sameSite?: 'Lax' | 'None' | 'Strict'
|
||||||
|
secure?: boolean
|
||||||
|
value?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateCookies = (cookies: CookieOptions[]): string => {
|
||||||
|
return cookies.map((options) => generateCookie(options)).join('; ')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateCookie = (args: CookieOptions): string => {
|
||||||
|
const { name, domain, expires, httpOnly, maxAge, path, sameSite, secure: secureArg, value } = args
|
||||||
|
|
||||||
|
let cookieString = `${name}=${value || ''}`
|
||||||
|
|
||||||
|
const secure = secureArg || sameSite === 'None'
|
||||||
|
|
||||||
|
if (expires) {
|
||||||
|
cookieString += `; Expires=${expires.toUTCString()}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxAge) {
|
||||||
|
cookieString += `; Max-Age=${maxAge}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domain) {
|
||||||
|
cookieString += `; Domain=${domain}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
cookieString += `; Path=${path}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secure) {
|
||||||
|
cookieString += '; Secure'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (httpOnly) {
|
||||||
|
cookieString += '; HttpOnly'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sameSite) {
|
||||||
|
cookieString += `; SameSite=${sameSite}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return cookieString
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetCookieExpirationArgs = {
|
||||||
|
/*
|
||||||
|
The number of seconds until the cookie expires
|
||||||
|
@default 7200 seconds (2 hours)
|
||||||
|
*/
|
||||||
|
seconds: number
|
||||||
|
}
|
||||||
|
const getCookieExpiration = ({ seconds = 7200 }: GetCookieExpirationArgs) => {
|
||||||
|
const currentTime = new Date()
|
||||||
|
currentTime.setSeconds(currentTime.getSeconds() + seconds)
|
||||||
|
return currentTime
|
||||||
|
}
|
||||||
|
|
||||||
|
type GeneratePayloadCookieArgs = {
|
||||||
|
/* The auth collection config */
|
||||||
|
collectionConfig: SanitizedCollectionConfig
|
||||||
|
/* An instance of payload */
|
||||||
|
payload: PayloadT
|
||||||
|
/* The token to be stored in the cookie */
|
||||||
|
token: string
|
||||||
|
}
|
||||||
|
export const generatePayloadCookie = ({
|
||||||
|
collectionConfig,
|
||||||
|
payload,
|
||||||
|
token,
|
||||||
|
}: GeneratePayloadCookieArgs): string => {
|
||||||
|
const sameSite =
|
||||||
|
typeof collectionConfig.auth.cookies.sameSite === 'string'
|
||||||
|
? collectionConfig.auth.cookies.sameSite
|
||||||
|
: collectionConfig.auth.cookies.sameSite
|
||||||
|
? 'Strict'
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
return generateCookie({
|
||||||
|
name: `${payload.config.cookiePrefix}-token`,
|
||||||
|
domain: collectionConfig.auth.cookies.domain ?? undefined,
|
||||||
|
expires: getCookieExpiration({ seconds: collectionConfig.auth.tokenExpiration }),
|
||||||
|
httpOnly: true,
|
||||||
|
path: '/',
|
||||||
|
sameSite,
|
||||||
|
secure: collectionConfig.auth.cookies.secure,
|
||||||
|
value: token,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateExpiredPayloadCookie = ({
|
||||||
|
collectionConfig,
|
||||||
|
payload,
|
||||||
|
}: Omit<GeneratePayloadCookieArgs, 'token'>): string => {
|
||||||
|
const sameSite =
|
||||||
|
typeof collectionConfig.auth.cookies.sameSite === 'string'
|
||||||
|
? collectionConfig.auth.cookies.sameSite
|
||||||
|
: collectionConfig.auth.cookies.sameSite
|
||||||
|
? 'Strict'
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const expires = new Date(Date.now() - 1000)
|
||||||
|
|
||||||
|
return generateCookie({
|
||||||
|
name: `${payload.config.cookiePrefix}-token`,
|
||||||
|
domain: collectionConfig.auth.cookies.domain ?? undefined,
|
||||||
|
expires,
|
||||||
|
httpOnly: true,
|
||||||
|
path: '/',
|
||||||
|
sameSite,
|
||||||
|
secure: collectionConfig.auth.cookies.secure,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const parseCookies = (headers: Request['headers']): Map<string, string> => {
|
||||||
|
const cookieMap = new Map<string, string>()
|
||||||
|
const cookie = headers.get('Cookie')
|
||||||
|
|
||||||
|
if (cookie) {
|
||||||
|
cookie.split(';').forEach((cookie) => {
|
||||||
|
const parts = cookie.split('=')
|
||||||
|
const key = parts.shift().trim()
|
||||||
|
const encodedValue = parts.join('=')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decodedValue = decodeURI(encodedValue)
|
||||||
|
cookieMap.set(key, decodedValue)
|
||||||
|
} catch (e) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return cookieMap
|
||||||
|
}
|
||||||
34
packages/next/src/utilities/jwt.ts
Normal file
34
packages/next/src/utilities/jwt.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { AuthStrategyFunctionArgs } from 'payload/auth'
|
||||||
|
import { parseCookies } from './cookies'
|
||||||
|
|
||||||
|
export const extractJWT = (
|
||||||
|
args: Pick<AuthStrategyFunctionArgs, 'headers' | 'payload'>,
|
||||||
|
): null | string => {
|
||||||
|
const { headers, payload } = args
|
||||||
|
|
||||||
|
const jwtFromHeader = headers.get('Authorization')
|
||||||
|
const origin = headers.get('Origin')
|
||||||
|
|
||||||
|
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?.startsWith('Bearer ')) {
|
||||||
|
return jwtFromHeader.replace('Bearer ', '')
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookies = parseCookies(headers)
|
||||||
|
const tokenCookieName = `${payload.config.cookiePrefix}-token`
|
||||||
|
const cookieToken = cookies?.get(tokenCookieName)
|
||||||
|
|
||||||
|
if (!cookieToken) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!origin || payload.config.csrf.length === 0 || payload.config.csrf.indexOf(origin) > -1) {
|
||||||
|
return cookieToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import type { PayloadRequest } from '../exports/types'
|
|||||||
import { Forbidden } from '../errors'
|
import { Forbidden } from '../errors'
|
||||||
|
|
||||||
type OperationArgs = {
|
type OperationArgs = {
|
||||||
data?: Record<string, unknown>
|
data?: any
|
||||||
disableErrors?: boolean
|
disableErrors?: boolean
|
||||||
id?: number | string
|
id?: number | string
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { AuthStrategyFunctionArgs } from '.'
|
import type { AuthStrategyFunctionArgs } from '.'
|
||||||
|
|
||||||
import { parseCookies } from '../utilities/cookies'
|
import { parseCookies } from '../utilities/parseCookies'
|
||||||
|
|
||||||
export const extractJWT = (
|
export const extractJWT = (
|
||||||
args: Pick<AuthStrategyFunctionArgs, 'headers' | 'payload'>,
|
args: Pick<AuthStrategyFunctionArgs, 'headers' | 'payload'>,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import type { User } from '..'
|
import type { User } from '.'
|
||||||
import type { CollectionConfig } from '../../collections/config/types'
|
import type { CollectionConfig } from '../collections/config/types'
|
||||||
import type { Field, TabAsField } from '../../fields/config/types'
|
import type { Field, TabAsField } from '../fields/config/types'
|
||||||
|
|
||||||
import { fieldAffectsData, tabHasName } from '../../fields/config/types'
|
import { fieldAffectsData, tabHasName } from '../fields/config/types'
|
||||||
|
|
||||||
type TraverseFieldsArgs = {
|
type TraverseFieldsArgs = {
|
||||||
data: Record<string, unknown>
|
data: Record<string, unknown>
|
||||||
@@ -2,7 +2,7 @@ import type { PayloadT } from '../../..'
|
|||||||
|
|
||||||
import formatName from '../../../graphql/utilities/formatName'
|
import formatName from '../../../graphql/utilities/formatName'
|
||||||
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
||||||
import access from '../../operations/access'
|
import { accessOperation } from '../../operations/access'
|
||||||
|
|
||||||
const formatConfigNames = (results, configs) => {
|
const formatConfigNames = (results, configs) => {
|
||||||
const formattedResults = { ...results }
|
const formattedResults = { ...results }
|
||||||
@@ -22,7 +22,7 @@ function accessResolver(payload: PayloadT) {
|
|||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
}
|
}
|
||||||
|
|
||||||
const accessResults = await access(options)
|
const accessResults = await accessOperation(options)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...accessResults,
|
...accessResults,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
||||||
import init from '../../operations/init'
|
import { init } from '../../operations/init'
|
||||||
|
|
||||||
function initResolver(collection: string) {
|
function initResolver(collection: string) {
|
||||||
async function resolver(_, args, context) {
|
async function resolver(_, args, context) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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 login from '../../operations/login'
|
import { loginOperation } from '../../operations/login'
|
||||||
|
|
||||||
function loginResolver(collection: Collection) {
|
function loginResolver(collection: Collection) {
|
||||||
async function resolver(_, args, context) {
|
async function resolver(_, args, context) {
|
||||||
@@ -16,7 +16,7 @@ function loginResolver(collection: Collection) {
|
|||||||
res: context.res,
|
res: context.res,
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = login(options)
|
const result = loginOperation(options)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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 logout from '../../operations/logout'
|
import { logoutOperation } from '../../operations/logout'
|
||||||
|
|
||||||
function logoutResolver(collection: Collection): any {
|
function logoutResolver(collection: Collection): any {
|
||||||
async function resolver(_, args, context) {
|
async function resolver(_, args, context) {
|
||||||
@@ -11,7 +11,7 @@ function logoutResolver(collection: Collection): any {
|
|||||||
res: context.res,
|
res: context.res,
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await logout(options)
|
const result = await logoutOperation(options)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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 me from '../../operations/me'
|
import { meOperation } from '../../operations/me'
|
||||||
|
|
||||||
function meResolver(collection: Collection): any {
|
function meResolver(collection: Collection): any {
|
||||||
async function resolver(_, args, context) {
|
async function resolver(_, args, context) {
|
||||||
@@ -10,7 +10,7 @@ function meResolver(collection: Collection): any {
|
|||||||
depth: 0,
|
depth: 0,
|
||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
}
|
}
|
||||||
return me(options)
|
return meOperation(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolver
|
return resolver
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { Collection } from '../../../collections/config/types'
|
|||||||
|
|
||||||
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
||||||
import { extractJWT } from '../../getExtractJWT'
|
import { extractJWT } from '../../getExtractJWT'
|
||||||
import refresh from '../../operations/refresh'
|
import { refreshOperation } from '../../operations/refresh'
|
||||||
|
|
||||||
function refreshResolver(collection: Collection) {
|
function refreshResolver(collection: Collection) {
|
||||||
async function resolver(_, args, context) {
|
async function resolver(_, args, context) {
|
||||||
@@ -22,7 +22,7 @@ function refreshResolver(collection: Collection) {
|
|||||||
token,
|
token,
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await refresh(options)
|
const result = await refreshOperation(options)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
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 resetPassword from '../../operations/resetPassword'
|
import { resetPasswordOperation } from '../../operations/resetPassword'
|
||||||
|
|
||||||
function resetPasswordResolver(collection: Collection) {
|
function resetPasswordResolver(collection: Collection) {
|
||||||
async function resolver(_, args, context) {
|
async function resolver(_, args, context) {
|
||||||
@@ -18,7 +18,7 @@ function resetPasswordResolver(collection: Collection) {
|
|||||||
res: context.res,
|
res: context.res,
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await resetPassword(options)
|
const result = await resetPasswordOperation(options)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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 unlock from '../../operations/unlock'
|
import { unlockOperation } from '../../operations/unlock'
|
||||||
|
|
||||||
function unlockResolver(collection: Collection) {
|
function unlockResolver(collection: Collection) {
|
||||||
async function resolver(_, args, context) {
|
async function resolver(_, args, context) {
|
||||||
@@ -11,7 +11,7 @@ function unlockResolver(collection: Collection) {
|
|||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await unlock(options)
|
const result = await unlockOperation(options)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
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 verifyEmail from '../../operations/verifyEmail'
|
import { verifyEmailOperation } from '../../operations/verifyEmail'
|
||||||
|
|
||||||
function verifyEmailResolver(collection: Collection) {
|
function verifyEmailResolver(collection: Collection) {
|
||||||
async function resolver(_, args, context) {
|
async function resolver(_, args, context) {
|
||||||
@@ -17,7 +17,7 @@ function verifyEmailResolver(collection: Collection) {
|
|||||||
token: args.token,
|
token: args.token,
|
||||||
}
|
}
|
||||||
|
|
||||||
const success = await verifyEmail(options)
|
const success = await verifyEmailOperation(options)
|
||||||
return success
|
return success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import httpStatus from 'http-status'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../types'
|
|
||||||
import type { Permissions } from '../types'
|
|
||||||
|
|
||||||
import access from '../operations/access'
|
|
||||||
|
|
||||||
export default async function accessRequestHandler(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction,
|
|
||||||
): Promise<Response<Permissions> | void> {
|
|
||||||
try {
|
|
||||||
const accessResults = await access({
|
|
||||||
req,
|
|
||||||
})
|
|
||||||
|
|
||||||
return res.status(httpStatus.OK).json(accessResults)
|
|
||||||
} catch (error) {
|
|
||||||
return next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import httpStatus from 'http-status'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../types'
|
|
||||||
|
|
||||||
import forgotPassword from '../operations/forgotPassword'
|
|
||||||
|
|
||||||
export default async function forgotPasswordHandler(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction,
|
|
||||||
): Promise<any> {
|
|
||||||
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,
|
|
||||||
req,
|
|
||||||
})
|
|
||||||
|
|
||||||
return res.status(httpStatus.OK).json({
|
|
||||||
message: 'Success',
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
return next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import type { SanitizedConfig } from '../../exports/config'
|
|
||||||
|
|
||||||
import { getPayload } from '../..'
|
|
||||||
import init from '../operations/init'
|
|
||||||
|
|
||||||
export const initHandler = ({ config }: { config: Promise<SanitizedConfig> }) =>
|
|
||||||
async function (request: Request, { params }: { params: { collection: string } }) {
|
|
||||||
const payload = await getPayload({ config })
|
|
||||||
request.payload = payload
|
|
||||||
|
|
||||||
const initialized = await init({
|
|
||||||
collection: params.collection,
|
|
||||||
req: request,
|
|
||||||
})
|
|
||||||
|
|
||||||
return Response.json({ initialized })
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import httpStatus from 'http-status'
|
|
||||||
import { URL } from 'url'
|
|
||||||
|
|
||||||
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(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
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: isNumber(depth) ? depth : undefined,
|
|
||||||
req,
|
|
||||||
res,
|
|
||||||
})
|
|
||||||
|
|
||||||
res.status(httpStatus.OK).json({
|
|
||||||
exp: result.exp,
|
|
||||||
message: 'Auth Passed',
|
|
||||||
token: result.token,
|
|
||||||
user: result.user,
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import httpStatus from 'http-status'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../types'
|
|
||||||
|
|
||||||
import logout from '../operations/logout'
|
|
||||||
|
|
||||||
export default async function logoutHandler(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction,
|
|
||||||
): Promise<Response<{ message: string }> | void> {
|
|
||||||
try {
|
|
||||||
const message = await logout({
|
|
||||||
collection: req.collection,
|
|
||||||
req,
|
|
||||||
res,
|
|
||||||
})
|
|
||||||
|
|
||||||
return res.status(httpStatus.OK).json({ message })
|
|
||||||
} catch (error) {
|
|
||||||
return next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../types'
|
|
||||||
|
|
||||||
import me from '../operations/me'
|
|
||||||
|
|
||||||
export default async function meHandler(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction,
|
|
||||||
): Promise<any> {
|
|
||||||
try {
|
|
||||||
const response = await me({
|
|
||||||
collection: req.collection,
|
|
||||||
req,
|
|
||||||
})
|
|
||||||
return res.status(200).json(response)
|
|
||||||
} catch (err) {
|
|
||||||
return next(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../types'
|
|
||||||
|
|
||||||
import { extractJWT } from '../getExtractJWT'
|
|
||||||
import refresh from '../operations/refresh'
|
|
||||||
|
|
||||||
export default async function refreshHandler(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction,
|
|
||||||
): Promise<any> {
|
|
||||||
try {
|
|
||||||
let token
|
|
||||||
|
|
||||||
token = extractJWT(req)
|
|
||||||
|
|
||||||
if (req.body) {
|
|
||||||
token = req.body.data
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await refresh({
|
|
||||||
collection: req.collection,
|
|
||||||
req,
|
|
||||||
res,
|
|
||||||
token,
|
|
||||||
})
|
|
||||||
|
|
||||||
return res.status(200).json({
|
|
||||||
message: 'Token refresh successful',
|
|
||||||
...result,
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
return next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../types'
|
|
||||||
|
|
||||||
import registerFirstUser from '../operations/registerFirstUser'
|
|
||||||
|
|
||||||
export default async function registerFirstUserHandler(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction,
|
|
||||||
): Promise<any> {
|
|
||||||
try {
|
|
||||||
const firstUser = await registerFirstUser({
|
|
||||||
collection: req.collection,
|
|
||||||
// TODO(JARROD): remove reliance on express body parsing
|
|
||||||
data: req.body,
|
|
||||||
req,
|
|
||||||
res,
|
|
||||||
})
|
|
||||||
|
|
||||||
return res.status(201).json(firstUser)
|
|
||||||
} catch (error) {
|
|
||||||
return next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import httpStatus from 'http-status'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../types'
|
|
||||||
|
|
||||||
import resetPassword from '../operations/resetPassword'
|
|
||||||
|
|
||||||
async function resetPasswordHandler(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction,
|
|
||||||
): Promise<any> {
|
|
||||||
try {
|
|
||||||
const result = await resetPassword({
|
|
||||||
collection: req.collection,
|
|
||||||
// TODO(JARROD): remove reliance on express body parsing
|
|
||||||
data: req.body,
|
|
||||||
req,
|
|
||||||
res,
|
|
||||||
})
|
|
||||||
|
|
||||||
return res.status(httpStatus.OK).json({
|
|
||||||
message: 'Password reset successfully.',
|
|
||||||
token: result.token,
|
|
||||||
user: result.user,
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
return next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default resetPasswordHandler
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import httpStatus from 'http-status'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../types'
|
|
||||||
|
|
||||||
import unlock from '../operations/unlock'
|
|
||||||
|
|
||||||
export default async function unlockHandler(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction,
|
|
||||||
): Promise<any> {
|
|
||||||
try {
|
|
||||||
await unlock({
|
|
||||||
collection: req.collection,
|
|
||||||
// TODO(JARROD): remove reliance on express body parsing
|
|
||||||
data: { email: req.body.email },
|
|
||||||
req,
|
|
||||||
})
|
|
||||||
|
|
||||||
return res.status(httpStatus.OK).json({
|
|
||||||
message: 'Success',
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
return next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// TODO(JARROD): remove reliance on express
|
|
||||||
import type { NextFunction, Response } from 'express'
|
|
||||||
|
|
||||||
import httpStatus from 'http-status'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../types'
|
|
||||||
|
|
||||||
import verifyEmail from '../operations/verifyEmail'
|
|
||||||
|
|
||||||
async function verifyEmailHandler(
|
|
||||||
req: PayloadRequest,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction,
|
|
||||||
): Promise<any> {
|
|
||||||
try {
|
|
||||||
await verifyEmail({
|
|
||||||
collection: req.collection,
|
|
||||||
req,
|
|
||||||
token: req.params.token,
|
|
||||||
})
|
|
||||||
|
|
||||||
return res.status(httpStatus.OK).json({
|
|
||||||
message: 'Email verified successfully.',
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
return next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default verifyEmailHandler
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import passport from 'passport'
|
|
||||||
import AnonymousStrategy from 'passport-anonymous'
|
|
||||||
|
|
||||||
import type { Payload } from '../payload'
|
|
||||||
|
|
||||||
import jwtStrategy from './strategies/jwt'
|
|
||||||
|
|
||||||
function initAuth(ctx: Payload): void {
|
|
||||||
passport.use(new AnonymousStrategy.Strategy())
|
|
||||||
passport.use('jwt', jwtStrategy(ctx))
|
|
||||||
}
|
|
||||||
|
|
||||||
export default initAuth
|
|
||||||
@@ -11,7 +11,7 @@ type Arguments = {
|
|||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
async function accessOperation(args: Arguments): Promise<Permissions> {
|
export const accessOperation = async (args: Arguments): Promise<Permissions> => {
|
||||||
const {
|
const {
|
||||||
req,
|
req,
|
||||||
req: { payload, user },
|
req: { payload, user },
|
||||||
@@ -40,5 +40,3 @@ async function accessOperation(args: Arguments): Promise<Permissions> {
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default accessOperation
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export type Arguments = {
|
|||||||
|
|
||||||
export type Result = string
|
export type Result = string
|
||||||
|
|
||||||
async function forgotPassword(incomingArgs: Arguments): Promise<null | string> {
|
export const forgotPasswordOperation = async (incomingArgs: Arguments): Promise<null | string> => {
|
||||||
if (!Object.prototype.hasOwnProperty.call(incomingArgs.data, 'email')) {
|
if (!Object.prototype.hasOwnProperty.call(incomingArgs.data, 'email')) {
|
||||||
throw new APIError('Missing email.', 400)
|
throw new APIError('Missing email.', 400)
|
||||||
}
|
}
|
||||||
@@ -66,8 +66,7 @@ async function forgotPassword(incomingArgs: Arguments): Promise<null | string> {
|
|||||||
// Forget password
|
// Forget password
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
let token: Buffer | string = crypto.randomBytes(20)
|
let token: string = crypto.randomBytes(20).toString('hex')
|
||||||
token = token.toString('hex')
|
|
||||||
|
|
||||||
type UserDoc = {
|
type UserDoc = {
|
||||||
id: number | string
|
id: number | string
|
||||||
@@ -165,5 +164,3 @@ async function forgotPassword(incomingArgs: Arguments): Promise<null | string> {
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default forgotPassword
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import type { PayloadRequest } from '../../types'
|
import type { PayloadRequest } from '../../types'
|
||||||
|
|
||||||
async function init(args: { collection: string; req: PayloadRequest }): Promise<boolean> {
|
export const initOperation = async (args: {
|
||||||
|
collection: string
|
||||||
|
req: PayloadRequest
|
||||||
|
}): Promise<boolean> => {
|
||||||
const { collection: slug, req } = args
|
const { collection: slug, req } = args
|
||||||
|
|
||||||
const doc = await req.payload.db.findOne({
|
const doc = await req.payload.db.findOne({
|
||||||
@@ -10,5 +13,3 @@ async function init(args: { collection: string; req: PayloadRequest }): Promise<
|
|||||||
|
|
||||||
return !!doc
|
return !!doc
|
||||||
}
|
}
|
||||||
|
|
||||||
export default init
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { getDataLoader } from '../../../collections/dataloader'
|
|||||||
import { APIError } from '../../../errors'
|
import { APIError } from '../../../errors'
|
||||||
import { i18nInit } from '../../../translations/init'
|
import { i18nInit } from '../../../translations/init'
|
||||||
import { setRequestContext } from '../../../utilities/setRequestContext'
|
import { setRequestContext } from '../../../utilities/setRequestContext'
|
||||||
import forgotPassword from '../forgotPassword'
|
import { forgotPasswordOperation } from '../forgotPassword'
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -50,7 +50,7 @@ async function localForgotPassword<T extends keyof GeneratedTypes['collections']
|
|||||||
if (!req.t) req.t = req.i18n.t
|
if (!req.t) req.t = req.i18n.t
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req)
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req)
|
||||||
|
|
||||||
return forgotPassword({
|
return forgotPasswordOperation({
|
||||||
collection,
|
collection,
|
||||||
data,
|
data,
|
||||||
disableEmail,
|
disableEmail,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import type { Response } from 'express'
|
|
||||||
|
|
||||||
import type { PayloadT, RequestContext } from '../../..'
|
import type { PayloadT, RequestContext } from '../../..'
|
||||||
import type { GeneratedTypes } from '../../../index'
|
import type { GeneratedTypes } from '../../../index'
|
||||||
import type { PayloadRequest } from '../../../types'
|
import type { PayloadRequest } from '../../../types'
|
||||||
@@ -9,7 +7,7 @@ import { getDataLoader } from '../../../collections/dataloader'
|
|||||||
import { APIError } from '../../../errors'
|
import { APIError } from '../../../errors'
|
||||||
import { i18nInit } from '../../../translations/init'
|
import { i18nInit } from '../../../translations/init'
|
||||||
import { setRequestContext } from '../../../utilities/setRequestContext'
|
import { setRequestContext } from '../../../utilities/setRequestContext'
|
||||||
import login from '../login'
|
import { loginOperation } from '../login'
|
||||||
|
|
||||||
export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: TSlug
|
collection: TSlug
|
||||||
@@ -23,7 +21,6 @@ export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
|||||||
locale?: string
|
locale?: string
|
||||||
overrideAccess?: boolean
|
overrideAccess?: boolean
|
||||||
req?: PayloadRequest
|
req?: PayloadRequest
|
||||||
res?: Response
|
|
||||||
showHiddenFields?: boolean
|
showHiddenFields?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +37,6 @@ async function localLogin<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
locale,
|
locale,
|
||||||
overrideAccess = true,
|
overrideAccess = true,
|
||||||
req = {} as PayloadRequest,
|
req = {} as PayloadRequest,
|
||||||
res,
|
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
} = options
|
} = options
|
||||||
setRequestContext(req, context)
|
setRequestContext(req, context)
|
||||||
@@ -68,14 +64,13 @@ async function localLogin<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
depth,
|
depth,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
res,
|
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locale) args.req.locale = locale
|
if (locale) args.req.locale = locale
|
||||||
if (fallbackLocale) args.req.fallbackLocale = fallbackLocale
|
if (fallbackLocale) args.req.fallbackLocale = fallbackLocale
|
||||||
|
|
||||||
return login<TSlug>(args)
|
return loginOperation<TSlug>(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default localLogin
|
export default localLogin
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { getDataLoader } from '../../../collections/dataloader'
|
|||||||
import { APIError } from '../../../errors'
|
import { APIError } from '../../../errors'
|
||||||
import { i18nInit } from '../../../translations/init'
|
import { i18nInit } from '../../../translations/init'
|
||||||
import { setRequestContext } from '../../../utilities/setRequestContext'
|
import { setRequestContext } from '../../../utilities/setRequestContext'
|
||||||
import resetPassword from '../resetPassword'
|
import { resetPasswordOperation } from '../resetPassword'
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -51,7 +51,7 @@ async function localResetPassword<T extends keyof GeneratedTypes['collections']>
|
|||||||
if (!req.t) req.t = req.i18n.t
|
if (!req.t) req.t = req.i18n.t
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req)
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req)
|
||||||
|
|
||||||
return resetPassword({
|
return resetPasswordOperation({
|
||||||
collection,
|
collection,
|
||||||
data,
|
data,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { getDataLoader } from '../../../collections/dataloader'
|
|||||||
import { APIError } from '../../../errors'
|
import { APIError } from '../../../errors'
|
||||||
import { i18nInit } from '../../../translations/init'
|
import { i18nInit } from '../../../translations/init'
|
||||||
import { setRequestContext } from '../../../utilities/setRequestContext'
|
import { setRequestContext } from '../../../utilities/setRequestContext'
|
||||||
import unlock from '../unlock'
|
import { unlockOperation } from '../unlock'
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -46,7 +46,7 @@ async function localUnlock<T extends keyof GeneratedTypes['collections']>(
|
|||||||
if (!req.t) req.t = req.i18n.t
|
if (!req.t) req.t = req.i18n.t
|
||||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req)
|
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req)
|
||||||
|
|
||||||
return unlock({
|
return unlockOperation({
|
||||||
collection,
|
collection,
|
||||||
data,
|
data,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import type { PayloadRequest } from '../../../types'
|
|||||||
import { APIError } from '../../../errors'
|
import { APIError } from '../../../errors'
|
||||||
import { i18nInit } from '../../../translations/init'
|
import { i18nInit } from '../../../translations/init'
|
||||||
import { setRequestContext } from '../../../utilities/setRequestContext'
|
import { setRequestContext } from '../../../utilities/setRequestContext'
|
||||||
import verifyEmail from '../verifyEmail'
|
import { verifyEmailOperation } from '../verifyEmail'
|
||||||
|
|
||||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||||
collection: T
|
collection: T
|
||||||
@@ -33,7 +33,7 @@ async function localVerifyEmail<T extends keyof GeneratedTypes['collections']>(
|
|||||||
req.payloadAPI = req.payloadAPI || 'local'
|
req.payloadAPI = req.payloadAPI || 'local'
|
||||||
req.i18n = i18nInit(payload.config.i18n)
|
req.i18n = i18nInit(payload.config.i18n)
|
||||||
|
|
||||||
return verifyEmail({
|
return verifyEmailOperation({
|
||||||
collection,
|
collection,
|
||||||
req,
|
req,
|
||||||
token,
|
token,
|
||||||
|
|||||||
@@ -9,16 +9,14 @@ import { buildAfterOperation } from '../../collections/operations/utils'
|
|||||||
import { AuthenticationError, LockedAuth } from '../../errors'
|
import { AuthenticationError, LockedAuth } from '../../errors'
|
||||||
import { afterRead } from '../../fields/hooks/afterRead'
|
import { afterRead } from '../../fields/hooks/afterRead'
|
||||||
import { commitTransaction } from '../../utilities/commitTransaction'
|
import { commitTransaction } from '../../utilities/commitTransaction'
|
||||||
import { generateCookie } from '../../utilities/cookies'
|
|
||||||
import getCookieExpiration from '../../utilities/getCookieExpiration'
|
|
||||||
import { initTransaction } from '../../utilities/initTransaction'
|
import { initTransaction } from '../../utilities/initTransaction'
|
||||||
import { killTransaction } from '../../utilities/killTransaction'
|
import { killTransaction } from '../../utilities/killTransaction'
|
||||||
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields'
|
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields'
|
||||||
|
import { getFieldsToSign } from '../getFieldsToSign'
|
||||||
import isLocked from '../isLocked'
|
import isLocked from '../isLocked'
|
||||||
import { authenticateLocalStrategy } from '../strategies/local/authenticate'
|
import { authenticateLocalStrategy } from '../strategies/local/authenticate'
|
||||||
import { incrementLoginAttempts } from '../strategies/local/incrementLoginAttempts'
|
import { incrementLoginAttempts } from '../strategies/local/incrementLoginAttempts'
|
||||||
import { getFieldsToSign } from './getFieldsToSign'
|
import { unlockOperation } from './unlock'
|
||||||
import unlock from './unlock'
|
|
||||||
|
|
||||||
export type Result = {
|
export type Result = {
|
||||||
exp?: number
|
exp?: number
|
||||||
@@ -35,15 +33,12 @@ export type Arguments = {
|
|||||||
depth?: number
|
depth?: number
|
||||||
overrideAccess?: boolean
|
overrideAccess?: boolean
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
responseOptions?: ResponseInit & {
|
|
||||||
headers: Headers
|
|
||||||
}
|
|
||||||
showHiddenFields?: boolean
|
showHiddenFields?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
export const loginOperation = async <TSlug extends keyof GeneratedTypes['collections']>(
|
||||||
incomingArgs: Arguments,
|
incomingArgs: Arguments,
|
||||||
): Promise<Result & { user: GeneratedTypes['collections'][TSlug] }> {
|
): Promise<Result & { user: GeneratedTypes['collections'][TSlug] }> => {
|
||||||
let args = incomingArgs
|
let args = incomingArgs
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -70,7 +65,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
req,
|
req,
|
||||||
req: {
|
req: {
|
||||||
payload,
|
payload,
|
||||||
payload: { config, secret },
|
payload: { secret },
|
||||||
},
|
},
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
} = args
|
} = args
|
||||||
@@ -120,7 +115,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (maxLoginAttemptsEnabled) {
|
if (maxLoginAttemptsEnabled) {
|
||||||
await unlock({
|
await unlockOperation({
|
||||||
collection: {
|
collection: {
|
||||||
config: collectionConfig,
|
config: collectionConfig,
|
||||||
},
|
},
|
||||||
@@ -152,28 +147,6 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
expiresIn: collectionConfig.auth.tokenExpiration,
|
expiresIn: collectionConfig.auth.tokenExpiration,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (args.responseOptions) {
|
|
||||||
const sameSite =
|
|
||||||
typeof collectionConfig.auth.cookies.sameSite === 'string'
|
|
||||||
? collectionConfig.auth.cookies.sameSite
|
|
||||||
: collectionConfig.auth.cookies.sameSite
|
|
||||||
? 'Strict'
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const cookie = generateCookie({
|
|
||||||
name: `${config.cookiePrefix}-token`,
|
|
||||||
domain: collectionConfig.auth.cookies.domain ?? undefined,
|
|
||||||
expires: getCookieExpiration(collectionConfig.auth.tokenExpiration),
|
|
||||||
httpOnly: true,
|
|
||||||
path: '/',
|
|
||||||
sameSite,
|
|
||||||
secure: collectionConfig.auth.cookies.secure,
|
|
||||||
value: token,
|
|
||||||
})
|
|
||||||
|
|
||||||
args.responseOptions.headers.set('Set-Cookie', cookie)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.user = user
|
req.user = user
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -273,5 +246,3 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default login
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// TODO(JARROD): remove express Response
|
|
||||||
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'
|
||||||
@@ -11,37 +8,20 @@ import { APIError } from '../../errors'
|
|||||||
export type Arguments = {
|
export type Arguments = {
|
||||||
collection: Collection
|
collection: Collection
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
res: Response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function logout(incomingArgs: Arguments): Promise<string> {
|
export const logoutOperation = async (incomingArgs: Arguments): Promise<boolean> => {
|
||||||
let args = incomingArgs
|
let args = incomingArgs
|
||||||
const {
|
const {
|
||||||
collection,
|
|
||||||
collection: { config: collectionConfig },
|
collection: { config: collectionConfig },
|
||||||
|
req: { collection, user },
|
||||||
req,
|
req,
|
||||||
req: {
|
|
||||||
payload: { config },
|
|
||||||
user,
|
|
||||||
},
|
|
||||||
res,
|
|
||||||
} = incomingArgs
|
} = incomingArgs
|
||||||
|
|
||||||
if (!user) throw new APIError('No User', httpStatus.BAD_REQUEST)
|
if (!user) throw new APIError('No User', httpStatus.BAD_REQUEST)
|
||||||
if (user.collection !== collectionConfig.slug)
|
if (user.collection !== collectionConfig.slug)
|
||||||
throw new APIError('Incorrect collection', httpStatus.FORBIDDEN)
|
throw new APIError('Incorrect collection', httpStatus.FORBIDDEN)
|
||||||
|
|
||||||
const cookieOptions = {
|
|
||||||
domain: undefined,
|
|
||||||
httpOnly: true,
|
|
||||||
path: '/',
|
|
||||||
sameSite: collectionConfig.auth.cookies.sameSite,
|
|
||||||
secure: collectionConfig.auth.cookies.secure,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionConfig.auth.cookies.domain)
|
|
||||||
cookieOptions.domain = collectionConfig.auth.cookies.domain
|
|
||||||
|
|
||||||
await collection.config.hooks.afterLogout.reduce(async (priorHook, hook) => {
|
await collection.config.hooks.afterLogout.reduce(async (priorHook, hook) => {
|
||||||
await priorHook
|
await priorHook
|
||||||
|
|
||||||
@@ -50,13 +30,8 @@ async function logout(incomingArgs: Arguments): Promise<string> {
|
|||||||
collection: args.collection?.config,
|
collection: args.collection?.config,
|
||||||
context: req.context,
|
context: req.context,
|
||||||
req,
|
req,
|
||||||
res,
|
|
||||||
})) || args
|
})) || args
|
||||||
}, Promise.resolve())
|
}, Promise.resolve())
|
||||||
|
|
||||||
res.clearCookie(`${config.cookiePrefix}-token`, cookieOptions)
|
return true
|
||||||
|
|
||||||
return req.t('authentication:loggedOutSuccessfully')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default logout
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import type { Collection } from '../../collections/config/types'
|
|||||||
import type { PayloadRequest } from '../../types'
|
import type { PayloadRequest } from '../../types'
|
||||||
import type { User } from '../types'
|
import type { User } from '../types'
|
||||||
|
|
||||||
import { extractJWT } from '../getExtractJWT'
|
|
||||||
|
|
||||||
export type Result = {
|
export type Result = {
|
||||||
collection?: string
|
collection?: string
|
||||||
exp?: number
|
exp?: number
|
||||||
@@ -16,11 +14,16 @@ export type Result = {
|
|||||||
|
|
||||||
export type Arguments = {
|
export type Arguments = {
|
||||||
collection: Collection
|
collection: Collection
|
||||||
|
currentToken?: string
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
async function me({ collection, req }: Arguments): Promise<Result> {
|
export const meOperation = async ({
|
||||||
let response: Result = {
|
collection,
|
||||||
|
currentToken,
|
||||||
|
req,
|
||||||
|
}: Arguments): Promise<Result> => {
|
||||||
|
let result: Result = {
|
||||||
user: null,
|
user: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,17 +48,15 @@ async function me({ collection, req }: Arguments): Promise<Result> {
|
|||||||
|
|
||||||
delete user.collection
|
delete user.collection
|
||||||
|
|
||||||
response = {
|
result = {
|
||||||
collection: req.user.collection,
|
collection: req.user.collection,
|
||||||
user,
|
user,
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = extractJWT(req)
|
if (currentToken) {
|
||||||
|
const decoded = jwt.decode(currentToken) as jwt.JwtPayload
|
||||||
if (token) {
|
if (decoded) result.exp = decoded.exp
|
||||||
const decoded = jwt.decode(token) as jwt.JwtPayload
|
if (!collection.config.auth.removeTokenFromResponses) result.token = currentToken
|
||||||
if (decoded) response.exp = decoded.exp
|
|
||||||
if (!collection.config.auth.removeTokenFromResponses) response.token = token
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,16 +67,14 @@ async function me({ collection, req }: Arguments): Promise<Result> {
|
|||||||
await collection.config.hooks.afterMe.reduce(async (priorHook, hook) => {
|
await collection.config.hooks.afterMe.reduce(async (priorHook, hook) => {
|
||||||
await priorHook
|
await priorHook
|
||||||
|
|
||||||
response =
|
result =
|
||||||
(await hook({
|
(await hook({
|
||||||
collection: collection?.config,
|
collection: collection?.config,
|
||||||
context: req.context,
|
context: req.context,
|
||||||
req,
|
req,
|
||||||
response,
|
response: result,
|
||||||
})) || response
|
})) || result
|
||||||
}, Promise.resolve())
|
}, Promise.resolve())
|
||||||
|
|
||||||
return response
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export default me
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// TODO(JARROD): remove express Response
|
|
||||||
import type { Response } from 'express'
|
|
||||||
|
|
||||||
import jwt from 'jsonwebtoken'
|
import jwt from 'jsonwebtoken'
|
||||||
import url from 'url'
|
import url from 'url'
|
||||||
|
|
||||||
@@ -10,8 +7,7 @@ import type { Document } from '../../types'
|
|||||||
|
|
||||||
import { buildAfterOperation } from '../../collections/operations/utils'
|
import { buildAfterOperation } from '../../collections/operations/utils'
|
||||||
import { Forbidden } from '../../errors'
|
import { Forbidden } from '../../errors'
|
||||||
import getCookieExpiration from '../../utilities/getCookieExpiration'
|
import { getFieldsToSign } from '../getFieldsToSign'
|
||||||
import { getFieldsToSign } from './getFieldsToSign'
|
|
||||||
|
|
||||||
export type Result = {
|
export type Result = {
|
||||||
exp: number
|
exp: number
|
||||||
@@ -22,11 +18,10 @@ export type Result = {
|
|||||||
export type Arguments = {
|
export type Arguments = {
|
||||||
collection: Collection
|
collection: Collection
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
res?: Response
|
|
||||||
token: string
|
token: string
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refresh(incomingArgs: Arguments): Promise<Result> {
|
export const refreshOperation = async (incomingArgs: Arguments): Promise<Result> => {
|
||||||
let args = incomingArgs
|
let args = incomingArgs
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -83,22 +78,6 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
|||||||
|
|
||||||
const exp = (jwt.decode(refreshedToken) as Record<string, unknown>).exp as number
|
const exp = (jwt.decode(refreshedToken) as Record<string, unknown>).exp as number
|
||||||
|
|
||||||
if (args.res) {
|
|
||||||
const cookieOptions = {
|
|
||||||
domain: undefined,
|
|
||||||
expires: getCookieExpiration(collectionConfig.auth.tokenExpiration),
|
|
||||||
httpOnly: true,
|
|
||||||
path: '/',
|
|
||||||
sameSite: collectionConfig.auth.cookies.sameSite,
|
|
||||||
secure: collectionConfig.auth.cookies.secure,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionConfig.auth.cookies.domain)
|
|
||||||
cookieOptions.domain = collectionConfig.auth.cookies.domain
|
|
||||||
|
|
||||||
args.res.cookie(`${config.cookiePrefix}-token`, refreshedToken, cookieOptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
let result: Result = {
|
let result: Result = {
|
||||||
exp,
|
exp,
|
||||||
refreshedToken,
|
refreshedToken,
|
||||||
@@ -118,7 +97,6 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
|||||||
context: args.req.context,
|
context: args.req.context,
|
||||||
exp,
|
exp,
|
||||||
req: args.req,
|
req: args.req,
|
||||||
res: args.res,
|
|
||||||
token: refreshedToken,
|
token: refreshedToken,
|
||||||
})) || result
|
})) || result
|
||||||
}, Promise.resolve())
|
}, Promise.resolve())
|
||||||
@@ -144,5 +122,3 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export default refresh
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// TODO(JARROD): remove express Response
|
|
||||||
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 '../../'
|
||||||
@@ -18,18 +16,17 @@ 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Result<T> = {
|
export type Result<T> = {
|
||||||
message: string
|
exp?: number
|
||||||
user: T
|
token?: string
|
||||||
|
user?: T
|
||||||
}
|
}
|
||||||
|
|
||||||
async function registerFirstUser<TSlug extends keyof GeneratedTypes['collections']>(
|
export const registerFirstUserOperation = async <TSlug extends keyof GeneratedTypes['collections']>(
|
||||||
args: Arguments<GeneratedTypes['collections'][TSlug]>,
|
args: Arguments<GeneratedTypes['collections'][TSlug]>,
|
||||||
): Promise<Result<GeneratedTypes['collections'][TSlug]>> {
|
): Promise<Result<GeneratedTypes['collections'][TSlug]>> => {
|
||||||
const {
|
const {
|
||||||
collection: {
|
collection: {
|
||||||
config,
|
config,
|
||||||
@@ -80,27 +77,21 @@ async function registerFirstUser<TSlug extends keyof GeneratedTypes['collections
|
|||||||
// Log in new user
|
// Log in new user
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const { token } = await payload.login({
|
const { exp, token } = await payload.login({
|
||||||
...args,
|
...args,
|
||||||
collection: slug,
|
collection: slug,
|
||||||
req,
|
req,
|
||||||
})
|
})
|
||||||
|
|
||||||
const resultToReturn = {
|
|
||||||
...result,
|
|
||||||
token,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldCommit) await commitTransaction(req)
|
if (shouldCommit) await commitTransaction(req)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: 'Registered and logged in successfully. Welcome!',
|
exp,
|
||||||
user: resultToReturn,
|
token,
|
||||||
|
user: result,
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
await killTransaction(req)
|
await killTransaction(req)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default registerFirstUser
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// TODO(JARROD): remove express Response
|
|
||||||
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'
|
||||||
@@ -8,12 +5,11 @@ import type { PayloadRequest } from '../../types'
|
|||||||
|
|
||||||
import { APIError } from '../../errors'
|
import { APIError } from '../../errors'
|
||||||
import { commitTransaction } from '../../utilities/commitTransaction'
|
import { commitTransaction } from '../../utilities/commitTransaction'
|
||||||
import getCookieExpiration from '../../utilities/getCookieExpiration'
|
|
||||||
import { initTransaction } from '../../utilities/initTransaction'
|
import { initTransaction } from '../../utilities/initTransaction'
|
||||||
import { killTransaction } from '../../utilities/killTransaction'
|
import { killTransaction } from '../../utilities/killTransaction'
|
||||||
|
import { getFieldsToSign } from '../getFieldsToSign'
|
||||||
import { authenticateLocalStrategy } from '../strategies/local/authenticate'
|
import { authenticateLocalStrategy } from '../strategies/local/authenticate'
|
||||||
import { generatePasswordSaltHash } from '../strategies/local/generatePasswordSaltHash'
|
import { generatePasswordSaltHash } from '../strategies/local/generatePasswordSaltHash'
|
||||||
import { getFieldsToSign } from './getFieldsToSign'
|
|
||||||
|
|
||||||
export type Result = {
|
export type Result = {
|
||||||
token?: string
|
token?: string
|
||||||
@@ -29,11 +25,9 @@ export type Arguments = {
|
|||||||
depth?: number
|
depth?: number
|
||||||
overrideAccess?: boolean
|
overrideAccess?: boolean
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
// TODO(JARROD): remove express Response
|
|
||||||
res?: Response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resetPassword(args: Arguments): Promise<Result> {
|
export const resetPasswordOperation = async (args: Arguments): Promise<Result> => {
|
||||||
if (
|
if (
|
||||||
!Object.prototype.hasOwnProperty.call(args.data, 'token') ||
|
!Object.prototype.hasOwnProperty.call(args.data, 'token') ||
|
||||||
!Object.prototype.hasOwnProperty.call(args.data, 'password')
|
!Object.prototype.hasOwnProperty.call(args.data, 'password')
|
||||||
@@ -47,7 +41,7 @@ async function resetPassword(args: Arguments): Promise<Result> {
|
|||||||
depth,
|
depth,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req: {
|
req: {
|
||||||
payload: { config, secret },
|
payload: { secret },
|
||||||
payload,
|
payload,
|
||||||
},
|
},
|
||||||
req,
|
req,
|
||||||
@@ -102,22 +96,6 @@ async function resetPassword(args: Arguments): Promise<Result> {
|
|||||||
expiresIn: collectionConfig.auth.tokenExpiration,
|
expiresIn: collectionConfig.auth.tokenExpiration,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (args.res) {
|
|
||||||
const cookieOptions = {
|
|
||||||
domain: undefined,
|
|
||||||
expires: getCookieExpiration(collectionConfig.auth.tokenExpiration),
|
|
||||||
httpOnly: true,
|
|
||||||
path: '/',
|
|
||||||
sameSite: collectionConfig.auth.cookies.sameSite,
|
|
||||||
secure: collectionConfig.auth.cookies.secure,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionConfig.auth.cookies.domain)
|
|
||||||
cookieOptions.domain = collectionConfig.auth.cookies.domain
|
|
||||||
|
|
||||||
args.res.cookie(`${config.cookiePrefix}-token`, token, cookieOptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
const fullUser = await payload.findByID({
|
const fullUser = await payload.findByID({
|
||||||
id: user.id,
|
id: user.id,
|
||||||
collection: collectionConfig.slug,
|
collection: collectionConfig.slug,
|
||||||
@@ -137,4 +115,4 @@ async function resetPassword(args: Arguments): Promise<Result> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default resetPassword
|
export default resetPasswordOperation
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export type Args = {
|
|||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unlock(args: Args): Promise<boolean> {
|
export const unlockOperation = async (args: Args): Promise<boolean> => {
|
||||||
if (!Object.prototype.hasOwnProperty.call(args.data, 'email')) {
|
if (!Object.prototype.hasOwnProperty.call(args.data, 'email')) {
|
||||||
throw new APIError('Missing email.')
|
throw new APIError('Missing email.')
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ async function unlock(args: Args): Promise<boolean> {
|
|||||||
const {
|
const {
|
||||||
collection: { config: collectionConfig },
|
collection: { config: collectionConfig },
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req: { locale, payload },
|
req: { locale },
|
||||||
req,
|
req,
|
||||||
} = args
|
} = args
|
||||||
|
|
||||||
@@ -82,4 +82,4 @@ async function unlock(args: Args): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default unlock
|
export default unlockOperation
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export type Args = {
|
|||||||
token: string
|
token: string
|
||||||
}
|
}
|
||||||
|
|
||||||
async function verifyEmail(args: Args): Promise<boolean> {
|
export const verifyEmailOperation = async (args: Args): Promise<boolean> => {
|
||||||
const { collection, req, token } = args
|
const { collection, req, token } = args
|
||||||
if (!Object.prototype.hasOwnProperty.call(args, 'token')) {
|
if (!Object.prototype.hasOwnProperty.call(args, 'token')) {
|
||||||
throw new APIError('Missing required data.', httpStatus.BAD_REQUEST)
|
throw new APIError('Missing required data.', httpStatus.BAD_REQUEST)
|
||||||
@@ -55,4 +55,4 @@ async function verifyEmail(args: Args): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default verifyEmail
|
export default verifyEmailOperation
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import type { NextFunction, Request, Response } from 'express'
|
|
||||||
|
|
||||||
import type { Collection } from './config/types'
|
|
||||||
|
|
||||||
const bindCollectionMiddleware =
|
|
||||||
(collection: Collection) =>
|
|
||||||
(req: Request & { collection: Collection }, res: Response, next: NextFunction): void => {
|
|
||||||
req.collection = collection
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
|
|
||||||
export default bindCollectionMiddleware
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
import type { Endpoint } from '../config/types'
|
|
||||||
import type { SanitizedCollectionConfig } from './config/types'
|
|
||||||
|
|
||||||
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'
|
|
||||||
import docAccessRequestHandler from './requestHandlers/docAccess'
|
|
||||||
import find from './requestHandlers/find'
|
|
||||||
import findByID from './requestHandlers/findByID'
|
|
||||||
import findVersionByID from './requestHandlers/findVersionByID'
|
|
||||||
import findVersions from './requestHandlers/findVersions'
|
|
||||||
import restoreVersion from './requestHandlers/restoreVersion'
|
|
||||||
import update from './requestHandlers/update'
|
|
||||||
import updateByID, { deprecatedUpdate } from './requestHandlers/updateByID'
|
|
||||||
|
|
||||||
const buildEndpoints = (collection: SanitizedCollectionConfig): Endpoint[] => {
|
|
||||||
if (!collection.endpoints) return []
|
|
||||||
const endpoints = [...collection.endpoints]
|
|
||||||
|
|
||||||
if (collection.auth) {
|
|
||||||
if (!collection.auth.disableLocalStrategy) {
|
|
||||||
if (collection.auth.verify) {
|
|
||||||
endpoints.push({
|
|
||||||
handler: verifyEmail,
|
|
||||||
method: 'post',
|
|
||||||
path: '/verify/:token',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collection.auth.maxLoginAttempts > 0) {
|
|
||||||
endpoints.push({
|
|
||||||
handler: unlock,
|
|
||||||
method: 'post',
|
|
||||||
path: '/unlock',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoints.push(
|
|
||||||
{
|
|
||||||
handler: loginHandler,
|
|
||||||
method: 'post',
|
|
||||||
path: '/login',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: registerFirstUserHandler,
|
|
||||||
method: 'post',
|
|
||||||
path: '/first-register',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: forgotPasswordHandler,
|
|
||||||
method: 'post',
|
|
||||||
path: '/forgot-password',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: resetPassword,
|
|
||||||
method: 'post',
|
|
||||||
path: '/reset-password',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoints.push(
|
|
||||||
{
|
|
||||||
handler: initHandler,
|
|
||||||
method: 'get',
|
|
||||||
path: '/init',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: meHandler,
|
|
||||||
method: 'get',
|
|
||||||
path: '/me',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: logoutHandler,
|
|
||||||
method: 'post',
|
|
||||||
path: '/logout',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: refreshHandler,
|
|
||||||
method: 'post',
|
|
||||||
path: '/refresh-token',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collection.versions) {
|
|
||||||
endpoints.push(
|
|
||||||
{
|
|
||||||
handler: findVersions,
|
|
||||||
method: 'get',
|
|
||||||
path: '/versions',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: findVersionByID,
|
|
||||||
method: 'get',
|
|
||||||
path: '/versions/:id',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: restoreVersion,
|
|
||||||
method: 'post',
|
|
||||||
path: '/versions/:id',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoints.push(
|
|
||||||
{
|
|
||||||
handler: find,
|
|
||||||
method: 'get',
|
|
||||||
path: '/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: create,
|
|
||||||
method: 'post',
|
|
||||||
path: '/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: docAccessRequestHandler,
|
|
||||||
method: 'get',
|
|
||||||
path: '/access/:id',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: docAccessRequestHandler,
|
|
||||||
method: 'post',
|
|
||||||
path: '/access/:id',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: docAccessRequestHandler,
|
|
||||||
method: 'post',
|
|
||||||
path: '/access',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: deprecatedUpdate,
|
|
||||||
method: 'put',
|
|
||||||
path: '/:id',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: update,
|
|
||||||
method: 'patch',
|
|
||||||
path: '/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: updateByID,
|
|
||||||
method: 'patch',
|
|
||||||
path: '/:id',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: findByID,
|
|
||||||
method: 'get',
|
|
||||||
path: '/:id',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: deleteByID,
|
|
||||||
method: 'delete',
|
|
||||||
path: '/:id',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
handler: deleteHandler,
|
|
||||||
method: 'delete',
|
|
||||||
path: '/',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return endpoints
|
|
||||||
}
|
|
||||||
|
|
||||||
export default buildEndpoints
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
import type { Response } from 'express'
|
|
||||||
import type { GraphQLInputObjectType, GraphQLNonNull, GraphQLObjectType } from 'graphql'
|
import type { GraphQLInputObjectType, GraphQLNonNull, GraphQLObjectType } from 'graphql'
|
||||||
import type { DeepRequired } from 'ts-essentials'
|
import type { DeepRequired } from 'ts-essentials'
|
||||||
|
|
||||||
@@ -169,7 +167,6 @@ export type AfterLogoutHook<T extends TypeWithID = any> = (args: {
|
|||||||
collection: SanitizedCollectionConfig
|
collection: SanitizedCollectionConfig
|
||||||
context: RequestContext
|
context: RequestContext
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
res: Response
|
|
||||||
}) => any
|
}) => any
|
||||||
|
|
||||||
export type AfterMeHook<T extends TypeWithID = any> = (args: {
|
export type AfterMeHook<T extends TypeWithID = any> = (args: {
|
||||||
@@ -186,7 +183,6 @@ export type AfterRefreshHook<T extends TypeWithID = any> = (args: {
|
|||||||
context: RequestContext
|
context: RequestContext
|
||||||
exp: number
|
exp: number
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
res: Response
|
|
||||||
token: string
|
token: string
|
||||||
}) => any
|
}) => any
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import {
|
|||||||
GraphQLString,
|
GraphQLString,
|
||||||
} from 'graphql'
|
} from 'graphql'
|
||||||
|
|
||||||
|
import type { PayloadT } from '../..'
|
||||||
import type { Field } from '../../fields/config/types'
|
import type { Field } from '../../fields/config/types'
|
||||||
import type { ObjectTypeConfig } from '../../graphql/schema/buildObjectType'
|
import type { ObjectTypeConfig } from '../../graphql/schema/buildObjectType'
|
||||||
import type { Payload } from '../../payload'
|
|
||||||
import type { Collection, SanitizedCollectionConfig } from '../config/types'
|
import type { Collection, SanitizedCollectionConfig } from '../config/types'
|
||||||
|
|
||||||
import forgotPassword from '../../auth/graphql/resolvers/forgotPassword'
|
import forgotPassword from '../../auth/graphql/resolvers/forgotPassword'
|
||||||
@@ -42,7 +42,7 @@ import findVersionsResolver from './resolvers/findVersions'
|
|||||||
import restoreVersionResolver from './resolvers/restoreVersion'
|
import restoreVersionResolver from './resolvers/restoreVersion'
|
||||||
import updateResolver from './resolvers/update'
|
import updateResolver from './resolvers/update'
|
||||||
|
|
||||||
function initCollectionsGraphQL(payload: Payload): void {
|
function initCollectionsGraphQL(payload: PayloadT): void {
|
||||||
Object.keys(payload.collections).forEach((slug) => {
|
Object.keys(payload.collections).forEach((slug) => {
|
||||||
const collection: Collection = payload.collections[slug]
|
const collection: Collection = payload.collections[slug]
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ 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'
|
||||||
import create from '../../operations/create'
|
import { createOperation } from '../../operations/create'
|
||||||
|
|
||||||
export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
|
export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
@@ -21,7 +21,6 @@ export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
|
|||||||
},
|
},
|
||||||
context: {
|
context: {
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
res: Response
|
|
||||||
},
|
},
|
||||||
) => Promise<GeneratedTypes['collections'][TSlug]>
|
) => Promise<GeneratedTypes['collections'][TSlug]>
|
||||||
|
|
||||||
@@ -41,7 +40,7 @@ export default function createResolver<TSlug extends keyof GeneratedTypes['colle
|
|||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await create(options)
|
const result = await createOperation(options)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ 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'
|
||||||
import deleteByID from '../../operations/deleteByID'
|
import { deleteByIDOperation } from '../../operations/deleteByID'
|
||||||
|
|
||||||
export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
|
export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
@@ -34,7 +34,7 @@ export default function getDeleteResolver<TSlug extends keyof GeneratedTypes['co
|
|||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await deleteByID(options)
|
const result = await deleteByIDOperation(options)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { CollectionPermission, GlobalPermission } from '../../../auth'
|
|||||||
import type { PayloadRequest } from '../../../types'
|
import type { PayloadRequest } from '../../../types'
|
||||||
|
|
||||||
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
||||||
import { docAccess } from '../../operations/docAccess'
|
import { docAccessOperation } from '../../operations/docAccess'
|
||||||
|
|
||||||
export type Resolver = (
|
export type Resolver = (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
@@ -17,7 +17,7 @@ export type Resolver = (
|
|||||||
|
|
||||||
export function docAccessResolver(): Resolver {
|
export function docAccessResolver(): Resolver {
|
||||||
async function resolver(_, args, context) {
|
async function resolver(_, args, context) {
|
||||||
return docAccess({
|
return docAccessOperation({
|
||||||
id: args.id,
|
id: args.id,
|
||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import type { Where } from '../../../types'
|
|||||||
import type { Collection } from '../../config/types'
|
import type { Collection } from '../../config/types'
|
||||||
|
|
||||||
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
||||||
import find from '../../operations/find'
|
import { findOperation } from '../../operations/find'
|
||||||
|
|
||||||
export type Resolver = (
|
export type Resolver = (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
@@ -42,7 +42,7 @@ export default function findResolver(collection: Collection): Resolver {
|
|||||||
where: args.where,
|
where: args.where,
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await find(options)
|
const results = await findOperation(options)
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ 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'
|
||||||
import findByID from '../../operations/findByID'
|
import { findByIDOperation } from '../../operations/findByID'
|
||||||
|
|
||||||
export type Resolver<T> = (
|
export type Resolver<T> = (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
@@ -35,7 +35,7 @@ export default function findByIDResolver<T extends keyof GeneratedTypes['collect
|
|||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await findByID(options)
|
const result = await findByIDOperation(options)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { TypeWithVersion } from '../../../versions/types'
|
|||||||
import type { Collection, TypeWithID } from '../../config/types'
|
import type { Collection, TypeWithID } from '../../config/types'
|
||||||
|
|
||||||
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
||||||
import findVersionByID from '../../operations/findVersionByID'
|
import { findVersionByIDOperation } from '../../operations/findVersionByID'
|
||||||
|
|
||||||
export type Resolver<T extends TypeWithID = any> = (
|
export type Resolver<T extends TypeWithID = any> = (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
@@ -35,7 +35,7 @@ export default function findVersionByIDResolver(collection: Collection): Resolve
|
|||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await findVersionByID(options)
|
const result = await findVersionByIDOperation(options)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import type { Where } from '../../../types'
|
|||||||
import type { Collection } from '../../config/types'
|
import type { Collection } from '../../config/types'
|
||||||
|
|
||||||
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
import isolateTransactionID from '../../../utilities/isolateTransactionID'
|
||||||
import findVersions from '../../operations/findVersions'
|
import { findVersionsOperation } from '../../operations/findVersions'
|
||||||
|
|
||||||
export type Resolver = (
|
export type Resolver = (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
@@ -41,7 +41,7 @@ export default function findVersionsResolver(collection: Collection): Resolver {
|
|||||||
where: args.where,
|
where: args.where,
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await findVersions(options)
|
const result = await findVersionsOperation(options)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ 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'
|
||||||
import restoreVersion from '../../operations/restoreVersion'
|
import { restoreVersionOperation } from '../../operations/restoreVersion'
|
||||||
|
|
||||||
export type Resolver = (
|
export type Resolver = (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
@@ -27,7 +27,7 @@ export default function restoreVersionResolver(collection: Collection): Resolver
|
|||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await restoreVersion(options)
|
const result = await restoreVersionOperation(options)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ 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'
|
||||||
import updateByID from '../../operations/updateByID'
|
import { updateByIDOperation } from '../../operations/updateByID'
|
||||||
|
|
||||||
export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
|
export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
@@ -40,7 +40,7 @@ export default function updateResolver<TSlug extends keyof GeneratedTypes['colle
|
|||||||
req: isolateTransactionID(context.req),
|
req: isolateTransactionID(context.req),
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await updateByID<TSlug>(options)
|
const result = await updateByIDOperation<TSlug>(options)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
import express from 'express'
|
|
||||||
import passport from 'passport'
|
|
||||||
|
|
||||||
import type { Payload } from '../payload'
|
|
||||||
import type { SanitizedCollectionConfig } from './config/types'
|
|
||||||
|
|
||||||
import apiKeyStrategy from '../auth/strategies/apiKey'
|
|
||||||
import mountEndpoints from '../express/mountEndpoints'
|
|
||||||
import bindCollectionMiddleware from './bindCollection'
|
|
||||||
import buildEndpoints from './buildEndpoints'
|
|
||||||
|
|
||||||
export default function initCollectionsHTTP(ctx: Payload): void {
|
|
||||||
ctx.config.collections = ctx.config.collections.map((collection: SanitizedCollectionConfig) => {
|
|
||||||
const formattedCollection = collection
|
|
||||||
|
|
||||||
const router = express.Router()
|
|
||||||
const { slug } = collection
|
|
||||||
|
|
||||||
router.all('*', bindCollectionMiddleware(ctx.collections[formattedCollection.slug]))
|
|
||||||
|
|
||||||
if (collection.auth) {
|
|
||||||
const { config } = ctx.collections[formattedCollection.slug]
|
|
||||||
|
|
||||||
if (collection.auth.useAPIKey) {
|
|
||||||
passport.use(`${config.slug}-api-key`, apiKeyStrategy(ctx, config))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(collection.auth.strategies)) {
|
|
||||||
collection.auth.strategies.forEach(({ name, strategy }, index) => {
|
|
||||||
const passportStrategy = typeof strategy === 'object' ? strategy : strategy(ctx)
|
|
||||||
passport.use(`${config.slug}-${name ?? index}`, passportStrategy)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const endpoints = buildEndpoints(collection)
|
|
||||||
mountEndpoints(ctx.express, router, endpoints)
|
|
||||||
|
|
||||||
ctx.router.use(`/${slug}`, router)
|
|
||||||
|
|
||||||
return formattedCollection
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user