diff --git a/docs/fields/join.mdx b/docs/fields/join.mdx index 6939590b75..7c4adedc6c 100644 --- a/docs/fields/join.mdx +++ b/docs/fields/join.mdx @@ -136,6 +136,7 @@ powerful Admin UI. | **`admin`** | Admin-specific configuration. [More details](#admin-config-options). | | **`custom`** | Extension point for adding custom data (e.g. for plugins). | | **`typescriptSchema`** | Override field type generation with providing a JSON schema. | +| **`graphQL`** | Custom graphQL configuration for the field. [More details](/docs/graphql/overview#field-complexity) | _\* An asterisk denotes that a property is required._ diff --git a/docs/fields/relationship.mdx b/docs/fields/relationship.mdx index c6fd2609ca..737f98f438 100644 --- a/docs/fields/relationship.mdx +++ b/docs/fields/relationship.mdx @@ -61,6 +61,7 @@ export const MyRelationshipField: Field = { | **`custom`** | Extension point for adding custom data (e.g. for plugins) | | **`typescriptSchema`** | Override field type generation with providing a JSON schema | | **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) | +| **`graphQL`** | Custom graphQL configuration for the field. [More details](/docs/graphql/overview#field-complexity) | _\* An asterisk denotes that a property is required._ diff --git a/docs/fields/upload.mdx b/docs/fields/upload.mdx index 01dd4bcf53..52246c28d4 100644 --- a/docs/fields/upload.mdx +++ b/docs/fields/upload.mdx @@ -68,6 +68,7 @@ export const MyUploadField: Field = { | **`custom`** | Extension point for adding custom data (e.g. for plugins) | | **`typescriptSchema`** | Override field type generation with providing a JSON schema | | **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) | +| **`graphQL`** | Custom graphQL configuration for the field. [More details](/docs/graphql/overview#field-complexity) | _\* An asterisk denotes that a property is required._ diff --git a/docs/graphql/overview.mdx b/docs/graphql/overview.mdx index 934f547ad9..def1aede52 100644 --- a/docs/graphql/overview.mdx +++ b/docs/graphql/overview.mdx @@ -23,6 +23,7 @@ At the top of your Payload Config you can define all the options to manage Graph | `maxComplexity` | A number used to set the maximum allowed complexity allowed by requests [More](/docs/graphql/overview#query-complexity-limits) | | `disablePlaygroundInProduction` | A boolean that if false will enable the GraphQL playground, defaults to true. [More](/docs/graphql/overview#graphql-playground) | | `disable` | A boolean that if true will disable the GraphQL entirely, defaults to false. | +| `validationRules` | A function that takes the ExecutionArgs and returns an array of ValidationRules. | ## Collections @@ -124,6 +125,55 @@ You can even log in using the `login[collection-singular-label-here]` mutation t see a ton of detail about how GraphQL operates within Payload. +## Custom Validation Rules + +You can add custom validation rules to your GraphQL API by defining a `validationRules` function in your Payload Config. This function should return an array of [Validation Rules](https://graphql.org/graphql-js/validation/#validation-rules) that will be applied to all incoming queries and mutations. + +```ts +import { GraphQL } from '@payloadcms/graphql/types' +import { buildConfig } from 'payload' + +export default buildConfig({ + // ... + graphQL: { + validationRules: (args) => [ + NoProductionIntrospection + ] + }, + // ... +}) + +const NoProductionIntrospection: GraphQL.ValidationRule = (context) => ({ + Field(node) { + if (process.env.NODE_ENV === 'production') { + if (node.name.value === '__schema' || node.name.value === '__type') { + context.reportError( + new GraphQL.GraphQLError( + 'GraphQL introspection is not allowed, but the query contained __schema or __type', + { nodes: [node] } + ) + ); + } + } + } +}) +``` + ## Query complexity limits Payload comes with a built-in query complexity limiter to prevent bad people from trying to slow down your server by running massive queries. To learn more, [click here](/docs/production/preventing-abuse#limiting-graphql-complexity). + +## Field complexity + +You can define custom complexity for `relationship`, `upload` and `join` type fields. This is useful if you want to assign a higher complexity to a field that is more expensive to resolve. This can help prevent users from running queries that are too complex. + +```ts +const fieldWithComplexity = { + name: 'authors', + type: 'relationship', + relationship: 'authors', + graphQL: { + complexity: 100, // highlight-line + } +} +``` diff --git a/packages/graphql/src/index.ts b/packages/graphql/src/index.ts index dd6bc6b34a..09374d4d7b 100644 --- a/packages/graphql/src/index.ts +++ b/packages/graphql/src/index.ts @@ -98,14 +98,12 @@ export function configToSchema(config: SanitizedConfig): { const query = new GraphQL.GraphQLObjectType(graphqlResult.Query) const mutation = new GraphQL.GraphQLObjectType(graphqlResult.Mutation) - const schemaToCreate = { + const schema = new GraphQL.GraphQLSchema({ mutation, query, - } + }) - const schema = new GraphQL.GraphQLSchema(schemaToCreate) - - const validationRules = (args) => [ + const validationRules = (args): GraphQL.ValidationRule[] => [ createComplexityRule({ estimators: [ fieldExtensionsEstimator(), @@ -115,6 +113,9 @@ export function configToSchema(config: SanitizedConfig): { variables: args.variableValues, // onComplete: (complexity) => { console.log('Query Complexity:', complexity); }, }), + ...(typeof config?.graphQL?.validationRules === 'function' + ? config.graphQL.validationRules(args) + : []), ] return { diff --git a/packages/graphql/src/schema/buildObjectType.ts b/packages/graphql/src/schema/buildObjectType.ts index 76eacfc5ea..f1753d8001 100644 --- a/packages/graphql/src/schema/buildObjectType.ts +++ b/packages/graphql/src/schema/buildObjectType.ts @@ -245,7 +245,10 @@ export function buildObjectType({ type: graphqlResult.collections[field.collection].graphQL.whereInputType, }, }, - extensions: { complexity: 10 }, + extensions: { + complexity: + typeof field?.graphQL?.complexity === 'number' ? field.graphQL.complexity : 10, + }, async resolve(parent, args, context: Context) { const { collection } = field const { limit, sort, where } = args @@ -416,7 +419,10 @@ export function buildObjectType({ forceNullable, ), args: relationshipArgs, - extensions: { complexity: 10 }, + extensions: { + complexity: + typeof field?.graphQL?.complexity === 'number' ? field.graphQL.complexity : 10, + }, async resolve(parent, args, context: Context) { const value = parent[field.name] const locale = args.locale || context.req.locale @@ -768,7 +774,10 @@ export function buildObjectType({ forceNullable, ), args: relationshipArgs, - extensions: { complexity: 10 }, + extensions: { + complexity: + typeof field?.graphQL?.complexity === 'number' ? field.graphQL.complexity : 10, + }, async resolve(parent, args, context: Context) { const value = parent[field.name] const locale = args.locale || context.req.locale diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index 1eee12794c..c823cd88a2 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -950,6 +950,12 @@ export type Config = { * Filepath to write the generated schema to */ schemaOutputFile?: string + /** + * Function that returns an array of validation rules to apply to the GraphQL schema + * + * @see https://payloadcms.com/docs/graphql/overview#custom-validation-rules + */ + validationRules?: (args: GraphQL.ExecutionArgs) => GraphQL.ValidationRule[] } /** * Tap into Payload-wide hooks. diff --git a/packages/payload/src/fields/config/client.ts b/packages/payload/src/fields/config/client.ts index d11779fcdd..1e454ba6d3 100644 --- a/packages/payload/src/fields/config/client.ts +++ b/packages/payload/src/fields/config/client.ts @@ -32,6 +32,7 @@ export type ServerOnlyFieldProperties = | 'editor' // This is a `richText` only property | 'enumName' // can be a function | 'filterOptions' // This is a `relationship` and `upload` only property + | 'graphQL' | 'label' | 'typescriptSchema' | 'validate' @@ -53,6 +54,7 @@ const serverOnlyFieldProperties: Partial[] = [ 'typescriptSchema', 'dbName', // can be a function 'enumName', // can be a function + 'graphQL', // client does not need graphQL // the following props are handled separately (see below): // `label` // `fields` diff --git a/packages/payload/src/fields/config/types.ts b/packages/payload/src/fields/config/types.ts index 3796da3ebb..4d2f9aa56e 100644 --- a/packages/payload/src/fields/config/types.ts +++ b/packages/payload/src/fields/config/types.ts @@ -370,6 +370,17 @@ export type OptionObject = { export type Option = OptionObject | string +export type FieldGraphQLType = { + graphQL?: { + /** + * Complexity for the query. This is used to limit the complexity of the join query. + * + * @default 10 + */ + complexity?: number + } +} + export interface FieldBase { /** * Do not set this property manually. This is set to true during sanitization, to avoid @@ -844,6 +855,7 @@ type SharedUploadProperties = { validate?: UploadFieldSingleValidation } ) & + FieldGraphQLType & Omit type SharedUploadPropertiesClient = FieldBaseClient & @@ -1023,6 +1035,7 @@ type SharedRelationshipProperties = { validate?: RelationshipFieldSingleValidation } ) & + FieldGraphQLType & Omit type SharedRelationshipPropertiesClient = FieldBaseClient & @@ -1405,7 +1418,8 @@ export type JoinField = { type: 'join' validate?: never where?: Where -} & FieldBase +} & FieldBase & + FieldGraphQLType export type JoinFieldClient = { admin?: AdminClient & Pick diff --git a/test/graphql/config.ts b/test/graphql/config.ts new file mode 100644 index 0000000000..1793c4aeef --- /dev/null +++ b/test/graphql/config.ts @@ -0,0 +1,67 @@ +import { GraphQL } from '@payloadcms/graphql/types' +import { fileURLToPath } from 'node:url' +import path from 'path' + +import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' +import { devUser } from '../credentials.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfigWithDefaults({ + // ...extend config here + collections: [ + { + slug: 'posts', + fields: [ + { + name: 'title', + label: 'Title', + type: 'text', + }, + { + type: 'relationship', + relationTo: 'posts', + name: 'relationToSelf', + graphQL: { + complexity: 801, + }, + }, + ], + }, + ], + admin: { + importMap: { + baseDir: path.resolve(dirname), + }, + }, + onInit: async (payload) => { + await payload.create({ + collection: 'users', + data: { + email: devUser.email, + password: devUser.password, + }, + }) + }, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + graphQL: { + maxComplexity: 800, + validationRules: () => [NoIntrospection], + }, +}) + +const NoIntrospection: GraphQL.ValidationRule = (context) => ({ + Field(node) { + if (node.name.value === '__schema' || node.name.value === '__type') { + context.reportError( + new GraphQL.GraphQLError( + 'GraphQL introspection is not allowed, but the query contained __schema or __type', + { nodes: [node] }, + ), + ) + } + }, +}) diff --git a/test/graphql/eslint.config.js b/test/graphql/eslint.config.js new file mode 100644 index 0000000000..327c58a8e0 --- /dev/null +++ b/test/graphql/eslint.config.js @@ -0,0 +1,19 @@ +import { rootParserOptions } from '../../eslint.config.js' +import testEslintConfig from '../eslint.config.js' + +/** @typedef {import('eslint').Linter.Config} Config */ + +/** @type {Config[]} */ +export const index = [ + ...testEslintConfig, + { + languageOptions: { + parserOptions: { + ...rootParserOptions, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +] + +export default index diff --git a/test/graphql/int.spec.ts b/test/graphql/int.spec.ts new file mode 100644 index 0000000000..27a99952cd --- /dev/null +++ b/test/graphql/int.spec.ts @@ -0,0 +1,84 @@ +import type { Payload } from 'payload' + +import path from 'path' +import { fileURLToPath } from 'url' + +import type { NextRESTClient } from '../helpers/NextRESTClient.js' + +import { idToString } from '../helpers/idToString.js' +import { initPayloadInt } from '../helpers/initPayloadInt.js' + +let payload: Payload +let restClient: NextRESTClient + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +describe('graphql', () => { + beforeAll(async () => { + ;({ payload, restClient } = await initPayloadInt(dirname)) + }) + + afterAll(async () => { + if (typeof payload.db.destroy === 'function') { + await payload.db.destroy() + } + }) + + describe('graphql', () => { + it('should not be able to query introspection', async () => { + const query = `query { + __schema { + queryType { + name + } + } + }` + + const response = await restClient + .GRAPHQL_POST({ + body: JSON.stringify({ query }), + }) + .then((res) => res.json()) + + expect(response.errors[0].message).toMatch( + 'GraphQL introspection is not allowed, but the query contained __schema or __type', + ) + }) + + it('should respect maxComplexity', async () => { + const post = await payload.create({ + collection: 'posts', + data: { + title: 'example post', + }, + }) + await payload.update({ + collection: 'posts', + id: post.id, + data: { + relatedToSelf: post.id, + }, + }) + + const query = `query { + Post(id: ${idToString(post.id, payload)}) { + title + relationToSelf { + id + } + } + }` + + const response = await restClient + .GRAPHQL_POST({ + body: JSON.stringify({ query }), + }) + .then((res) => res.json()) + + expect(response.errors[0].message).toMatch( + 'The query exceeds the maximum complexity of 800. Actual complexity is 804', + ) + }) + }) +}) diff --git a/test/graphql/payload-types.ts b/test/graphql/payload-types.ts new file mode 100644 index 0000000000..06293ce574 --- /dev/null +++ b/test/graphql/payload-types.ts @@ -0,0 +1,214 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * This file was automatically generated by Payload. + * DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config, + * and re-run `payload generate:types` to regenerate this file. + */ + +export interface Config { + auth: { + users: UserAuthOperations; + }; + collections: { + posts: Post; + users: User; + 'payload-locked-documents': PayloadLockedDocument; + 'payload-preferences': PayloadPreference; + 'payload-migrations': PayloadMigration; + }; + collectionsJoins: {}; + collectionsSelect: { + posts: PostsSelect | PostsSelect; + users: UsersSelect | UsersSelect; + 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; + 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; + 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; + }; + db: { + defaultIDType: string; + }; + globals: {}; + globalsSelect: {}; + locale: null; + user: User & { + collection: 'users'; + }; + jobs: { + tasks: unknown; + workflows: unknown; + }; +} +export interface UserAuthOperations { + forgotPassword: { + email: string; + password: string; + }; + login: { + email: string; + password: string; + }; + registerFirstUser: { + email: string; + password: string; + }; + unlock: { + email: string; + password: string; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts". + */ +export interface Post { + id: string; + title?: string | null; + relationToSelf?: (string | null) | Post; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users". + */ +export interface User { + id: string; + updatedAt: string; + createdAt: string; + email: string; + resetPasswordToken?: string | null; + resetPasswordExpiration?: string | null; + salt?: string | null; + hash?: string | null; + loginAttempts?: number | null; + lockUntil?: string | null; + password?: string | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents". + */ +export interface PayloadLockedDocument { + id: string; + document?: + | ({ + relationTo: 'posts'; + value: string | Post; + } | null) + | ({ + relationTo: 'users'; + value: string | User; + } | null); + globalSlug?: string | null; + user: { + relationTo: 'users'; + value: string | User; + }; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences". + */ +export interface PayloadPreference { + id: string; + user: { + relationTo: 'users'; + value: string | User; + }; + key?: string | null; + value?: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations". + */ +export interface PayloadMigration { + id: string; + name?: string | null; + batch?: number | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts_select". + */ +export interface PostsSelect { + title?: T; + relationToSelf?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users_select". + */ +export interface UsersSelect { + updatedAt?: T; + createdAt?: T; + email?: T; + resetPasswordToken?: T; + resetPasswordExpiration?: T; + salt?: T; + hash?: T; + loginAttempts?: T; + lockUntil?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents_select". + */ +export interface PayloadLockedDocumentsSelect { + document?: T; + globalSlug?: T; + user?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences_select". + */ +export interface PayloadPreferencesSelect { + user?: T; + key?: T; + value?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations_select". + */ +export interface PayloadMigrationsSelect { + name?: T; + batch?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "auth". + */ +export interface Auth { + [k: string]: unknown; +} + + +declare module 'payload' { + // @ts-ignore + export interface GeneratedTypes extends Config {} +} \ No newline at end of file diff --git a/test/graphql/schema.graphql b/test/graphql/schema.graphql new file mode 100644 index 0000000000..853bed9d13 --- /dev/null +++ b/test/graphql/schema.graphql @@ -0,0 +1,1799 @@ +type Query { + Post(id: String!, draft: Boolean): Post + Posts(draft: Boolean, where: Post_where, limit: Int, page: Int, pagination: Boolean, sort: String): Posts + countPosts(draft: Boolean, where: Post_where): countPosts + docAccessPost(id: String!): postsDocAccess + User(id: String!, draft: Boolean): User + Users(draft: Boolean, where: User_where, limit: Int, page: Int, pagination: Boolean, sort: String): Users + countUsers(draft: Boolean, where: User_where): countUsers + docAccessUser(id: String!): usersDocAccess + meUser: usersMe + initializedUser: Boolean + PayloadLockedDocument(id: String!, draft: Boolean): PayloadLockedDocument + PayloadLockedDocuments(draft: Boolean, where: PayloadLockedDocument_where, limit: Int, page: Int, pagination: Boolean, sort: String): PayloadLockedDocuments + countPayloadLockedDocuments(draft: Boolean, where: PayloadLockedDocument_where): countPayloadLockedDocuments + docAccessPayloadLockedDocument(id: String!): payload_locked_documentsDocAccess + PayloadPreference(id: String!, draft: Boolean): PayloadPreference + PayloadPreferences(draft: Boolean, where: PayloadPreference_where, limit: Int, page: Int, pagination: Boolean, sort: String): PayloadPreferences + countPayloadPreferences(draft: Boolean, where: PayloadPreference_where): countPayloadPreferences + docAccessPayloadPreference(id: String!): payload_preferencesDocAccess + Access: Access +} + +type Post { + id: String! + title: String + relationToSelf: Post + updatedAt: DateTime + createdAt: DateTime +} + +""" +A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar DateTime + +type Posts { + docs: [Post] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input Post_where { + title: Post_title_operator + relationToSelf: Post_relationToSelf_operator + updatedAt: Post_updatedAt_operator + createdAt: Post_createdAt_operator + id: Post_id_operator + AND: [Post_where_and] + OR: [Post_where_or] +} + +input Post_title_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Post_relationToSelf_operator { + equals: JSON + not_equals: JSON + in: [JSON] + not_in: [JSON] + all: [JSON] + exists: Boolean +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") + +input Post_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Post_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Post_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Post_where_and { + title: Post_title_operator + relationToSelf: Post_relationToSelf_operator + updatedAt: Post_updatedAt_operator + createdAt: Post_createdAt_operator + id: Post_id_operator + AND: [Post_where_and] + OR: [Post_where_or] +} + +input Post_where_or { + title: Post_title_operator + relationToSelf: Post_relationToSelf_operator + updatedAt: Post_updatedAt_operator + createdAt: Post_createdAt_operator + id: Post_id_operator + AND: [Post_where_and] + OR: [Post_where_or] +} + +type countPosts { + totalDocs: Int +} + +type postsDocAccess { + fields: PostsDocAccessFields + create: PostsCreateDocAccess + read: PostsReadDocAccess + update: PostsUpdateDocAccess + delete: PostsDeleteDocAccess +} + +type PostsDocAccessFields { + title: PostsDocAccessFields_title + relationToSelf: PostsDocAccessFields_relationToSelf + updatedAt: PostsDocAccessFields_updatedAt + createdAt: PostsDocAccessFields_createdAt +} + +type PostsDocAccessFields_title { + create: PostsDocAccessFields_title_Create + read: PostsDocAccessFields_title_Read + update: PostsDocAccessFields_title_Update + delete: PostsDocAccessFields_title_Delete +} + +type PostsDocAccessFields_title_Create { + permission: Boolean! +} + +type PostsDocAccessFields_title_Read { + permission: Boolean! +} + +type PostsDocAccessFields_title_Update { + permission: Boolean! +} + +type PostsDocAccessFields_title_Delete { + permission: Boolean! +} + +type PostsDocAccessFields_relationToSelf { + create: PostsDocAccessFields_relationToSelf_Create + read: PostsDocAccessFields_relationToSelf_Read + update: PostsDocAccessFields_relationToSelf_Update + delete: PostsDocAccessFields_relationToSelf_Delete +} + +type PostsDocAccessFields_relationToSelf_Create { + permission: Boolean! +} + +type PostsDocAccessFields_relationToSelf_Read { + permission: Boolean! +} + +type PostsDocAccessFields_relationToSelf_Update { + permission: Boolean! +} + +type PostsDocAccessFields_relationToSelf_Delete { + permission: Boolean! +} + +type PostsDocAccessFields_updatedAt { + create: PostsDocAccessFields_updatedAt_Create + read: PostsDocAccessFields_updatedAt_Read + update: PostsDocAccessFields_updatedAt_Update + delete: PostsDocAccessFields_updatedAt_Delete +} + +type PostsDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PostsDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PostsDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PostsDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PostsDocAccessFields_createdAt { + create: PostsDocAccessFields_createdAt_Create + read: PostsDocAccessFields_createdAt_Read + update: PostsDocAccessFields_createdAt_Update + delete: PostsDocAccessFields_createdAt_Delete +} + +type PostsDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PostsDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PostsDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PostsDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PostsCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +""" +The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSONObject @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") + +type PostsReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PostsUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PostsDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type User { + id: String! + updatedAt: DateTime + createdAt: DateTime + email: EmailAddress! + resetPasswordToken: String + resetPasswordExpiration: DateTime + salt: String + hash: String + loginAttempts: Float + lockUntil: DateTime +} + +""" +A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. +""" +scalar EmailAddress @specifiedBy(url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address") + +type Users { + docs: [User] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input User_where { + updatedAt: User_updatedAt_operator + createdAt: User_createdAt_operator + email: User_email_operator + id: User_id_operator + AND: [User_where_and] + OR: [User_where_or] +} + +input User_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input User_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input User_email_operator { + equals: EmailAddress + not_equals: EmailAddress + like: EmailAddress + contains: EmailAddress + in: [EmailAddress] + not_in: [EmailAddress] + all: [EmailAddress] +} + +input User_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input User_where_and { + updatedAt: User_updatedAt_operator + createdAt: User_createdAt_operator + email: User_email_operator + id: User_id_operator + AND: [User_where_and] + OR: [User_where_or] +} + +input User_where_or { + updatedAt: User_updatedAt_operator + createdAt: User_createdAt_operator + email: User_email_operator + id: User_id_operator + AND: [User_where_and] + OR: [User_where_or] +} + +type countUsers { + totalDocs: Int +} + +type usersDocAccess { + fields: UsersDocAccessFields + create: UsersCreateDocAccess + read: UsersReadDocAccess + update: UsersUpdateDocAccess + delete: UsersDeleteDocAccess + unlock: UsersUnlockDocAccess +} + +type UsersDocAccessFields { + updatedAt: UsersDocAccessFields_updatedAt + createdAt: UsersDocAccessFields_createdAt + email: UsersDocAccessFields_email +} + +type UsersDocAccessFields_updatedAt { + create: UsersDocAccessFields_updatedAt_Create + read: UsersDocAccessFields_updatedAt_Read + update: UsersDocAccessFields_updatedAt_Update + delete: UsersDocAccessFields_updatedAt_Delete +} + +type UsersDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt { + create: UsersDocAccessFields_createdAt_Create + read: UsersDocAccessFields_createdAt_Read + update: UsersDocAccessFields_createdAt_Update + delete: UsersDocAccessFields_createdAt_Delete +} + +type UsersDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type UsersDocAccessFields_email { + create: UsersDocAccessFields_email_Create + read: UsersDocAccessFields_email_Read + update: UsersDocAccessFields_email_Update + delete: UsersDocAccessFields_email_Delete +} + +type UsersDocAccessFields_email_Create { + permission: Boolean! +} + +type UsersDocAccessFields_email_Read { + permission: Boolean! +} + +type UsersDocAccessFields_email_Update { + permission: Boolean! +} + +type UsersDocAccessFields_email_Delete { + permission: Boolean! +} + +type UsersCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUnlockDocAccess { + permission: Boolean! + where: JSONObject +} + +type usersMe { + collection: String + exp: Int + strategy: String + token: String + user: User +} + +type PayloadLockedDocument { + id: String! + document: PayloadLockedDocument_Document_Relationship + globalSlug: String + user: PayloadLockedDocument_User_Relationship! + updatedAt: DateTime + createdAt: DateTime +} + +type PayloadLockedDocument_Document_Relationship { + relationTo: PayloadLockedDocument_Document_RelationTo + value: PayloadLockedDocument_Document +} + +enum PayloadLockedDocument_Document_RelationTo { + posts + users +} + +union PayloadLockedDocument_Document = Post | User + +type PayloadLockedDocument_User_Relationship { + relationTo: PayloadLockedDocument_User_RelationTo + value: PayloadLockedDocument_User +} + +enum PayloadLockedDocument_User_RelationTo { + users +} + +union PayloadLockedDocument_User = User + +type PayloadLockedDocuments { + docs: [PayloadLockedDocument] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input PayloadLockedDocument_where { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +input PayloadLockedDocument_document_Relation { + relationTo: PayloadLockedDocument_document_Relation_RelationTo + value: JSON +} + +enum PayloadLockedDocument_document_Relation_RelationTo { + posts + users +} + +input PayloadLockedDocument_globalSlug_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadLockedDocument_user_Relation { + relationTo: PayloadLockedDocument_user_Relation_RelationTo + value: JSON +} + +enum PayloadLockedDocument_user_Relation_RelationTo { + users +} + +input PayloadLockedDocument_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadLockedDocument_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadLockedDocument_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadLockedDocument_where_and { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +input PayloadLockedDocument_where_or { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +type countPayloadLockedDocuments { + totalDocs: Int +} + +type payload_locked_documentsDocAccess { + fields: PayloadLockedDocumentsDocAccessFields + create: PayloadLockedDocumentsCreateDocAccess + read: PayloadLockedDocumentsReadDocAccess + update: PayloadLockedDocumentsUpdateDocAccess + delete: PayloadLockedDocumentsDeleteDocAccess +} + +type PayloadLockedDocumentsDocAccessFields { + document: PayloadLockedDocumentsDocAccessFields_document + globalSlug: PayloadLockedDocumentsDocAccessFields_globalSlug + user: PayloadLockedDocumentsDocAccessFields_user + updatedAt: PayloadLockedDocumentsDocAccessFields_updatedAt + createdAt: PayloadLockedDocumentsDocAccessFields_createdAt +} + +type PayloadLockedDocumentsDocAccessFields_document { + create: PayloadLockedDocumentsDocAccessFields_document_Create + read: PayloadLockedDocumentsDocAccessFields_document_Read + update: PayloadLockedDocumentsDocAccessFields_document_Update + delete: PayloadLockedDocumentsDocAccessFields_document_Delete +} + +type PayloadLockedDocumentsDocAccessFields_document_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug { + create: PayloadLockedDocumentsDocAccessFields_globalSlug_Create + read: PayloadLockedDocumentsDocAccessFields_globalSlug_Read + update: PayloadLockedDocumentsDocAccessFields_globalSlug_Update + delete: PayloadLockedDocumentsDocAccessFields_globalSlug_Delete +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user { + create: PayloadLockedDocumentsDocAccessFields_user_Create + read: PayloadLockedDocumentsDocAccessFields_user_Read + update: PayloadLockedDocumentsDocAccessFields_user_Update + delete: PayloadLockedDocumentsDocAccessFields_user_Delete +} + +type PayloadLockedDocumentsDocAccessFields_user_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt { + create: PayloadLockedDocumentsDocAccessFields_updatedAt_Create + read: PayloadLockedDocumentsDocAccessFields_updatedAt_Read + update: PayloadLockedDocumentsDocAccessFields_updatedAt_Update + delete: PayloadLockedDocumentsDocAccessFields_updatedAt_Delete +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt { + create: PayloadLockedDocumentsDocAccessFields_createdAt_Create + read: PayloadLockedDocumentsDocAccessFields_createdAt_Read + update: PayloadLockedDocumentsDocAccessFields_createdAt_Update + delete: PayloadLockedDocumentsDocAccessFields_createdAt_Delete +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreference { + id: String! + user: PayloadPreference_User_Relationship! + key: String + value: JSON + updatedAt: DateTime + createdAt: DateTime +} + +type PayloadPreference_User_Relationship { + relationTo: PayloadPreference_User_RelationTo + value: PayloadPreference_User +} + +enum PayloadPreference_User_RelationTo { + users +} + +union PayloadPreference_User = User + +type PayloadPreferences { + docs: [PayloadPreference] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input PayloadPreference_where { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + AND: [PayloadPreference_where_and] + OR: [PayloadPreference_where_or] +} + +input PayloadPreference_user_Relation { + relationTo: PayloadPreference_user_Relation_RelationTo + value: JSON +} + +enum PayloadPreference_user_Relation_RelationTo { + users +} + +input PayloadPreference_key_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadPreference_value_operator { + equals: JSON + not_equals: JSON + like: JSON + contains: JSON + within: JSON + intersects: JSON + exists: Boolean +} + +input PayloadPreference_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadPreference_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadPreference_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadPreference_where_and { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + AND: [PayloadPreference_where_and] + OR: [PayloadPreference_where_or] +} + +input PayloadPreference_where_or { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + AND: [PayloadPreference_where_and] + OR: [PayloadPreference_where_or] +} + +type countPayloadPreferences { + totalDocs: Int +} + +type payload_preferencesDocAccess { + fields: PayloadPreferencesDocAccessFields + create: PayloadPreferencesCreateDocAccess + read: PayloadPreferencesReadDocAccess + update: PayloadPreferencesUpdateDocAccess + delete: PayloadPreferencesDeleteDocAccess +} + +type PayloadPreferencesDocAccessFields { + user: PayloadPreferencesDocAccessFields_user + key: PayloadPreferencesDocAccessFields_key + value: PayloadPreferencesDocAccessFields_value + updatedAt: PayloadPreferencesDocAccessFields_updatedAt + createdAt: PayloadPreferencesDocAccessFields_createdAt +} + +type PayloadPreferencesDocAccessFields_user { + create: PayloadPreferencesDocAccessFields_user_Create + read: PayloadPreferencesDocAccessFields_user_Read + update: PayloadPreferencesDocAccessFields_user_Update + delete: PayloadPreferencesDocAccessFields_user_Delete +} + +type PayloadPreferencesDocAccessFields_user_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key { + create: PayloadPreferencesDocAccessFields_key_Create + read: PayloadPreferencesDocAccessFields_key_Read + update: PayloadPreferencesDocAccessFields_key_Update + delete: PayloadPreferencesDocAccessFields_key_Delete +} + +type PayloadPreferencesDocAccessFields_key_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value { + create: PayloadPreferencesDocAccessFields_value_Create + read: PayloadPreferencesDocAccessFields_value_Read + update: PayloadPreferencesDocAccessFields_value_Update + delete: PayloadPreferencesDocAccessFields_value_Delete +} + +type PayloadPreferencesDocAccessFields_value_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt { + create: PayloadPreferencesDocAccessFields_updatedAt_Create + read: PayloadPreferencesDocAccessFields_updatedAt_Read + update: PayloadPreferencesDocAccessFields_updatedAt_Update + delete: PayloadPreferencesDocAccessFields_updatedAt_Delete +} + +type PayloadPreferencesDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt { + create: PayloadPreferencesDocAccessFields_createdAt_Create + read: PayloadPreferencesDocAccessFields_createdAt_Read + update: PayloadPreferencesDocAccessFields_createdAt_Update + delete: PayloadPreferencesDocAccessFields_createdAt_Delete +} + +type PayloadPreferencesDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type Access { + canAccessAdmin: Boolean! + posts: postsAccess + users: usersAccess + payload_locked_documents: payload_locked_documentsAccess + payload_preferences: payload_preferencesAccess +} + +type postsAccess { + fields: PostsFields + create: PostsCreateAccess + read: PostsReadAccess + update: PostsUpdateAccess + delete: PostsDeleteAccess +} + +type PostsFields { + title: PostsFields_title + relationToSelf: PostsFields_relationToSelf + updatedAt: PostsFields_updatedAt + createdAt: PostsFields_createdAt +} + +type PostsFields_title { + create: PostsFields_title_Create + read: PostsFields_title_Read + update: PostsFields_title_Update + delete: PostsFields_title_Delete +} + +type PostsFields_title_Create { + permission: Boolean! +} + +type PostsFields_title_Read { + permission: Boolean! +} + +type PostsFields_title_Update { + permission: Boolean! +} + +type PostsFields_title_Delete { + permission: Boolean! +} + +type PostsFields_relationToSelf { + create: PostsFields_relationToSelf_Create + read: PostsFields_relationToSelf_Read + update: PostsFields_relationToSelf_Update + delete: PostsFields_relationToSelf_Delete +} + +type PostsFields_relationToSelf_Create { + permission: Boolean! +} + +type PostsFields_relationToSelf_Read { + permission: Boolean! +} + +type PostsFields_relationToSelf_Update { + permission: Boolean! +} + +type PostsFields_relationToSelf_Delete { + permission: Boolean! +} + +type PostsFields_updatedAt { + create: PostsFields_updatedAt_Create + read: PostsFields_updatedAt_Read + update: PostsFields_updatedAt_Update + delete: PostsFields_updatedAt_Delete +} + +type PostsFields_updatedAt_Create { + permission: Boolean! +} + +type PostsFields_updatedAt_Read { + permission: Boolean! +} + +type PostsFields_updatedAt_Update { + permission: Boolean! +} + +type PostsFields_updatedAt_Delete { + permission: Boolean! +} + +type PostsFields_createdAt { + create: PostsFields_createdAt_Create + read: PostsFields_createdAt_Read + update: PostsFields_createdAt_Update + delete: PostsFields_createdAt_Delete +} + +type PostsFields_createdAt_Create { + permission: Boolean! +} + +type PostsFields_createdAt_Read { + permission: Boolean! +} + +type PostsFields_createdAt_Update { + permission: Boolean! +} + +type PostsFields_createdAt_Delete { + permission: Boolean! +} + +type PostsCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PostsReadAccess { + permission: Boolean! + where: JSONObject +} + +type PostsUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PostsDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type usersAccess { + fields: UsersFields + create: UsersCreateAccess + read: UsersReadAccess + update: UsersUpdateAccess + delete: UsersDeleteAccess + unlock: UsersUnlockAccess +} + +type UsersFields { + updatedAt: UsersFields_updatedAt + createdAt: UsersFields_createdAt + email: UsersFields_email +} + +type UsersFields_updatedAt { + create: UsersFields_updatedAt_Create + read: UsersFields_updatedAt_Read + update: UsersFields_updatedAt_Update + delete: UsersFields_updatedAt_Delete +} + +type UsersFields_updatedAt_Create { + permission: Boolean! +} + +type UsersFields_updatedAt_Read { + permission: Boolean! +} + +type UsersFields_updatedAt_Update { + permission: Boolean! +} + +type UsersFields_updatedAt_Delete { + permission: Boolean! +} + +type UsersFields_createdAt { + create: UsersFields_createdAt_Create + read: UsersFields_createdAt_Read + update: UsersFields_createdAt_Update + delete: UsersFields_createdAt_Delete +} + +type UsersFields_createdAt_Create { + permission: Boolean! +} + +type UsersFields_createdAt_Read { + permission: Boolean! +} + +type UsersFields_createdAt_Update { + permission: Boolean! +} + +type UsersFields_createdAt_Delete { + permission: Boolean! +} + +type UsersFields_email { + create: UsersFields_email_Create + read: UsersFields_email_Read + update: UsersFields_email_Update + delete: UsersFields_email_Delete +} + +type UsersFields_email_Create { + permission: Boolean! +} + +type UsersFields_email_Read { + permission: Boolean! +} + +type UsersFields_email_Update { + permission: Boolean! +} + +type UsersFields_email_Delete { + permission: Boolean! +} + +type UsersCreateAccess { + permission: Boolean! + where: JSONObject +} + +type UsersReadAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type UsersDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUnlockAccess { + permission: Boolean! + where: JSONObject +} + +type payload_locked_documentsAccess { + fields: PayloadLockedDocumentsFields + create: PayloadLockedDocumentsCreateAccess + read: PayloadLockedDocumentsReadAccess + update: PayloadLockedDocumentsUpdateAccess + delete: PayloadLockedDocumentsDeleteAccess +} + +type PayloadLockedDocumentsFields { + document: PayloadLockedDocumentsFields_document + globalSlug: PayloadLockedDocumentsFields_globalSlug + user: PayloadLockedDocumentsFields_user + updatedAt: PayloadLockedDocumentsFields_updatedAt + createdAt: PayloadLockedDocumentsFields_createdAt +} + +type PayloadLockedDocumentsFields_document { + create: PayloadLockedDocumentsFields_document_Create + read: PayloadLockedDocumentsFields_document_Read + update: PayloadLockedDocumentsFields_document_Update + delete: PayloadLockedDocumentsFields_document_Delete +} + +type PayloadLockedDocumentsFields_document_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug { + create: PayloadLockedDocumentsFields_globalSlug_Create + read: PayloadLockedDocumentsFields_globalSlug_Read + update: PayloadLockedDocumentsFields_globalSlug_Update + delete: PayloadLockedDocumentsFields_globalSlug_Delete +} + +type PayloadLockedDocumentsFields_globalSlug_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user { + create: PayloadLockedDocumentsFields_user_Create + read: PayloadLockedDocumentsFields_user_Read + update: PayloadLockedDocumentsFields_user_Update + delete: PayloadLockedDocumentsFields_user_Delete +} + +type PayloadLockedDocumentsFields_user_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt { + create: PayloadLockedDocumentsFields_updatedAt_Create + read: PayloadLockedDocumentsFields_updatedAt_Read + update: PayloadLockedDocumentsFields_updatedAt_Update + delete: PayloadLockedDocumentsFields_updatedAt_Delete +} + +type PayloadLockedDocumentsFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt { + create: PayloadLockedDocumentsFields_createdAt_Create + read: PayloadLockedDocumentsFields_createdAt_Read + update: PayloadLockedDocumentsFields_createdAt_Update + delete: PayloadLockedDocumentsFields_createdAt_Delete +} + +type PayloadLockedDocumentsFields_createdAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsReadAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type payload_preferencesAccess { + fields: PayloadPreferencesFields + create: PayloadPreferencesCreateAccess + read: PayloadPreferencesReadAccess + update: PayloadPreferencesUpdateAccess + delete: PayloadPreferencesDeleteAccess +} + +type PayloadPreferencesFields { + user: PayloadPreferencesFields_user + key: PayloadPreferencesFields_key + value: PayloadPreferencesFields_value + updatedAt: PayloadPreferencesFields_updatedAt + createdAt: PayloadPreferencesFields_createdAt +} + +type PayloadPreferencesFields_user { + create: PayloadPreferencesFields_user_Create + read: PayloadPreferencesFields_user_Read + update: PayloadPreferencesFields_user_Update + delete: PayloadPreferencesFields_user_Delete +} + +type PayloadPreferencesFields_user_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_key { + create: PayloadPreferencesFields_key_Create + read: PayloadPreferencesFields_key_Read + update: PayloadPreferencesFields_key_Update + delete: PayloadPreferencesFields_key_Delete +} + +type PayloadPreferencesFields_key_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_value { + create: PayloadPreferencesFields_value_Create + read: PayloadPreferencesFields_value_Read + update: PayloadPreferencesFields_value_Update + delete: PayloadPreferencesFields_value_Delete +} + +type PayloadPreferencesFields_value_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt { + create: PayloadPreferencesFields_updatedAt_Create + read: PayloadPreferencesFields_updatedAt_Read + update: PayloadPreferencesFields_updatedAt_Update + delete: PayloadPreferencesFields_updatedAt_Delete +} + +type PayloadPreferencesFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt { + create: PayloadPreferencesFields_createdAt_Create + read: PayloadPreferencesFields_createdAt_Read + update: PayloadPreferencesFields_createdAt_Update + delete: PayloadPreferencesFields_createdAt_Delete +} + +type PayloadPreferencesFields_createdAt_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesReadAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type Mutation { + createPost(data: mutationPostInput!, draft: Boolean): Post + updatePost(id: String!, autosave: Boolean, data: mutationPostUpdateInput!, draft: Boolean): Post + deletePost(id: String!): Post + duplicatePost(id: String!, data: mutationPostInput!): Post + createUser(data: mutationUserInput!, draft: Boolean): User + updateUser(id: String!, autosave: Boolean, data: mutationUserUpdateInput!, draft: Boolean): User + deleteUser(id: String!): User + refreshTokenUser: usersRefreshedUser + logoutUser: String + unlockUser(email: String!): Boolean! + loginUser(email: String!, password: String): usersLoginResult + forgotPasswordUser(disableEmail: Boolean, expiration: Int, email: String!): Boolean! + resetPasswordUser(password: String, token: String): usersResetPassword + verifyEmailUser(token: String): Boolean + createPayloadLockedDocument(data: mutationPayloadLockedDocumentInput!, draft: Boolean): PayloadLockedDocument + updatePayloadLockedDocument(id: String!, autosave: Boolean, data: mutationPayloadLockedDocumentUpdateInput!, draft: Boolean): PayloadLockedDocument + deletePayloadLockedDocument(id: String!): PayloadLockedDocument + duplicatePayloadLockedDocument(id: String!, data: mutationPayloadLockedDocumentInput!): PayloadLockedDocument + createPayloadPreference(data: mutationPayloadPreferenceInput!, draft: Boolean): PayloadPreference + updatePayloadPreference(id: String!, autosave: Boolean, data: mutationPayloadPreferenceUpdateInput!, draft: Boolean): PayloadPreference + deletePayloadPreference(id: String!): PayloadPreference + duplicatePayloadPreference(id: String!, data: mutationPayloadPreferenceInput!): PayloadPreference +} + +input mutationPostInput { + title: String + relationToSelf: String + updatedAt: String + createdAt: String +} + +input mutationPostUpdateInput { + title: String + relationToSelf: String + updatedAt: String + createdAt: String +} + +input mutationUserInput { + updatedAt: String + createdAt: String + email: String! + resetPasswordToken: String + resetPasswordExpiration: String + salt: String + hash: String + loginAttempts: Float + lockUntil: String + password: String! +} + +input mutationUserUpdateInput { + updatedAt: String + createdAt: String + email: String + resetPasswordToken: String + resetPasswordExpiration: String + salt: String + hash: String + loginAttempts: Float + lockUntil: String + password: String +} + +type usersRefreshedUser { + exp: Int + refreshedToken: String + strategy: String + user: usersJWT +} + +type usersJWT { + email: EmailAddress! + collection: String! +} + +type usersLoginResult { + exp: Int + token: String + user: User +} + +type usersResetPassword { + token: String + user: User +} + +input mutationPayloadLockedDocumentInput { + document: PayloadLockedDocument_DocumentRelationshipInput + globalSlug: String + user: PayloadLockedDocument_UserRelationshipInput + updatedAt: String + createdAt: String +} + +input PayloadLockedDocument_DocumentRelationshipInput { + relationTo: PayloadLockedDocument_DocumentRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocument_DocumentRelationshipInputRelationTo { + posts + users +} + +input PayloadLockedDocument_UserRelationshipInput { + relationTo: PayloadLockedDocument_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocument_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadLockedDocumentUpdateInput { + document: PayloadLockedDocumentUpdate_DocumentRelationshipInput + globalSlug: String + user: PayloadLockedDocumentUpdate_UserRelationshipInput + updatedAt: String + createdAt: String +} + +input PayloadLockedDocumentUpdate_DocumentRelationshipInput { + relationTo: PayloadLockedDocumentUpdate_DocumentRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocumentUpdate_DocumentRelationshipInputRelationTo { + posts + users +} + +input PayloadLockedDocumentUpdate_UserRelationshipInput { + relationTo: PayloadLockedDocumentUpdate_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocumentUpdate_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadPreferenceInput { + user: PayloadPreference_UserRelationshipInput + key: String + value: JSON + updatedAt: String + createdAt: String +} + +input PayloadPreference_UserRelationshipInput { + relationTo: PayloadPreference_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadPreference_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadPreferenceUpdateInput { + user: PayloadPreferenceUpdate_UserRelationshipInput + key: String + value: JSON + updatedAt: String + createdAt: String +} + +input PayloadPreferenceUpdate_UserRelationshipInput { + relationTo: PayloadPreferenceUpdate_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadPreferenceUpdate_UserRelationshipInputRelationTo { + users +} \ No newline at end of file diff --git a/test/graphql/tsconfig.eslint.json b/test/graphql/tsconfig.eslint.json new file mode 100644 index 0000000000..b34cc7afbb --- /dev/null +++ b/test/graphql/tsconfig.eslint.json @@ -0,0 +1,13 @@ +{ + // extend your base config to share compilerOptions, etc + //"extends": "./tsconfig.json", + "compilerOptions": { + // ensure that nobody can accidentally use this config for a build + "noEmit": true + }, + "include": [ + // whatever paths you intend to lint + "./**/*.ts", + "./**/*.tsx" + ] +} diff --git a/test/graphql/tsconfig.json b/test/graphql/tsconfig.json new file mode 100644 index 0000000000..3c43903cfd --- /dev/null +++ b/test/graphql/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.json" +}