@strapi/plugin-graphql 4.0.0-next.8 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/admin/src/index.js +0 -8
- package/package.json +43 -35
- package/server/bootstrap.js +148 -0
- package/server/config/default-config.js +13 -0
- package/server/config/index.js +7 -0
- package/server/format-graphql-error.js +50 -0
- package/server/services/builders/dynamic-zones.js +97 -0
- package/server/services/builders/entity-meta.js +7 -0
- package/server/services/builders/entity.js +43 -0
- package/server/services/builders/enums.js +24 -0
- package/server/services/builders/filters/content-type.js +93 -0
- package/server/services/builders/filters/index.js +7 -0
- package/server/services/builders/filters/operators/and.js +15 -0
- package/server/services/builders/filters/operators/between.js +15 -0
- package/server/services/builders/filters/operators/contains.js +13 -0
- package/server/services/builders/filters/operators/containsi.js +13 -0
- package/server/services/builders/filters/operators/ends-with.js +13 -0
- package/server/services/builders/filters/operators/eq.js +23 -0
- package/server/services/builders/filters/operators/gt.js +13 -0
- package/server/services/builders/filters/operators/gte.js +13 -0
- package/server/services/builders/filters/operators/in.js +15 -0
- package/server/services/builders/filters/operators/index.js +38 -0
- package/server/services/builders/filters/operators/lt.js +13 -0
- package/server/services/builders/filters/operators/lte.js +13 -0
- package/server/services/builders/filters/operators/ne.js +13 -0
- package/server/services/builders/filters/operators/not-contains.js +13 -0
- package/server/services/builders/filters/operators/not-containsi.js +13 -0
- package/server/services/builders/filters/operators/not-in.js +15 -0
- package/server/services/builders/filters/operators/not-null.js +13 -0
- package/server/services/builders/filters/operators/not.js +19 -0
- package/server/services/builders/filters/operators/null.js +13 -0
- package/server/services/builders/filters/operators/or.js +15 -0
- package/server/services/builders/filters/operators/starts-with.js +13 -0
- package/server/services/builders/generic-morph.js +41 -0
- package/server/services/builders/index.js +92 -0
- package/server/services/builders/input.js +121 -0
- package/server/services/builders/mutations/collection-type.js +191 -0
- package/server/services/builders/mutations/index.js +9 -0
- package/server/services/builders/mutations/single-type.js +141 -0
- package/server/services/builders/queries/collection-type.js +120 -0
- package/server/services/builders/queries/index.js +9 -0
- package/server/services/builders/queries/single-type.js +70 -0
- package/server/services/builders/relation-response-collection.js +35 -0
- package/server/services/builders/resolvers/association.js +85 -0
- package/server/services/builders/resolvers/component.js +18 -0
- package/server/services/builders/resolvers/dynamic-zone.js +9 -0
- package/server/services/builders/resolvers/index.js +18 -0
- package/server/services/builders/resolvers/mutation.js +33 -0
- package/server/services/builders/resolvers/query.js +19 -0
- package/server/services/builders/response-collection.js +43 -0
- package/server/services/builders/response.js +32 -0
- package/server/services/builders/type.js +364 -0
- package/server/services/builders/utils.js +134 -0
- package/server/services/constants.js +149 -0
- package/server/services/content-api/index.js +179 -0
- package/server/services/content-api/policy.js +60 -0
- package/server/services/content-api/register-functions/collection-type.js +72 -0
- package/server/services/content-api/register-functions/component.js +15 -0
- package/server/services/content-api/register-functions/content-type/dynamic-zones.js +36 -0
- package/server/services/content-api/register-functions/content-type/enums.js +33 -0
- package/server/services/content-api/register-functions/content-type/filters.js +15 -0
- package/server/services/content-api/register-functions/content-type/index.js +13 -0
- package/server/services/content-api/register-functions/content-type/inputs.js +21 -0
- package/server/services/content-api/register-functions/index.js +22 -0
- package/server/services/content-api/register-functions/internals.js +13 -0
- package/server/services/content-api/register-functions/polymorphic.js +69 -0
- package/server/services/content-api/register-functions/scalars.js +14 -0
- package/server/services/content-api/register-functions/single-type.js +72 -0
- package/server/services/content-api/wrap-resolvers.js +144 -0
- package/server/services/extension/extension.js +95 -0
- package/server/services/extension/index.js +5 -0
- package/server/services/extension/shadow-crud-manager.js +159 -0
- package/server/services/format/index.js +7 -0
- package/server/services/format/return-types.js +27 -0
- package/server/services/index.js +21 -0
- package/server/services/internals/args/index.js +11 -0
- package/server/services/internals/args/pagination.js +19 -0
- package/server/services/internals/args/publication-state.js +12 -0
- package/server/services/internals/args/sort.js +10 -0
- package/server/services/internals/helpers/get-enabled-scalars.js +15 -0
- package/server/services/internals/helpers/index.js +7 -0
- package/server/services/internals/index.js +13 -0
- package/server/services/internals/scalars/index.js +18 -0
- package/server/services/internals/scalars/time.js +36 -0
- package/server/services/internals/types/error.js +34 -0
- package/server/services/internals/types/filters.js +39 -0
- package/server/services/internals/types/index.js +29 -0
- package/server/services/internals/types/pagination.js +24 -0
- package/server/services/internals/types/publication-state.js +24 -0
- package/server/services/internals/types/response-collection-meta.js +39 -0
- package/server/services/type-registry.js +104 -0
- package/server/services/utils/attributes.js +84 -0
- package/server/services/utils/index.js +11 -0
- package/server/services/utils/mappers/entity-to-response-entity.js +12 -0
- package/server/services/utils/mappers/graphql-filters-to-strapi-query.js +109 -0
- package/server/services/utils/mappers/graphql-scalar-to-operators.js +17 -0
- package/server/services/utils/mappers/index.js +13 -0
- package/server/services/utils/mappers/strapi-scalar-to-graphql-scalar.js +25 -0
- package/server/services/utils/naming.js +287 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +7 -9
- package/admin/src/assets/images/logo.svg +0 -38
- package/config/routes.json +0 -3
- package/config/schema.graphql +0 -1
- package/config/settings.json +0 -12
- package/controllers/GraphQL.js +0 -9
- package/hooks/graphql/defaults.json +0 -5
- package/hooks/graphql/index.js +0 -174
- package/hooks/graphql/load-config.js +0 -42
- package/services/build-aggregation.js +0 -565
- package/services/data-loaders.js +0 -55
- package/services/naming.js +0 -15
- package/services/resolvers-builder.js +0 -204
- package/services/schema-definitions.js +0 -131
- package/services/schema-generator.js +0 -178
- package/services/shadow-crud.js +0 -612
- package/services/type-builder.js +0 -311
- package/services/utils.js +0 -200
- package/types/dynamiczoneScalar.js +0 -40
- package/types/publication-state.js +0 -16
- package/types/time.js +0 -26
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { unionType } = require('nexus');
|
|
4
|
+
|
|
5
|
+
const registerPolymorphicContentType = (contentType, { registry, strapi }) => {
|
|
6
|
+
const { service: getService } = strapi.plugin('graphql');
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
naming,
|
|
10
|
+
attributes: { isMorphRelation },
|
|
11
|
+
} = getService('utils');
|
|
12
|
+
const { KINDS } = getService('constants');
|
|
13
|
+
|
|
14
|
+
const { attributes = {} } = contentType;
|
|
15
|
+
|
|
16
|
+
// Isolate its polymorphic attributes
|
|
17
|
+
const morphAttributes = Object.entries(attributes).filter(([, attribute]) =>
|
|
18
|
+
isMorphRelation(attribute)
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
// For each one of those polymorphic attribute
|
|
22
|
+
for (const [attributeName, attribute] of morphAttributes) {
|
|
23
|
+
const name = naming.getMorphRelationTypeName(contentType, attributeName);
|
|
24
|
+
const { target } = attribute;
|
|
25
|
+
|
|
26
|
+
// Ignore those whose target is not an array
|
|
27
|
+
if (!Array.isArray(target)) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Transform target UIDs into types names
|
|
32
|
+
const members = target
|
|
33
|
+
// Get content types definitions
|
|
34
|
+
.map(uid => strapi.getModel(uid))
|
|
35
|
+
// Resolve types names
|
|
36
|
+
.map(contentType => naming.getTypeName(contentType));
|
|
37
|
+
|
|
38
|
+
// Register the new polymorphic union type
|
|
39
|
+
registry.register(
|
|
40
|
+
name,
|
|
41
|
+
|
|
42
|
+
unionType({
|
|
43
|
+
name,
|
|
44
|
+
|
|
45
|
+
resolveType(obj) {
|
|
46
|
+
const contentType = strapi.getModel(obj.__type);
|
|
47
|
+
|
|
48
|
+
if (!contentType) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (contentType.modelType === 'component') {
|
|
53
|
+
return naming.getComponentName(contentType);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return naming.getTypeName(contentType);
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
definition(t) {
|
|
60
|
+
t.members(...members);
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
|
|
64
|
+
{ kind: KINDS.morph, contentType, attributeName }
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
module.exports = { registerPolymorphicContentType };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const registerScalars = ({ registry, strapi }) => {
|
|
4
|
+
const { service: getService } = strapi.plugin('graphql');
|
|
5
|
+
|
|
6
|
+
const { scalars } = getService('internals');
|
|
7
|
+
const { KINDS } = getService('constants');
|
|
8
|
+
|
|
9
|
+
Object.entries(scalars).forEach(([name, definition]) => {
|
|
10
|
+
registry.register(name, definition, { kind: KINDS.scalar });
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
module.exports = { registerScalars };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const registerSingleType = (contentType, { registry, strapi, builders }) => {
|
|
4
|
+
const { service: getService } = strapi.plugin('graphql');
|
|
5
|
+
|
|
6
|
+
const { naming } = getService('utils');
|
|
7
|
+
const { KINDS } = getService('constants');
|
|
8
|
+
|
|
9
|
+
const extension = getService('extension');
|
|
10
|
+
|
|
11
|
+
const types = {
|
|
12
|
+
base: naming.getTypeName(contentType),
|
|
13
|
+
entity: naming.getEntityName(contentType),
|
|
14
|
+
response: naming.getEntityResponseName(contentType),
|
|
15
|
+
responseCollection: naming.getEntityResponseCollectionName(contentType),
|
|
16
|
+
relationResponseCollection: naming.getRelationResponseCollectionName(contentType),
|
|
17
|
+
queries: naming.getEntityQueriesTypeName(contentType),
|
|
18
|
+
mutations: naming.getEntityMutationsTypeName(contentType),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const getConfig = kind => ({ kind, contentType });
|
|
22
|
+
|
|
23
|
+
// Single type's definition
|
|
24
|
+
registry.register(types.base, builders.buildTypeDefinition(contentType), getConfig(KINDS.type));
|
|
25
|
+
|
|
26
|
+
// Higher level entity definition
|
|
27
|
+
registry.register(
|
|
28
|
+
types.entity,
|
|
29
|
+
builders.buildEntityDefinition(contentType),
|
|
30
|
+
getConfig(KINDS.entity)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// Responses definition
|
|
34
|
+
registry.register(
|
|
35
|
+
types.response,
|
|
36
|
+
builders.buildResponseDefinition(contentType),
|
|
37
|
+
getConfig(KINDS.entityResponse)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Response collection definition
|
|
41
|
+
registry.register(
|
|
42
|
+
types.responseCollection,
|
|
43
|
+
builders.buildResponseCollectionDefinition(contentType),
|
|
44
|
+
getConfig(KINDS.entityResponseCollection)
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
registry.register(
|
|
48
|
+
types.relationResponseCollection,
|
|
49
|
+
builders.buildRelationResponseCollectionDefinition(contentType),
|
|
50
|
+
getConfig(KINDS.relationResponseCollection)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
if (extension.shadowCRUD(contentType.uid).areQueriesEnabled()) {
|
|
54
|
+
// Queries
|
|
55
|
+
registry.register(
|
|
56
|
+
types.queries,
|
|
57
|
+
builders.buildSingleTypeQueries(contentType),
|
|
58
|
+
getConfig(KINDS.query)
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (extension.shadowCRUD(contentType.uid).areMutationsEnabled()) {
|
|
63
|
+
// Mutations
|
|
64
|
+
registry.register(
|
|
65
|
+
types.mutations,
|
|
66
|
+
builders.buildSingleTypeMutations(contentType),
|
|
67
|
+
getConfig(KINDS.mutation)
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
module.exports = { registerSingleType };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { get, getOr, isFunction, first, isNil } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { GraphQLObjectType } = require('graphql');
|
|
6
|
+
const { ForbiddenError } = require('@strapi/utils').errors;
|
|
7
|
+
const { createPoliciesMiddleware } = require('./policy');
|
|
8
|
+
|
|
9
|
+
const introspectionQueries = [
|
|
10
|
+
'__Schema',
|
|
11
|
+
'__Type',
|
|
12
|
+
'__Field',
|
|
13
|
+
'__InputValue',
|
|
14
|
+
'__EnumValue',
|
|
15
|
+
'__Directive',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Wrap the schema's resolvers if they've been
|
|
20
|
+
* customized using the GraphQL extension service
|
|
21
|
+
* @param {object} options
|
|
22
|
+
* @param {GraphQLSchema} options.schema
|
|
23
|
+
* @param {object} options.strapi
|
|
24
|
+
* @param {object} options.extension
|
|
25
|
+
* @return {GraphQLSchema}
|
|
26
|
+
*/
|
|
27
|
+
const wrapResolvers = ({ schema, strapi, extension = {} }) => {
|
|
28
|
+
// Get all the registered resolvers configuration
|
|
29
|
+
const { resolversConfig = {} } = extension;
|
|
30
|
+
|
|
31
|
+
// Fields filters
|
|
32
|
+
const isValidFieldName = ([field]) => !field.startsWith('__');
|
|
33
|
+
|
|
34
|
+
const typeMap = schema.getTypeMap();
|
|
35
|
+
|
|
36
|
+
Object.entries(typeMap).forEach(([type, definition]) => {
|
|
37
|
+
const isGraphQLObjectType = definition instanceof GraphQLObjectType;
|
|
38
|
+
const isIgnoredType = introspectionQueries.includes(type);
|
|
39
|
+
|
|
40
|
+
if (!isGraphQLObjectType || isIgnoredType) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const fields = definition.getFields();
|
|
45
|
+
const fieldsToProcess = Object.entries(fields).filter(isValidFieldName);
|
|
46
|
+
|
|
47
|
+
for (const [fieldName, fieldDefinition] of fieldsToProcess) {
|
|
48
|
+
const defaultResolver = get(fieldName);
|
|
49
|
+
|
|
50
|
+
const path = `${type}.${fieldName}`;
|
|
51
|
+
const resolverConfig = getOr({}, path, resolversConfig);
|
|
52
|
+
|
|
53
|
+
const { resolve: baseResolver = defaultResolver } = fieldDefinition;
|
|
54
|
+
|
|
55
|
+
// Parse & initialize the middlewares
|
|
56
|
+
const middlewares = parseMiddlewares(resolverConfig, strapi);
|
|
57
|
+
|
|
58
|
+
// Generate the policy middleware
|
|
59
|
+
const policyMiddleware = createPoliciesMiddleware(resolverConfig, { strapi });
|
|
60
|
+
|
|
61
|
+
// Add the policyMiddleware at the end of the middlewares collection
|
|
62
|
+
middlewares.push(policyMiddleware);
|
|
63
|
+
|
|
64
|
+
// Bind every middleware to the next one
|
|
65
|
+
const boundMiddlewares = middlewares.map((middleware, index, collection) => {
|
|
66
|
+
return (...args) =>
|
|
67
|
+
middleware(
|
|
68
|
+
// Make sure the last middleware in the list calls the baseResolver
|
|
69
|
+
index >= collection.length - 1 ? baseResolver : boundMiddlewares[index + 1],
|
|
70
|
+
...args
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* GraphQL authorization flow
|
|
76
|
+
* @param {object} context
|
|
77
|
+
* @return {Promise<void>}
|
|
78
|
+
*/
|
|
79
|
+
const authorize = async ({ context }) => {
|
|
80
|
+
const authConfig = get('auth', resolverConfig);
|
|
81
|
+
const authContext = get('state.auth', context);
|
|
82
|
+
|
|
83
|
+
const isValidType = ['Mutation', 'Query', 'Subscription'].includes(type);
|
|
84
|
+
const hasConfig = !isNil(authConfig);
|
|
85
|
+
|
|
86
|
+
const isAuthDisabled = authConfig === false;
|
|
87
|
+
|
|
88
|
+
if ((isValidType || hasConfig) && !isAuthDisabled) {
|
|
89
|
+
try {
|
|
90
|
+
await strapi.auth.verify(authContext, authConfig);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
throw new ForbiddenError();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Base resolver wrapper that handles authorization, middlewares & policies
|
|
99
|
+
* @param {object} parent
|
|
100
|
+
* @param {object} args
|
|
101
|
+
* @param {object} context
|
|
102
|
+
* @param {object} info
|
|
103
|
+
* @return {Promise<any>}
|
|
104
|
+
*/
|
|
105
|
+
fieldDefinition.resolve = async (parent, args, context, info) => {
|
|
106
|
+
await authorize({ context });
|
|
107
|
+
|
|
108
|
+
// Execute middlewares (including the policy middleware which will always be included)
|
|
109
|
+
return first(boundMiddlewares).call(null, parent, args, context, info);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return schema;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get & parse middlewares definitions from the resolver's config
|
|
119
|
+
* @param {object} resolverConfig
|
|
120
|
+
* @param {object} strapi
|
|
121
|
+
* @return {function[]}
|
|
122
|
+
*/
|
|
123
|
+
const parseMiddlewares = (resolverConfig, strapi) => {
|
|
124
|
+
const resolverMiddlewares = getOr([], 'middlewares', resolverConfig);
|
|
125
|
+
|
|
126
|
+
// TODO: [v4] to factorize with compose endpoints (routes)
|
|
127
|
+
return resolverMiddlewares.map(middleware => {
|
|
128
|
+
if (isFunction(middleware)) {
|
|
129
|
+
return middleware;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (typeof middleware === 'string') {
|
|
133
|
+
return strapi.middleware(middleware);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (typeof middleware === 'object') {
|
|
137
|
+
const { name, options = {} } = middleware;
|
|
138
|
+
|
|
139
|
+
return strapi.middleware(name)(options);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
module.exports = { wrapResolvers };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const nexus = require('nexus');
|
|
4
|
+
const { merge } = require('lodash/fp');
|
|
5
|
+
|
|
6
|
+
const createShadowCRUDManager = require('./shadow-crud-manager');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef StrapiGraphQLExtensionConfiguration
|
|
10
|
+
* @property {NexusGen[]} types - A collection of Nexus types
|
|
11
|
+
* @property {string} typeDefs - Type definitions (SDL format)
|
|
12
|
+
* @property {object} resolvers - A resolver map
|
|
13
|
+
* @property {object} resolversConfig - An object that bind a configuration to a resolver based on an absolute path (the key)
|
|
14
|
+
* @property {NexusPlugin[]} plugins - A collection of Nexus plugins
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {function({ strapi: object, nexus: object, typeRegistry: object }): StrapiGraphQLExtensionConfiguration} StrapiGraphQLExtensionConfigurationFactory
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const getDefaultState = () => ({
|
|
22
|
+
types: [],
|
|
23
|
+
typeDefs: [],
|
|
24
|
+
resolvers: {},
|
|
25
|
+
resolversConfig: {},
|
|
26
|
+
plugins: [],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const createExtension = ({ strapi } = {}) => {
|
|
30
|
+
const configs = [];
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
shadowCRUD: createShadowCRUDManager({ strapi }),
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Register a new extension configuration
|
|
37
|
+
* @param {StrapiGraphQLExtensionConfiguration | StrapiGraphQLExtensionConfigurationFactory} configuration
|
|
38
|
+
* @return {this}
|
|
39
|
+
*/
|
|
40
|
+
use(configuration) {
|
|
41
|
+
configs.push(configuration);
|
|
42
|
+
|
|
43
|
+
return this;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Convert the registered configuration into a single extension object & return it
|
|
48
|
+
* @param {object} options
|
|
49
|
+
* @param {object} options.typeRegistry
|
|
50
|
+
* @return {object}
|
|
51
|
+
*/
|
|
52
|
+
generate({ typeRegistry }) {
|
|
53
|
+
const resolveConfig = config => {
|
|
54
|
+
return typeof config === 'function' ? config({ strapi, nexus, typeRegistry }) : config;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Evaluate & merge every registered configuration object, then return the result
|
|
58
|
+
return configs.reduce((acc, configuration) => {
|
|
59
|
+
const { types, typeDefs, resolvers, resolversConfig, plugins } = resolveConfig(
|
|
60
|
+
configuration
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Register type definitions
|
|
64
|
+
if (typeof typeDefs === 'string') {
|
|
65
|
+
acc.typeDefs.push(typeDefs);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Register nexus types
|
|
69
|
+
if (Array.isArray(types)) {
|
|
70
|
+
acc.types.push(...types);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Register nexus plugins
|
|
74
|
+
if (Array.isArray(plugins)) {
|
|
75
|
+
acc.plugins.push(...plugins);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Register resolvers
|
|
79
|
+
if (typeof resolvers === 'object') {
|
|
80
|
+
acc.resolvers = merge(acc.resolvers, resolvers);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Register resolvers configuration
|
|
84
|
+
if (typeof resolversConfig === 'object') {
|
|
85
|
+
// TODO: smarter merge for auth, middlewares & policies
|
|
86
|
+
acc.resolversConfig = merge(resolversConfig, acc.resolversConfig);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return acc;
|
|
90
|
+
}, getDefaultState());
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
module.exports = createExtension;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const getDefaultContentTypeConfig = () => ({
|
|
4
|
+
enabled: true,
|
|
5
|
+
|
|
6
|
+
mutations: true,
|
|
7
|
+
queries: true,
|
|
8
|
+
|
|
9
|
+
disabledActions: [],
|
|
10
|
+
fields: new Map(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const getDefaultFieldConfig = () => ({
|
|
14
|
+
enabled: true,
|
|
15
|
+
|
|
16
|
+
input: true,
|
|
17
|
+
output: true,
|
|
18
|
+
|
|
19
|
+
filters: true,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const ALL_ACTIONS = '*';
|
|
23
|
+
|
|
24
|
+
module.exports = () => {
|
|
25
|
+
const configs = new Map();
|
|
26
|
+
|
|
27
|
+
return uid => {
|
|
28
|
+
if (!configs.has(uid)) {
|
|
29
|
+
configs.set(uid, getDefaultContentTypeConfig());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
isEnabled() {
|
|
34
|
+
return configs.get(uid).enabled;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
isDisabled() {
|
|
38
|
+
return !this.isEnabled();
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
areQueriesEnabled() {
|
|
42
|
+
return configs.get(uid).queries;
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
areQueriesDisabled() {
|
|
46
|
+
return !this.areQueriesEnabled();
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
areMutationsEnabled() {
|
|
50
|
+
return configs.get(uid).mutations;
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
areMutationsDisabled() {
|
|
54
|
+
return !this.areMutationsEnabled();
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
isActionEnabled(action) {
|
|
58
|
+
const matchingActions = [action, ALL_ACTIONS];
|
|
59
|
+
|
|
60
|
+
return configs.get(uid).disabledActions.every(action => !matchingActions.includes(action));
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
isActionDisabled(action) {
|
|
64
|
+
return !this.isActionEnabled(action);
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
disable() {
|
|
68
|
+
configs.get(uid).enabled = false;
|
|
69
|
+
|
|
70
|
+
return this;
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
disableQueries() {
|
|
74
|
+
configs.get(uid).queries = false;
|
|
75
|
+
|
|
76
|
+
return this;
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
disableMutations() {
|
|
80
|
+
configs.get(uid).mutations = false;
|
|
81
|
+
|
|
82
|
+
return this;
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
disableAction(action) {
|
|
86
|
+
const config = configs.get(uid);
|
|
87
|
+
|
|
88
|
+
if (!config.disabledActions.includes(action)) {
|
|
89
|
+
config.disabledActions.push(action);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return this;
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
disableActions(actions = []) {
|
|
96
|
+
actions.forEach(action => this.disableAction(action));
|
|
97
|
+
|
|
98
|
+
return this;
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
field(fieldName) {
|
|
102
|
+
const { fields } = configs.get(uid);
|
|
103
|
+
|
|
104
|
+
if (!fields.has(fieldName)) {
|
|
105
|
+
fields.set(fieldName, getDefaultFieldConfig());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
isEnabled() {
|
|
110
|
+
return fields.get(fieldName).enabled;
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
hasInputEnabled() {
|
|
114
|
+
return fields.get(fieldName).input;
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
hasOutputEnabled() {
|
|
118
|
+
return fields.get(fieldName).output;
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
hasFiltersEnabeld() {
|
|
122
|
+
return fields.get(fieldName).filters;
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
disable() {
|
|
126
|
+
fields.set(fieldName, {
|
|
127
|
+
enabled: false,
|
|
128
|
+
|
|
129
|
+
output: false,
|
|
130
|
+
input: false,
|
|
131
|
+
|
|
132
|
+
filters: false,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return this;
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
disableOutput() {
|
|
139
|
+
fields.get(fieldName).output = false;
|
|
140
|
+
|
|
141
|
+
return this;
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
disableInput() {
|
|
145
|
+
fields.get(fieldName).input = false;
|
|
146
|
+
|
|
147
|
+
return this;
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
disableFilters() {
|
|
151
|
+
fields.get(fieldName).filters = false;
|
|
152
|
+
|
|
153
|
+
return this;
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = () => ({
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} value
|
|
6
|
+
* @param {object} info
|
|
7
|
+
* @param {object} info.args
|
|
8
|
+
* @param {string} info.resourceUID
|
|
9
|
+
*/
|
|
10
|
+
toEntityResponse(value, info = {}) {
|
|
11
|
+
const { args = {}, resourceUID } = info;
|
|
12
|
+
|
|
13
|
+
return { value, info: { args, resourceUID } };
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {object[]} nodes
|
|
18
|
+
* @param {object} info
|
|
19
|
+
* @param {object} info.args
|
|
20
|
+
* @param {string} info.resourceUID
|
|
21
|
+
*/
|
|
22
|
+
toEntityResponseCollection(nodes, info = {}) {
|
|
23
|
+
const { args = {}, resourceUID } = info;
|
|
24
|
+
|
|
25
|
+
return { nodes, info: { args, resourceUID } };
|
|
26
|
+
},
|
|
27
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const contentAPI = require('./content-api');
|
|
4
|
+
const typeRegistry = require('./type-registry');
|
|
5
|
+
const utils = require('./utils');
|
|
6
|
+
const constants = require('./constants');
|
|
7
|
+
const internals = require('./internals');
|
|
8
|
+
const builders = require('./builders');
|
|
9
|
+
const extension = require('./extension');
|
|
10
|
+
const format = require('./format');
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
builders,
|
|
14
|
+
'content-api': contentAPI,
|
|
15
|
+
constants,
|
|
16
|
+
extension,
|
|
17
|
+
format,
|
|
18
|
+
internals,
|
|
19
|
+
'type-registry': typeRegistry,
|
|
20
|
+
utils,
|
|
21
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const SortArg = require('./sort');
|
|
4
|
+
const publicationState = require('./publication-state');
|
|
5
|
+
const PaginationArg = require('./pagination');
|
|
6
|
+
|
|
7
|
+
module.exports = context => ({
|
|
8
|
+
SortArg,
|
|
9
|
+
PaginationArg,
|
|
10
|
+
PublicationStateArg: publicationState(context),
|
|
11
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { arg, inputObjectType } = require('nexus');
|
|
4
|
+
|
|
5
|
+
const PaginationInputType = inputObjectType({
|
|
6
|
+
name: 'PaginationArg',
|
|
7
|
+
|
|
8
|
+
definition(t) {
|
|
9
|
+
t.int('page');
|
|
10
|
+
t.int('pageSize');
|
|
11
|
+
t.int('start');
|
|
12
|
+
t.int('limit');
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
module.exports = arg({
|
|
17
|
+
type: PaginationInputType,
|
|
18
|
+
default: {},
|
|
19
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { arg } = require('nexus');
|
|
4
|
+
|
|
5
|
+
module.exports = ({ strapi }) => {
|
|
6
|
+
const { PUBLICATION_STATE_TYPE_NAME } = strapi.plugin('graphql').service('constants');
|
|
7
|
+
|
|
8
|
+
return arg({
|
|
9
|
+
type: PUBLICATION_STATE_TYPE_NAME,
|
|
10
|
+
default: 'live',
|
|
11
|
+
});
|
|
12
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { first } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
module.exports = ({ strapi }) => () => {
|
|
6
|
+
const { GRAPHQL_SCALAR_OPERATORS } = strapi.plugin('graphql').service('constants');
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
Object.entries(GRAPHQL_SCALAR_OPERATORS)
|
|
10
|
+
// To be valid, a GraphQL scalar must have at least one operator enabled
|
|
11
|
+
.filter(([, value]) => value.length > 0)
|
|
12
|
+
// Only keep the key (the scalar name)
|
|
13
|
+
.map(first)
|
|
14
|
+
);
|
|
15
|
+
};
|