Compare commits

...

1 Commits

Author SHA1 Message Date
James
f7e036e1b8 chore: adds ops counter test to graphql 2025-03-12 11:42:33 -04:00
7 changed files with 319 additions and 111 deletions

View File

@@ -6,65 +6,10 @@
* and re-run `payload generate:types` to regenerate this file.
*/
/**
* Supported timezones in IANA format.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "supportedTimezones".
*/
export type SupportedTimezones =
| 'Pacific/Midway'
| 'Pacific/Niue'
| 'Pacific/Honolulu'
| 'Pacific/Rarotonga'
| 'America/Anchorage'
| 'Pacific/Gambier'
| 'America/Los_Angeles'
| 'America/Tijuana'
| 'America/Denver'
| 'America/Phoenix'
| 'America/Chicago'
| 'America/Guatemala'
| 'America/New_York'
| 'America/Bogota'
| 'America/Caracas'
| 'America/Santiago'
| 'America/Buenos_Aires'
| 'America/Sao_Paulo'
| 'Atlantic/South_Georgia'
| 'Atlantic/Azores'
| 'Atlantic/Cape_Verde'
| 'Europe/London'
| 'Europe/Berlin'
| 'Africa/Lagos'
| 'Europe/Athens'
| 'Africa/Cairo'
| 'Europe/Moscow'
| 'Asia/Riyadh'
| 'Asia/Dubai'
| 'Asia/Baku'
| 'Asia/Karachi'
| 'Asia/Tashkent'
| 'Asia/Calcutta'
| 'Asia/Dhaka'
| 'Asia/Almaty'
| 'Asia/Jakarta'
| 'Asia/Bangkok'
| 'Asia/Shanghai'
| 'Asia/Singapore'
| 'Asia/Tokyo'
| 'Asia/Seoul'
| 'Australia/Sydney'
| 'Pacific/Guam'
| 'Pacific/Noumea'
| 'Pacific/Auckland'
| 'Pacific/Fiji';
export interface Config {
auth: {
users: UserAuthOperations;
};
blocks: {};
collections: {
posts: Post;
media: Media;

View File

@@ -4,6 +4,7 @@ import path from 'path'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { devUser } from '../credentials.js'
import { opsCounterPlugin } from './opsCounter.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
@@ -31,6 +32,80 @@ export default buildConfigWithDefaults({
complexity: 801,
},
},
{
name: 'slug',
type: 'text',
},
],
},
{
slug: 'posts-2',
fields: [
{
name: 'title',
label: 'Title',
type: 'text',
},
{
name: 'slug',
type: 'text',
},
],
},
{
slug: 'posts-3',
fields: [
{
name: 'title',
label: 'Title',
type: 'text',
},
{
name: 'slug',
type: 'text',
},
],
},
{
slug: 'posts-4',
fields: [
{
name: 'title',
label: 'Title',
type: 'text',
},
{
name: 'slug',
type: 'text',
},
],
},
{
slug: 'posts-5',
fields: [
{
name: 'title',
label: 'Title',
type: 'text',
},
{
name: 'slug',
type: 'text',
},
],
},
{
slug: 'posts-6',
fields: [
{
name: 'title',
label: 'Title',
type: 'text',
},
{
name: 'slug',
type: 'text',
},
],
},
],
@@ -53,8 +128,14 @@ export default buildConfigWithDefaults({
},
graphQL: {
maxComplexity: 800,
validationRules: () => [NoIntrospection],
// validationRules: () => [NoIntrospection],
},
plugins: [
opsCounterPlugin({
warnAt: 5,
max: 20,
}),
],
})
const NoIntrospection: GraphQL.ValidationRule = (context) => ({

View File

@@ -104,5 +104,51 @@ describe('graphql', () => {
expect(res.hyphenated_name).toStrictEqual('example-hyphenated-name')
})
it('should leverage expected amount of operations per query', async () => {
const query = `query pageTypeBySlug($slug: String!, $draft: Boolean = false) {
Posts(where: { slug: { equals: $slug } }, draft: $draft) {
docs {
id
}
}
Posts2s(where: { slug: { equals: $slug } }, draft: $draft) {
docs {
id
}
}
Posts3s(where: { slug: { equals: $slug } }, draft: $draft) {
docs {
id
}
}
Posts4s(where: { slug: { equals: $slug } }, draft: $draft) {
docs {
id
}
}
Posts5s(where: { slug: { equals: $slug } }, draft: $draft) {
docs {
id
}
}
Posts6s(where: { slug: { equals: $slug } }, draft: $draft) {
docs {
id
}
}
}`
const { data } = await restClient
.GRAPHQL_POST({ body: JSON.stringify({ query, variables: { slug: 'hello' } }) })
.then((res) => res.json())
expect(data.Posts.docs).toBeDefined()
expect(data.Posts2s.docs).toBeDefined()
expect(data.Posts3s.docs).toBeDefined()
expect(data.Posts4s.docs).toBeDefined()
expect(data.Posts5s.docs).toBeDefined()
expect(data.Posts6s.docs).toBeDefined()
})
})
})

View File

@@ -0,0 +1,52 @@
import type { CollectionBeforeOperationHook, Plugin } from 'payload'
import { APIError } from 'payload'
type Args = {
max?: number
warnAt?: number
}
export const opsCounterPlugin =
(args?: Args): Plugin =>
(config) => {
const max = args?.max || 50
const warnAt = args?.warnAt || 10
const beforeOperationHook: CollectionBeforeOperationHook = ({
req,
collection,
operation,
args,
}) => {
const currentCount = req.context.opsCount
if (typeof currentCount === 'number') {
req.context.opsCount = currentCount + 1
if (warnAt && currentCount >= warnAt) {
req.payload.logger.error(
`Detected a ${operation} in the "${collection.slug}" collection which has run ${warnAt} times or more.`,
)
}
if (currentCount > max) {
throw new APIError(`Maximum operations of ${max} detected.`)
}
} else {
req.context.opsCount = 1
}
}
;(config.collections || []).forEach((collection) => {
if (!collection.hooks) {
collection.hooks = {}
}
if (!collection.hooks.beforeOperation) {
collection.hooks.beforeOperation = []
}
collection.hooks.beforeOperation.push(beforeOperationHook)
})
return config
}

