chore: reduces graphql dependencies (#5979)
Co-authored-by: Elliot DeNolf <denolfe@gmail.com>
This commit is contained in:
@@ -27,20 +27,17 @@
|
||||
"devDependencies": {
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"@types/pluralize": "^0.0.33",
|
||||
"graphql-http": "^1.22.0",
|
||||
"payload": "workspace:*",
|
||||
"ts-essentials": "7.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"graphql": "16.8.1",
|
||||
"graphql-http": "^1.22.0",
|
||||
"graphql-playground-html": "1.6.30",
|
||||
"graphql-query-complexity": "0.12.0",
|
||||
"graphql-scalars": "1.22.2",
|
||||
"graphql-type-json": "0.3.2",
|
||||
"pluralize": "8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"payload": "workspace:*"
|
||||
"payload": "workspace:*",
|
||||
"graphql": "^16.8.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -4,12 +4,12 @@ import type { GraphQLInfo } from 'payload/config'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import * as GraphQL from 'graphql'
|
||||
|
||||
import {
|
||||
createComplexityRule,
|
||||
fieldExtensionsEstimator,
|
||||
simpleEstimator,
|
||||
} from 'graphql-query-complexity'
|
||||
|
||||
} from './packages/graphql-query-complexity/index.js'
|
||||
import accessResolver from './resolvers/auth/access.js'
|
||||
import buildFallbackLocaleInputType from './schema/buildFallbackLocaleInputType.js'
|
||||
import buildLocaleInputType from './schema/buildLocaleInputType.js'
|
||||
@@ -18,10 +18,10 @@ import initCollections from './schema/initCollections.js'
|
||||
import initGlobals from './schema/initGlobals.js'
|
||||
import { wrapCustomFields } from './utilities/wrapCustomResolver.js'
|
||||
|
||||
export async function configToSchema(config: SanitizedConfig): Promise<{
|
||||
export function configToSchema(config: SanitizedConfig): {
|
||||
schema: GraphQL.GraphQLSchema
|
||||
validationRules: (args: OperationArgs<any>) => GraphQL.ValidationRule[]
|
||||
}> {
|
||||
} {
|
||||
const collections = config.collections.reduce((acc, collection) => {
|
||||
acc[collection.slug] = {
|
||||
config: collection,
|
||||
|
||||
@@ -0,0 +1,455 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-use-before-define */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
|
||||
/**
|
||||
* Created by Ivo Meißner on 28.07.17.
|
||||
*/
|
||||
|
||||
import type {
|
||||
DocumentNode,
|
||||
FieldNode,
|
||||
FragmentDefinitionNode,
|
||||
FragmentSpreadNode,
|
||||
GraphQLCompositeType,
|
||||
GraphQLDirective,
|
||||
GraphQLField,
|
||||
GraphQLFieldMap,
|
||||
GraphQLNamedType,
|
||||
GraphQLSchema,
|
||||
GraphQLUnionType,
|
||||
InlineFragmentNode,
|
||||
OperationDefinitionNode} from 'graphql';
|
||||
|
||||
import {
|
||||
GraphQLError,
|
||||
GraphQLInterfaceType,
|
||||
GraphQLObjectType,
|
||||
Kind,
|
||||
TypeInfo,
|
||||
ValidationContext,
|
||||
getNamedType,
|
||||
isAbstractType,
|
||||
isCompositeType,
|
||||
visit,
|
||||
visitWithTypeInfo,
|
||||
} from 'graphql'
|
||||
import {
|
||||
getArgumentValues,
|
||||
getDirectiveValues,
|
||||
getVariableValues,
|
||||
} from 'graphql/execution/values.js'
|
||||
|
||||
export type ComplexityEstimatorArgs = {
|
||||
args: { [key: string]: any }
|
||||
childComplexity: number
|
||||
context?: Record<string, any>
|
||||
field: GraphQLField<any, any>
|
||||
node: FieldNode
|
||||
type: GraphQLCompositeType
|
||||
}
|
||||
|
||||
export type ComplexityEstimator = (options: ComplexityEstimatorArgs) => number | void
|
||||
|
||||
// Complexity can be anything that is supported by the configured estimators
|
||||
export type Complexity = any
|
||||
|
||||
// Map of complexities for possible types (of Union, Interface types)
|
||||
type ComplexityMap = {
|
||||
[typeName: string]: number
|
||||
}
|
||||
|
||||
export interface QueryComplexityOptions {
|
||||
// Pass request context to the estimators via estimationContext
|
||||
context?: Record<string, any>
|
||||
|
||||
// The query variables. This is needed because the variables are not available
|
||||
// Optional function to create a custom error
|
||||
createError?: (max: number, actual: number) => GraphQLError
|
||||
|
||||
// An array of complexity estimators to use for estimating the complexity
|
||||
estimators: Array<ComplexityEstimator>
|
||||
|
||||
// Optional callback function to retrieve the determined query complexity
|
||||
// Will be invoked whether the query is rejected or not
|
||||
// The maximum allowed query complexity, queries above this threshold will be rejected
|
||||
maximumComplexity: number
|
||||
|
||||
// This can be used for logging or to implement rate limiting
|
||||
onComplete?: (complexity: number) => void
|
||||
|
||||
// specify operation name only when pass multi-operation documents
|
||||
operationName?: string
|
||||
|
||||
// in the visitor of the graphql-js library
|
||||
variables?: Record<string, any>
|
||||
}
|
||||
|
||||
function queryComplexityMessage(max: number, actual: number): string {
|
||||
return `The query exceeds the maximum complexity of ${max}. ` + `Actual complexity is ${actual}`
|
||||
}
|
||||
|
||||
export function getComplexity(options: {
|
||||
context?: Record<string, any>
|
||||
estimators: ComplexityEstimator[]
|
||||
operationName?: string
|
||||
query: DocumentNode
|
||||
schema: GraphQLSchema
|
||||
variables?: Record<string, any>
|
||||
}): number {
|
||||
const typeInfo = new TypeInfo(options.schema)
|
||||
|
||||
const errors: GraphQLError[] = []
|
||||
const context = new ValidationContext(options.schema, options.query, typeInfo, (error) =>
|
||||
errors.push(error),
|
||||
)
|
||||
const visitor = new QueryComplexity(context, {
|
||||
// Maximum complexity does not matter since we're only interested in the calculated complexity.
|
||||
context: options.context,
|
||||
estimators: options.estimators,
|
||||
maximumComplexity: Infinity,
|
||||
operationName: options.operationName,
|
||||
variables: options.variables,
|
||||
})
|
||||
|
||||
visit(options.query, visitWithTypeInfo(typeInfo, visitor))
|
||||
|
||||
// Throw first error if any
|
||||
if (errors.length) {
|
||||
throw errors.pop()
|
||||
}
|
||||
|
||||
return visitor.complexity
|
||||
}
|
||||
|
||||
export default class QueryComplexity {
|
||||
OperationDefinition: Record<string, any>
|
||||
complexity: number
|
||||
context: ValidationContext
|
||||
estimators: Array<ComplexityEstimator>
|
||||
includeDirectiveDef: GraphQLDirective
|
||||
options: QueryComplexityOptions
|
||||
requestContext?: Record<string, any>
|
||||
skipDirectiveDef: GraphQLDirective
|
||||
variableValues: Record<string, any>
|
||||
|
||||
constructor(context: ValidationContext, options: QueryComplexityOptions) {
|
||||
if (!(typeof options.maximumComplexity === 'number' && options.maximumComplexity > 0)) {
|
||||
throw new Error('Maximum query complexity must be a positive number')
|
||||
}
|
||||
|
||||
this.context = context
|
||||
this.complexity = 0
|
||||
this.options = options
|
||||
|
||||
this.includeDirectiveDef = this.context.getSchema().getDirective('include')
|
||||
this.skipDirectiveDef = this.context.getSchema().getDirective('skip')
|
||||
this.estimators = options.estimators
|
||||
this.variableValues = {}
|
||||
this.requestContext = options.context
|
||||
|
||||
this.OperationDefinition = {
|
||||
enter: this.onOperationDefinitionEnter,
|
||||
leave: this.onOperationDefinitionLeave,
|
||||
}
|
||||
}
|
||||
|
||||
createError(): GraphQLError {
|
||||
if (typeof this.options.createError === 'function') {
|
||||
return this.options.createError(this.options.maximumComplexity, this.complexity)
|
||||
}
|
||||
return new GraphQLError(queryComplexityMessage(this.options.maximumComplexity, this.complexity))
|
||||
}
|
||||
|
||||
nodeComplexity(
|
||||
node: FieldNode | FragmentDefinitionNode | InlineFragmentNode | OperationDefinitionNode,
|
||||
typeDef: GraphQLInterfaceType | GraphQLObjectType | GraphQLUnionType,
|
||||
): number {
|
||||
if (node.selectionSet) {
|
||||
let fields: GraphQLFieldMap<any, any> = {}
|
||||
if (typeDef instanceof GraphQLObjectType || typeDef instanceof GraphQLInterfaceType) {
|
||||
fields = typeDef.getFields()
|
||||
}
|
||||
|
||||
// Determine all possible types of the current node
|
||||
let possibleTypeNames: string[]
|
||||
if (isAbstractType(typeDef)) {
|
||||
possibleTypeNames = this.context
|
||||
.getSchema()
|
||||
.getPossibleTypes(typeDef)
|
||||
.map((t) => t.name)
|
||||
} else {
|
||||
possibleTypeNames = [typeDef.name]
|
||||
}
|
||||
|
||||
// Collect complexities for all possible types individually
|
||||
const selectionSetComplexities: ComplexityMap = node.selectionSet.selections.reduce(
|
||||
(
|
||||
complexities: ComplexityMap,
|
||||
childNode: FieldNode | FragmentSpreadNode | InlineFragmentNode,
|
||||
): ComplexityMap => {
|
||||
// let nodeComplexity = 0;
|
||||
let innerComplexities = complexities
|
||||
|
||||
let includeNode = true
|
||||
let skipNode = false
|
||||
|
||||
for (const directive of childNode.directives ?? []) {
|
||||
const directiveName = directive.name.value
|
||||
switch (directiveName) {
|
||||
case 'include': {
|
||||
const values = getDirectiveValues(
|
||||
this.includeDirectiveDef,
|
||||
childNode,
|
||||
this.variableValues || {},
|
||||
)
|
||||
if (typeof values.if === 'boolean') {
|
||||
includeNode = values.if
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'skip': {
|
||||
const values = getDirectiveValues(
|
||||
this.skipDirectiveDef,
|
||||
childNode,
|
||||
this.variableValues || {},
|
||||
)
|
||||
if (typeof values.if === 'boolean') {
|
||||
skipNode = values.if
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!includeNode || skipNode) {
|
||||
return complexities
|
||||
}
|
||||
|
||||
switch (childNode.kind) {
|
||||
case Kind.FIELD: {
|
||||
const field = fields[childNode.name.value]
|
||||
// Invalid field, should be caught by other validation rules
|
||||
if (!field) {
|
||||
break
|
||||
}
|
||||
const fieldType = getNamedType(field.type)
|
||||
|
||||
// Get arguments
|
||||
let args: { [key: string]: any }
|
||||
try {
|
||||
args = getArgumentValues(field, childNode, this.variableValues || {})
|
||||
} catch (e) {
|
||||
this.context.reportError(e)
|
||||
return complexities
|
||||
}
|
||||
|
||||
// Check if we have child complexity
|
||||
let childComplexity = 0
|
||||
if (isCompositeType(fieldType)) {
|
||||
childComplexity = this.nodeComplexity(childNode, fieldType)
|
||||
}
|
||||
|
||||
// Run estimators one after another and return first valid complexity
|
||||
// score
|
||||
const estimatorArgs: ComplexityEstimatorArgs = {
|
||||
type: typeDef,
|
||||
args,
|
||||
childComplexity,
|
||||
context: this.requestContext,
|
||||
field,
|
||||
node: childNode,
|
||||
}
|
||||
const validScore = this.estimators.find((estimator) => {
|
||||
const tmpComplexity = estimator(estimatorArgs)
|
||||
|
||||
if (typeof tmpComplexity === 'number' && !isNaN(tmpComplexity)) {
|
||||
innerComplexities = addComplexities(
|
||||
tmpComplexity,
|
||||
complexities,
|
||||
possibleTypeNames,
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
if (!validScore) {
|
||||
this.context.reportError(
|
||||
new GraphQLError(
|
||||
`No complexity could be calculated for field ${typeDef.name}.${field.name}. ` +
|
||||
'At least one complexity estimator has to return a complexity score.',
|
||||
),
|
||||
)
|
||||
return complexities
|
||||
}
|
||||
break
|
||||
}
|
||||
case Kind.FRAGMENT_SPREAD: {
|
||||
const fragment = this.context.getFragment(childNode.name.value)
|
||||
// Unknown fragment, should be caught by other validation rules
|
||||
if (!fragment) {
|
||||
break
|
||||
}
|
||||
const fragmentType = this.context
|
||||
.getSchema()
|
||||
.getType(fragment.typeCondition.name.value)
|
||||
// Invalid fragment type, ignore. Should be caught by other validation rules
|
||||
if (!isCompositeType(fragmentType)) {
|
||||
break
|
||||
}
|
||||
const nodeComplexity = this.nodeComplexity(fragment, fragmentType)
|
||||
if (isAbstractType(fragmentType)) {
|
||||
// Add fragment complexity for all possible types
|
||||
innerComplexities = addComplexities(
|
||||
nodeComplexity,
|
||||
complexities,
|
||||
this.context
|
||||
.getSchema()
|
||||
.getPossibleTypes(fragmentType)
|
||||
.map((t) => t.name),
|
||||
)
|
||||
} else {
|
||||
// Add complexity for object type
|
||||
innerComplexities = addComplexities(nodeComplexity, complexities, [
|
||||
fragmentType.name,
|
||||
])
|
||||
}
|
||||
break
|
||||
}
|
||||
case Kind.INLINE_FRAGMENT: {
|
||||
let inlineFragmentType: GraphQLNamedType = typeDef
|
||||
if (childNode.typeCondition && childNode.typeCondition.name) {
|
||||
inlineFragmentType = this.context
|
||||
.getSchema()
|
||||
.getType(childNode.typeCondition.name.value)
|
||||
if (!isCompositeType(inlineFragmentType)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const nodeComplexity = this.nodeComplexity(childNode, inlineFragmentType)
|
||||
if (isAbstractType(inlineFragmentType)) {
|
||||
// Add fragment complexity for all possible types
|
||||
innerComplexities = addComplexities(
|
||||
nodeComplexity,
|
||||
complexities,
|
||||
this.context
|
||||
.getSchema()
|
||||
.getPossibleTypes(inlineFragmentType)
|
||||
.map((t) => t.name),
|
||||
)
|
||||
} else {
|
||||
// Add complexity for object type
|
||||
innerComplexities = addComplexities(nodeComplexity, complexities, [
|
||||
inlineFragmentType.name,
|
||||
])
|
||||
}
|
||||
break
|
||||
}
|
||||
default: {
|
||||
innerComplexities = addComplexities(
|
||||
this.nodeComplexity(childNode, typeDef),
|
||||
complexities,
|
||||
possibleTypeNames,
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return innerComplexities
|
||||
},
|
||||
{},
|
||||
)
|
||||
// Only return max complexity of all possible types
|
||||
if (!selectionSetComplexities) {
|
||||
return NaN
|
||||
}
|
||||
return Math.max(...Object.values(selectionSetComplexities), 0)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
onOperationDefinitionEnter(operation: OperationDefinitionNode): void {
|
||||
if (
|
||||
typeof this.options.operationName === 'string' &&
|
||||
this.options.operationName !== operation.name.value
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// Get variable values from variables that are passed from options, merged
|
||||
// with default values defined in the operation
|
||||
const { coerced, errors } = getVariableValues(
|
||||
this.context.getSchema(),
|
||||
// We have to create a new array here because input argument is not readonly in graphql ~14.6.0
|
||||
operation.variableDefinitions ? [...operation.variableDefinitions] : [],
|
||||
this.options.variables ?? {},
|
||||
)
|
||||
if (errors && errors.length) {
|
||||
// We have input validation errors, report errors and abort
|
||||
errors.forEach((error) => this.context.reportError(error))
|
||||
return
|
||||
}
|
||||
this.variableValues = coerced
|
||||
|
||||
switch (operation.operation) {
|
||||
case 'query':
|
||||
this.complexity += this.nodeComplexity(operation, this.context.getSchema().getQueryType())
|
||||
break
|
||||
case 'mutation':
|
||||
this.complexity += this.nodeComplexity(
|
||||
operation,
|
||||
this.context.getSchema().getMutationType(),
|
||||
)
|
||||
break
|
||||
case 'subscription':
|
||||
this.complexity += this.nodeComplexity(
|
||||
operation,
|
||||
this.context.getSchema().getSubscriptionType(),
|
||||
)
|
||||
break
|
||||
default:
|
||||
throw new Error(
|
||||
`Query complexity could not be calculated for operation of type ${operation.operation}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
onOperationDefinitionLeave(operation: OperationDefinitionNode): GraphQLError | void {
|
||||
if (
|
||||
typeof this.options.operationName === 'string' &&
|
||||
this.options.operationName !== operation.name.value
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.options.onComplete) {
|
||||
this.options.onComplete(this.complexity)
|
||||
}
|
||||
|
||||
if (this.complexity > this.options.maximumComplexity) {
|
||||
return this.context.reportError(this.createError())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a complexity to the complexity map for all possible types
|
||||
* @param complexity
|
||||
* @param complexityMap
|
||||
* @param possibleTypes
|
||||
*/
|
||||
function addComplexities(
|
||||
complexity: number,
|
||||
complexityMap: ComplexityMap,
|
||||
possibleTypes: string[],
|
||||
): ComplexityMap {
|
||||
for (const type of possibleTypes) {
|
||||
if (Object.prototype.hasOwnProperty.call(complexityMap, type)) {
|
||||
complexityMap[type] += complexity
|
||||
} else {
|
||||
complexityMap[type] = complexity
|
||||
}
|
||||
}
|
||||
return complexityMap
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { ValidationContext } from 'graphql'
|
||||
|
||||
import type { QueryComplexityOptions } from './QueryComplexity.js'
|
||||
|
||||
import QueryComplexity from './QueryComplexity.js'
|
||||
|
||||
export function createComplexityRule(
|
||||
options: QueryComplexityOptions,
|
||||
): (context: ValidationContext) => QueryComplexity {
|
||||
return (context: ValidationContext): QueryComplexity => {
|
||||
return new QueryComplexity(context, options)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { ComplexityEstimator, ComplexityEstimatorArgs } from '../../QueryComplexity.js'
|
||||
|
||||
export const fieldExtensionsEstimator = (): ComplexityEstimator => {
|
||||
return (args: ComplexityEstimatorArgs): number | void => {
|
||||
if (args.field.extensions) {
|
||||
// Calculate complexity score
|
||||
if (typeof args.field.extensions.complexity === 'number') {
|
||||
return args.childComplexity + args.field.extensions.complexity
|
||||
} else if (typeof args.field.extensions.complexity === 'function') {
|
||||
return args.field.extensions.complexity(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { ComplexityEstimator, ComplexityEstimatorArgs } from '../../QueryComplexity.js'
|
||||
|
||||
export const simpleEstimator = (options?: { defaultComplexity?: number }): ComplexityEstimator => {
|
||||
const defaultComplexity =
|
||||
options && typeof options.defaultComplexity === 'number' ? options.defaultComplexity : 1
|
||||
return (args: ComplexityEstimatorArgs): number | void => {
|
||||
return defaultComplexity + args.childComplexity
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export { createComplexityRule } from './createComplexityRule.js'
|
||||
export { fieldExtensionsEstimator } from './estimators/fieldExtensions/index.js'
|
||||
export { simpleEstimator } from './estimators/simple/index.js'
|
||||
73
packages/graphql/src/packages/graphql-type-json/index.ts
Normal file
73
packages/graphql/src/packages/graphql-type-json/index.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { GraphQLScalarType } from 'graphql'
|
||||
import { Kind, print } from 'graphql/language'
|
||||
|
||||
function identity(value) {
|
||||
return value
|
||||
}
|
||||
|
||||
function ensureObject(value) {
|
||||
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
||||
throw new TypeError(`JSONObject cannot represent non-object value: ${value}`)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
function parseObject(typeName, ast, variables) {
|
||||
const value = Object.create(null)
|
||||
ast.fields.forEach((field) => {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
value[field.name.value] = parseLiteral(typeName, field.value, variables)
|
||||
})
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
function parseLiteral(typeName, ast, variables) {
|
||||
switch (ast.kind) {
|
||||
case Kind.STRING:
|
||||
case Kind.BOOLEAN:
|
||||
return ast.value
|
||||
case Kind.INT:
|
||||
case Kind.FLOAT:
|
||||
return parseFloat(ast.value)
|
||||
case Kind.OBJECT:
|
||||
return parseObject(typeName, ast, variables)
|
||||
case Kind.LIST:
|
||||
return ast.values.map((n) => parseLiteral(typeName, n, variables))
|
||||
case Kind.NULL:
|
||||
return null
|
||||
case Kind.VARIABLE:
|
||||
return variables ? variables[ast.name.value] : undefined
|
||||
default:
|
||||
throw new TypeError(`${typeName} cannot represent value: ${print(ast)}`)
|
||||
}
|
||||
}
|
||||
|
||||
// This named export is intended for users of CommonJS. Users of ES modules
|
||||
// should instead use the default export.
|
||||
export const GraphQLJSON = new GraphQLScalarType({
|
||||
name: 'JSON',
|
||||
description:
|
||||
'The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).',
|
||||
parseLiteral: (ast, variables) => parseLiteral('JSON', ast, variables),
|
||||
parseValue: identity,
|
||||
serialize: identity,
|
||||
specifiedByURL: 'http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf',
|
||||
})
|
||||
|
||||
export const GraphQLJSONObject = new GraphQLScalarType({
|
||||
name: 'JSONObject',
|
||||
description:
|
||||
'The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).',
|
||||
parseLiteral: (ast, variables) => {
|
||||
if (ast.kind !== Kind.OBJECT) {
|
||||
throw new TypeError(`JSONObject cannot represent non-object value: ${print(ast)}`)
|
||||
}
|
||||
|
||||
return parseObject('JSONObject', ast, variables)
|
||||
},
|
||||
parseValue: ensureObject,
|
||||
serialize: ensureObject,
|
||||
specifiedByURL: 'http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf',
|
||||
})
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
import type { GraphQLInputFieldConfig, GraphQLScalarType, GraphQLType } from 'graphql'
|
||||
import type { GraphQLInfo } from 'payload/config'
|
||||
import type {
|
||||
@@ -37,11 +36,11 @@ import {
|
||||
GraphQLNonNull,
|
||||
GraphQLString,
|
||||
} from 'graphql'
|
||||
import { GraphQLJSON } from 'graphql-type-json'
|
||||
import { fieldAffectsData, optionIsObject, tabHasName } from 'payload/types'
|
||||
import { toWords } from 'payload/utilities'
|
||||
import { flattenTopLevelFields } from 'payload/utilities'
|
||||
|
||||
import { GraphQLJSON } from '../packages/graphql-type-json/index.js'
|
||||
import combineParentName from '../utilities/combineParentName.js'
|
||||
import formatName from '../utilities/formatName.js'
|
||||
import { groupOrTabHasRequiredSubfield } from '../utilities/groupOrTabHasRequiredSubfield.js'
|
||||
|
||||
@@ -41,13 +41,12 @@ import {
|
||||
GraphQLUnionType,
|
||||
} from 'graphql'
|
||||
import { DateTimeResolver, EmailAddressResolver } from 'graphql-scalars'
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { GraphQLJSON } from 'graphql-type-json'
|
||||
import { tabHasName } from 'payload/types'
|
||||
import { toWords } from 'payload/utilities'
|
||||
|
||||
import type { Context } from '../resolvers/types.js'
|
||||
|
||||
import { GraphQLJSON } from '../packages/graphql-type-json/index.js'
|
||||
import combineParentName from '../utilities/combineParentName.js'
|
||||
import formatName from '../utilities/formatName.js'
|
||||
import formatOptions from '../utilities/formatOptions.js'
|
||||
@@ -301,7 +300,7 @@ function buildObjectType({
|
||||
value: {
|
||||
type: new GraphQLUnionType({
|
||||
name: relationshipName,
|
||||
async resolveType(data, { req }) {
|
||||
resolveType(data, { req }) {
|
||||
return graphqlResult.collections[data.collection].graphQL.type.name
|
||||
},
|
||||
types,
|
||||
|
||||
@@ -8,9 +8,9 @@ import type {
|
||||
} from 'payload/types'
|
||||
|
||||
import { GraphQLBoolean, GraphQLNonNull, GraphQLObjectType } from 'graphql'
|
||||
import { GraphQLJSONObject } from 'graphql-type-json'
|
||||
import { toWords } from 'payload/utilities'
|
||||
|
||||
import { GraphQLJSONObject } from '../packages/graphql-type-json/index.js'
|
||||
import formatName from '../utilities/formatName.js'
|
||||
|
||||
type OperationType = 'create' | 'delete' | 'read' | 'readVersions' | 'unlock' | 'update'
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-use-before-define */
|
||||
import type { Field, FieldAffectingData } from 'payload/types'
|
||||
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { GraphQLInputObjectType, GraphQLList } from 'graphql'
|
||||
import { fieldAffectsData, fieldHasSubFields, fieldIsPresentationalOnly } from 'payload/types'
|
||||
import { flattenTopLevelFields } from 'payload/utilities'
|
||||
|
||||
@@ -21,16 +21,13 @@ import type {
|
||||
} from 'payload/types'
|
||||
|
||||
import { GraphQLEnumType, GraphQLInputObjectType } from 'graphql'
|
||||
import GraphQLJSONImport from 'graphql-type-json'
|
||||
|
||||
import { GraphQLJSON } from '../packages/graphql-type-json/index.js'
|
||||
import combineParentName from '../utilities/combineParentName.js'
|
||||
import formatName from '../utilities/formatName.js'
|
||||
import recursivelyBuildNestedPaths from './recursivelyBuildNestedPaths.js'
|
||||
import { withOperators } from './withOperators.js'
|
||||
|
||||
const GraphQLJSON = (GraphQLJSONImport ||
|
||||
GraphQLJSONImport.default) as unknown as typeof GraphQLJSONImport.default
|
||||
|
||||
type Args = {
|
||||
nestedFieldName?: string
|
||||
parentName: string
|
||||
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
GraphQLString,
|
||||
} from 'graphql'
|
||||
import { DateTimeResolver, EmailAddressResolver } from 'graphql-scalars'
|
||||
import { GraphQLJSON } from 'graphql-type-json'
|
||||
import { optionIsObject } from 'payload/types'
|
||||
|
||||
import { GraphQLJSON } from '../packages/graphql-type-json/index.js'
|
||||
import combineParentName from '../utilities/combineParentName.js'
|
||||
import formatName from '../utilities/formatName.js'
|
||||
import operators from './operators.js'
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
"@types/ws": "^8.5.10",
|
||||
"css-loader": "^6.10.0",
|
||||
"css-minimizer-webpack-plugin": "^6.0.0",
|
||||
"file-type": "16.5.4",
|
||||
"graphql-http": "^1.22.0",
|
||||
"mini-css-extract-plugin": "1.6.2",
|
||||
"payload": "workspace:*",
|
||||
"postcss-loader": "^8.1.1",
|
||||
@@ -55,8 +57,7 @@
|
||||
"swc-plugin-transform-remove-imports": "^1.12.1",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"webpack": "^5.78.0",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"file-type": "16.5.4"
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "6.0.8",
|
||||
@@ -66,8 +67,6 @@
|
||||
"@types/busboy": "^1.5.3",
|
||||
"busboy": "^1.6.0",
|
||||
"deep-equal": "2.2.2",
|
||||
"graphql": "16.8.1",
|
||||
"graphql-http": "^1.22.0",
|
||||
"graphql-playground-html": "1.6.30",
|
||||
"path-to-regexp": "^6.2.1",
|
||||
"qs": "6.11.2",
|
||||
@@ -77,10 +76,11 @@
|
||||
"ws": "^8.16.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"file-type": "16.5.4",
|
||||
"http-status": "1.6.2",
|
||||
"next": "^14.3.0-canary.7",
|
||||
"payload": "workspace:*",
|
||||
"file-type": "16.5.4"
|
||||
"graphql": "^16.8.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { GraphQLFormattedError } from 'graphql'
|
||||
import type { GraphQLError } from 'graphql'
|
||||
import type { GraphQLError, GraphQLFormattedError } from 'graphql'
|
||||
import type { CollectionAfterErrorHook, Payload, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { configToSchema } from '@payloadcms/graphql'
|
||||
@@ -65,7 +64,7 @@ export const getGraphql = async (config: Promise<SanitizedConfig> | SanitizedCon
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
cached.promise = new Promise(async (resolve) => {
|
||||
const resolvedConfig = await config
|
||||
const schema = await configToSchema(resolvedConfig)
|
||||
const schema = configToSchema(resolvedConfig)
|
||||
resolve(schema)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ export const withPayload = (nextConfig = {}) => {
|
||||
'libsql',
|
||||
'pino',
|
||||
'pino-pretty',
|
||||
'graphql',
|
||||
],
|
||||
},
|
||||
webpack: (webpackConfig, webpackOptions) => {
|
||||
|
||||
@@ -69,7 +69,8 @@
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/core": "^1.4.13"
|
||||
"@swc/core": "^1.4.13",
|
||||
"graphql": "^16.8.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/core": {
|
||||
@@ -109,7 +110,6 @@
|
||||
"file-loader": "6.2.0",
|
||||
"form-data": "3.0.1",
|
||||
"get-port": "5.1.1",
|
||||
"graphql": "16.8.1",
|
||||
"graphql-http": "^1.22.0",
|
||||
"mini-css-extract-plugin": "1.6.2",
|
||||
"nodemon": "3.0.3",
|
||||
|
||||
@@ -15,7 +15,6 @@ import type {
|
||||
RichTextAdapter,
|
||||
RowLabel,
|
||||
} from '../../admin/types.js'
|
||||
import type { User } from '../../auth/index.js'
|
||||
import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types.js'
|
||||
import type { CustomComponent, LabelFunction } from '../../config/types.js'
|
||||
import type { DBIdentifierName } from '../../database/types.js'
|
||||
|
||||
45
pnpm-lock.yaml
generated
45
pnpm-lock.yaml
generated
@@ -548,21 +548,9 @@ importers:
|
||||
graphql:
|
||||
specifier: ^16.8.1
|
||||
version: 16.8.1
|
||||
graphql-http:
|
||||
specifier: ^1.22.0
|
||||
version: 1.22.0(graphql@16.8.1)
|
||||
graphql-playground-html:
|
||||
specifier: 1.6.30
|
||||
version: 1.6.30
|
||||
graphql-query-complexity:
|
||||
specifier: 0.12.0
|
||||
version: 0.12.0(graphql@16.8.1)
|
||||
graphql-scalars:
|
||||
specifier: 1.22.2
|
||||
version: 1.22.2(graphql@16.8.1)
|
||||
graphql-type-json:
|
||||
specifier: 0.3.2
|
||||
version: 0.3.2(graphql@16.8.1)
|
||||
pluralize:
|
||||
specifier: 8.0.0
|
||||
version: 8.0.0
|
||||
@@ -573,6 +561,9 @@ importers:
|
||||
'@types/pluralize':
|
||||
specifier: ^0.0.33
|
||||
version: 0.0.33
|
||||
graphql-http:
|
||||
specifier: ^1.22.0
|
||||
version: 1.22.0(graphql@16.8.1)
|
||||
payload:
|
||||
specifier: workspace:*
|
||||
version: link:../payload
|
||||
@@ -650,9 +641,6 @@ importers:
|
||||
graphql:
|
||||
specifier: ^16.8.1
|
||||
version: 16.8.1
|
||||
graphql-http:
|
||||
specifier: ^1.22.0
|
||||
version: 1.22.0(graphql@16.8.1)
|
||||
graphql-playground-html:
|
||||
specifier: 1.6.30
|
||||
version: 1.6.30
|
||||
@@ -705,6 +693,9 @@ importers:
|
||||
file-type:
|
||||
specifier: 16.5.4
|
||||
version: 16.5.4
|
||||
graphql-http:
|
||||
specifier: ^1.22.0
|
||||
version: 1.22.0(graphql@16.8.1)
|
||||
mini-css-extract-plugin:
|
||||
specifier: 1.6.2
|
||||
version: 1.6.2(webpack@5.91.0)
|
||||
@@ -783,6 +774,9 @@ importers:
|
||||
get-tsconfig:
|
||||
specifier: ^4.7.2
|
||||
version: 4.7.3
|
||||
graphql:
|
||||
specifier: ^16.8.1
|
||||
version: 16.8.1
|
||||
http-status:
|
||||
specifier: 1.6.2
|
||||
version: 1.6.2
|
||||
@@ -925,9 +919,6 @@ importers:
|
||||
get-port:
|
||||
specifier: 5.1.1
|
||||
version: 5.1.1
|
||||
graphql:
|
||||
specifier: ^16.8.1
|
||||
version: 16.8.1
|
||||
graphql-http:
|
||||
specifier: ^1.22.0
|
||||
version: 1.22.0(graphql@16.8.1)
|
||||
@@ -10322,6 +10313,7 @@ packages:
|
||||
graphql: ^16.8.1
|
||||
dependencies:
|
||||
graphql: 16.8.1
|
||||
dev: true
|
||||
|
||||
/graphql-playground-html@1.6.30:
|
||||
resolution: {integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==}
|
||||
@@ -10329,15 +10321,6 @@ packages:
|
||||
xss: 1.0.15
|
||||
dev: false
|
||||
|
||||
/graphql-query-complexity@0.12.0(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-fWEyuSL6g/+nSiIRgIipfI6UXTI7bAxrpPlCY1c0+V3pAEUo1ybaKmSBgNr1ed2r+agm1plJww8Loig9y6s2dw==}
|
||||
peerDependencies:
|
||||
graphql: ^16.8.1
|
||||
dependencies:
|
||||
graphql: 16.8.1
|
||||
lodash.get: 4.4.2
|
||||
dev: false
|
||||
|
||||
/graphql-scalars@1.22.2(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -10348,14 +10331,6 @@ packages:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/graphql-type-json@0.3.2(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==}
|
||||
peerDependencies:
|
||||
graphql: ^16.8.1
|
||||
dependencies:
|
||||
graphql: 16.8.1
|
||||
dev: false
|
||||
|
||||
/graphql@16.8.1:
|
||||
resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==}
|
||||
engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
|
||||
|
||||
Reference in New Issue
Block a user