View File

@@ -6,66 +6,17 @@
* and re-run `payload generate:types` to regenerate this file.
*/
/**
* Supported timezones in IANA format.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "supportedTimezones".
*/
export type SupportedTimezones =
| 'Pacific/Midway'
| 'Pacific/Niue'
| 'Pacific/Honolulu'
| 'Pacific/Rarotonga'
| 'America/Anchorage'
| 'Pacific/Gambier'
| 'America/Los_Angeles'
| 'America/Tijuana'
| 'America/Denver'
| 'America/Phoenix'
| 'America/Chicago'
| 'America/Guatemala'
| 'America/New_York'
| 'America/Bogota'
| 'America/Caracas'
| 'America/Santiago'
| 'America/Buenos_Aires'
| 'America/Sao_Paulo'
| 'Atlantic/South_Georgia'
| 'Atlantic/Azores'
| 'Atlantic/Cape_Verde'
| 'Europe/London'
| 'Europe/Berlin'
| 'Africa/Lagos'
| 'Europe/Athens'
| 'Africa/Cairo'
| 'Europe/Moscow'
| 'Asia/Riyadh'
| 'Asia/Dubai'
| 'Asia/Baku'
| 'Asia/Karachi'
| 'Asia/Tashkent'
| 'Asia/Calcutta'
| 'Asia/Dhaka'
| 'Asia/Almaty'
| 'Asia/Jakarta'
| 'Asia/Bangkok'
| 'Asia/Shanghai'
| 'Asia/Singapore'
| 'Asia/Tokyo'
| 'Asia/Seoul'
| 'Australia/Sydney'
| 'Pacific/Guam'
| 'Pacific/Noumea'
| 'Pacific/Auckland'
| 'Pacific/Fiji';
export interface Config {
auth: {
users: UserAuthOperations;
};
collections: {
posts: Post;
'posts-2': Posts2;
'posts-3': Posts3;
'posts-4': Posts4;
'posts-5': Posts5;
'posts-6': Posts6;
users: User;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
@@ -74,6 +25,11 @@ export interface Config {
collectionsJoins: {};
collectionsSelect: {
posts: PostsSelect<false> | PostsSelect<true>;
'posts-2': Posts2Select<false> | Posts2Select<true>;
'posts-3': Posts3Select<false> | Posts3Select<true>;
'posts-4': Posts4Select<false> | Posts4Select<true>;
'posts-5': Posts5Select<false> | Posts5Select<true>;
'posts-6': Posts6Select<false> | Posts6Select<true>;
users: UsersSelect<false> | UsersSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
@@ -120,6 +76,62 @@ export interface Post {
title?: string | null;
'hyphenated-name'?: string | null;
relationToSelf?: (string | null) | Post;
slug?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-2".
*/
export interface Posts2 {
id: string;
title?: string | null;
slug?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-3".
*/
export interface Posts3 {
id: string;
title?: string | null;
slug?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-4".
*/
export interface Posts4 {
id: string;
title?: string | null;
slug?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-5".
*/
export interface Posts5 {
id: string;
title?: string | null;
slug?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-6".
*/
export interface Posts6 {
id: string;
title?: string | null;
slug?: string | null;
updatedAt: string;
createdAt: string;
}
@@ -151,6 +163,26 @@ export interface PayloadLockedDocument {
relationTo: 'posts';
value: string | Post;
} | null)
| ({
relationTo: 'posts-2';
value: string | Posts2;
} | null)
| ({
relationTo: 'posts-3';
value: string | Posts3;
} | null)
| ({
relationTo: 'posts-4';
value: string | Posts4;
} | null)
| ({
relationTo: 'posts-5';
value: string | Posts5;
} | null)
| ({
relationTo: 'posts-6';
value: string | Posts6;
} | null)
| ({
relationTo: 'users';
value: string | User;
@@ -205,6 +237,57 @@ export interface PostsSelect<T extends boolean = true> {
title?: T;
'hyphenated-name'?: T;
relationToSelf?: T;
slug?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-2_select".
*/
export interface Posts2Select<T extends boolean = true> {
title?: T;
slug?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-3_select".
*/
export interface Posts3Select<T extends boolean = true> {
title?: T;
slug?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-4_select".
*/
export interface Posts4Select<T extends boolean = true> {
title?: T;
slug?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-5_select".
*/
export interface Posts5Select<T extends boolean = true> {
title?: T;
slug?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts-6_select".
*/
export interface Posts6Select<T extends boolean = true> {
title?: T;
slug?: T;
updatedAt?: T;
createdAt?: T;
}

View File

@@ -53,6 +53,7 @@ export default withBundleAnalyzer(
return webpackConfig
},
serverExternalPackages: ['graphql'],
},
{ devBundleServerPackages: false },
),

View File

@@ -31,7 +31,7 @@
}
],
"paths": {
"@payload-config": ["./test/fields/config.ts"],
"@payload-config": ["./test/graphql/config.ts"],
"@payloadcms/admin-bar": ["./packages/admin-bar/src"],
"@payloadcms/live-preview": ["./packages/live-preview/src"],
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],