buro26-strapi-graphql 0.0.20 → 0.0.22

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 CHANGED
@@ -35,9 +35,403 @@ export default () => ({
35
35
 
36
36
  ### Create a new GraphQL Extension
37
37
 
38
+ To create a new GraphQL extension, create a folder named `graphql` in the content-type directory or within the
39
+ extensions folder (in case of extending a plugin).
40
+ Inside the `graphql` folder you can create files with any name. This plugin will scan the `graphql` folder register your
41
+ extensions with Strapi.
42
+
43
+ From each file create a default export that uses th `createGraphQLExtension` factory function. This function takes a
44
+ function as an argument that will receive the Strapi instance and should return an object with the following methods:
45
+
46
+ | Method | Description |
47
+ |-----------------|--------------------------------------------------|
48
+ | init | Called when the extension is initialized |
49
+ | types | Returns an array of GraphQL types |
50
+ | typeDefs | Returns a string with the type definition in SDL |
51
+ | resolvers | Returns an object with resolvers |
52
+ | resolversConfig | Returns an object with resolver configuration |
53
+
54
+ The functions you can implement follow the pattern of the Strapi customization
55
+ options: https://docs.strapi.io/dev-docs/plugins/graphql#customization. The return values here will be registered as-is
56
+ with Strapi in the register hook.
57
+
58
+ ```typescript
59
+ import { createGraphQLExtension } from 'buro26-strapi-graphql';
60
+ import { extendType, nonNull, stringArg } from 'nexus';
61
+
62
+ export default createGraphQLExtension(strapi => ({
63
+
64
+ init() {
65
+ // e.g. disable actions
66
+ strapi
67
+ .plugin('graphql')
68
+ .service('extension')
69
+ .shadowCRUD('api::my-type.my-type')
70
+ .disableActions(['find', 'findOne', 'create', 'update', 'delete']);
71
+ },
72
+
73
+ typeDefs() {
74
+ return `
75
+ type HelloWorldResponse {
76
+ greeting: String!
77
+ }
78
+ `;
79
+ },
80
+
81
+ types() {
82
+ return [
83
+ // Extend an existing type
84
+ extendType({
85
+ type: 'MyType',
86
+ definition(t) {
87
+ t.field('foo', {
88
+ type: 'Boolean',
89
+ resolve: async (root) => {
90
+ return false;
91
+ }
92
+ });
93
+ t.field('bar', {
94
+ type: 'Boolean',
95
+ resolve: async (root) => {
96
+ return false;
97
+ }
98
+ });
99
+ }
100
+ }),
101
+
102
+ // Create a new query
103
+ extendType({
104
+ type: 'Query',
105
+ definition(t) {
106
+ t.field('helloWorld', {
107
+ type: 'HelloWorldResponse',
108
+ args: {
109
+ greeting: nonNull(stringArg())
110
+ },
111
+ // either resolve here or add it in resolvers method
112
+ resolve: async (root, args) => {
113
+ // resolve logic
114
+ }
115
+ });
116
+ }
117
+ })
118
+ ];
119
+ },
120
+
121
+ resolvers() {
122
+ return {
123
+ Query: {
124
+ // Override an existing query
125
+ helloWorld: async (root, args) => {
126
+ // resolve logic
127
+ }
128
+ },
129
+ Mutation: {
130
+ // Override an existing mutation
131
+ updateMyType: async (root, args) => {
132
+ // resolve logic
133
+ }
134
+ }
135
+ };
136
+ },
137
+
138
+ resolversConfig() {
139
+ return {
140
+ 'Query.helloWorld': {
141
+ policies: [
142
+ async ({ state, args }, { strapi }) => {
143
+ // Validate request
144
+ }
145
+ ],
146
+ middlewares: [
147
+ async (next, root, args, context, info) => {
148
+ // Do something here
149
+
150
+ return next(root, args, context, info);
151
+ }
152
+ ]
153
+ }
154
+ };
155
+ }
156
+ }));
157
+ ```
158
+
38
159
  ### Overriding a field
39
160
 
40
- ### Add authorization to a field
161
+ Sometimes you will need to override a field in an existing type. You can do this by extending the type and adding the
162
+ field again. The field will be overridden with the new field definition. To make this easier we added a helper function
163
+ `overrideField` that will make this easier. The helper method also automatically generates a resolver for the field.
164
+
165
+ The overrideField function needs the content type and fieldName to be able to resolve the field type and the resolver.
166
+ The authorize function is optional and can be used to authorize the field. The resolve function is also optional and can
167
+ be used to resolve the field.
168
+
169
+ ```typescript
170
+ import { createGraphQLExtension, overrideField } from 'buro26-strapi-graphql';
171
+ import { extendType } from 'nexus';
172
+
173
+ export default createGraphQLExtension(strapi => ({
174
+ types() {
175
+ return [
176
+ // Extend an existing type
177
+ extendType({
178
+ type: 'MyType',
179
+ definition(t) {
180
+ overrideField<MyContentType>(t, {
181
+ contentTypeName: 'api::my-type.my-type',
182
+ fieldName: 'myField',
183
+ description: 'My field description',
184
+ authorize: async (root, args, context) => {
185
+ // Authorization logic
186
+ return true;
187
+ },
188
+ resolve: async (root) => {
189
+ // Resolver is optional
190
+ return false;
191
+ }
192
+ });
193
+ }
194
+ })
195
+
196
+ ];
197
+ }
198
+ }));
199
+ ```
200
+
201
+ ### Add authorization to an existing field
202
+
203
+ By default Strapi GraphQL does not support field level authorization. This plugin adds support for field level
204
+ authorization. You can add authorization to an existing field by using the before mentioned `overrideField` function.
205
+ The authorize function will be called before the field is resolved. If the authorize function returns false the field
206
+ will not be resolved and an error will be thrown.
207
+
208
+ If you decide not to pass the resolve function and only the authorize function, the field will be resolved by the
209
+ default resolver generated by the plugin.
210
+
211
+ ```typescript
212
+ import { createGraphQLExtension, overrideField } from 'buro26-strapi-graphql';
213
+ import { extendType } from 'nexus';
214
+
215
+ export default createGraphQLExtension(strapi => ({
216
+ types() {
217
+ return [
218
+ // Extend an existing type
219
+ extendType({
220
+ type: 'MyType',
221
+ definition(t) {
222
+ overrideField<MyContentType>(t, {
223
+ contentTypeName: 'api::my-type.my-type',
224
+ fieldName: 'myField',
225
+ authorize: async (root, args, context) => {
226
+ // Decide if the user is authorized to access the field
227
+ return true;
228
+ }
229
+ });
230
+ }
231
+ })
232
+
233
+ ];
234
+ }
235
+ }));
236
+ ```
237
+
238
+ ### Field middleware
239
+
240
+ You can add middleware to a specific field, similarly to adding authorization. Each field can have multiple middlewares.
241
+
242
+ This can be useful when you want to add some logic before or after the field is resolved. E.g. logging, caching,
243
+ response parsing, etc.
244
+
245
+ ```typescript
246
+ import { createGraphQLExtension, overrideField } from 'buro26-strapi-graphql';
247
+ import { extendType } from 'nexus';
248
+
249
+ export default createGraphQLExtension(strapi => ({
250
+ types() {
251
+ return [
252
+ // Extend an existing type
253
+ extendType({
254
+ type: 'MyType',
255
+ definition(t) {
256
+ t.field('myField', {
257
+ type: 'MyFieldType',
258
+ extensions: {
259
+ middlewares: [
260
+ next => async (root, args, context, info) => {
261
+ // Do something before the field is resolved
262
+
263
+ const res = next(root, args, context, info);
264
+
265
+ // Do something after the field is resolved
266
+
267
+ return res;
268
+ }
269
+ ]
270
+ },
271
+ resolve: async (root) => {
272
+ // Resolver is optional
273
+ }
274
+ })
275
+ overrideField<MyContentType>(t, {
276
+ contentTypeName: 'api::my-type.my-type',
277
+ fieldName: 'myField',
278
+ extensions: {
279
+ middlewares: [
280
+ next => async (root, args, context, info) => {
281
+ // Do something before the field is resolved
282
+
283
+ const res = next(root, args, context, info);
284
+
285
+ // Do something after the field is resolved
286
+
287
+ return res;
288
+ }
289
+ ]
290
+ }
291
+ });
292
+ }
293
+ })
294
+
295
+ ];
296
+ }
297
+ }));
298
+ ```
299
+
300
+ ### Utility functions
301
+
302
+ The plugin also provides utility functions to help you resolve entities and collections. These functions are useful when
303
+ you need to resolve entities and collections in your resolvers.
304
+
305
+ #### resolveEntity
306
+
307
+ The `resolveEntity` function can be used to resolve an entity by id. The function takes the content type name and an
308
+ object with all the resolve args passed the resolver function. The function will return the resolved entity as
309
+ EntityResponse.
310
+
311
+ ```typescript
312
+ import { createGraphQLExtension, overrideField, resolveEntity } from 'buro26-strapi-graphql';
313
+ import { extendType } from 'nexus';
314
+
315
+ export default createGraphQLExtension(strapi => ({
316
+ types() {
317
+ return [
318
+ // Extend an existing type
319
+ extendType({
320
+ type: 'MyType',
321
+ definition(t) {
322
+ t.field('myFields', {
323
+ type: 'MyFieldEntityResponse',
324
+ resolve: async (parent, args, context, info) => {
325
+ // Do something, and resolve the entit
326
+ return resolveEntity<MyContentType>('api::my-content-type.my-content-type', {
327
+ args: {
328
+ id: 'the id here',
329
+ },
330
+ parent,
331
+ context,
332
+ info,
333
+ })
334
+ }
335
+ });
336
+ overrideField<MyContentType>(t, {
337
+ contentTypeName: 'api::my-type.my-type',
338
+ fieldName: 'myOtherField',
339
+ resolve: async (parent, args, context, info) => {
340
+ // Do something, and resolve the entit
341
+ return resolveEntity<MyContentType>('api::my-content-type.my-content-type', {
342
+ args: {
343
+ id: 'the id here',
344
+ },
345
+ parent,
346
+ context,
347
+ info,
348
+ })
349
+ }
350
+ });
351
+ }
352
+ })
353
+
354
+ ];
355
+ }
356
+ }));
357
+ ```
358
+
359
+ #### resolveEntityCollection
360
+
361
+ The `resolveEntityCollection` function can be used to resolve a collection of entities. The function takes the content
362
+ type name and an object with all the resolve args passed the resolver function. The function will return the resolved
363
+ collection as EntityCollectionResponse.
364
+
365
+ ```typescript
366
+ import { createGraphQLExtension, overrideField, resolveEntityCollection } from 'buro26-strapi-graphql';
367
+ import { extendType } from 'nexus';
368
+
369
+ export default createGraphQLExtension(strapi => ({
370
+ types() {
371
+ return [
372
+ // Extend an existing type
373
+ extendType({
374
+ type: 'MyType',
375
+ definition(t) {
376
+ t.field('myFields', {
377
+ type: 'MyFieldEntityResponseCollection',
378
+ resolve: async (parent, args, context, info) => {
379
+ // Do something, and resolve the entit
380
+ return resolveEntityCollection<MyContentType>('api::my-content-type.my-content-type', {
381
+ args,
382
+ parent,
383
+ context,
384
+ info,
385
+ })
386
+ }
387
+ });
388
+ overrideField<MyContentType>(t, {
389
+ contentTypeName: 'api::my-type.my-type',
390
+ fieldName: 'myOtherField',
391
+ resolve: async (parent, args, context, info) => {
392
+ // Do something, and resolve the entit
393
+ return resolveEntityCollection<MyContentType>('api::my-content-type.my-content-type', {
394
+ args,
395
+ parent,
396
+ context,
397
+ info,
398
+ })
399
+ }
400
+ });
401
+ }
402
+ })
403
+
404
+ ];
405
+ }
406
+ }));
407
+ ```
408
+
409
+ #### resolveEntityRelationCollection
410
+
411
+ This function has the same API as `resolveEntityCollection` but is used to resolve a collection of entities from a
412
+ relational field on the provided content type.
413
+
414
+ #### toEntityResponse
415
+
416
+ This function is a typesafe response builder for a single entity. It takes the entity and the content type name and will
417
+ return an EntityResponse.
418
+
419
+ This function is re-exported from the Strapi GraphQL plugin.
420
+
421
+ #### toEntityCollectionResponse
422
+
423
+ This function is a typesafe response builder for a collection of entities. It takes the entities and the content type
424
+ name and will return an EntityCollectionResponse.
425
+
426
+ This function is re-exported from the Strapi GraphQL plugin.
427
+
428
+ #### resolveArgs
429
+
430
+ This function is a typesafe utility function to resolve the args passed to the resolver function. It will transform the
431
+ graphql
432
+ args into args that can be passed to the entityManager.
433
+
434
+ This function is re-exported from the Strapi GraphQL plugin.
41
435
 
42
436
  ## Test and Deploy
43
437
 
@@ -1,5 +1,8 @@
1
- import { type Strapi } from '@strapi/strapi';
2
- import { type GraphQLExtension } from './types';
1
+ import type { Strapi } from '@strapi/strapi';
2
+ import type { GraphQLExtension } from './types';
3
+ import type { Middleware, ResolveContext } from './utils';
4
+ import type { GraphQLResolveInfo } from 'graphql';
5
+ import type { GraphQLFieldConfig } from 'graphql/type';
3
6
  declare const _default: {
4
7
  register: ({ strapi }: {
5
8
  strapi: Strapi;
@@ -43,3 +46,31 @@ declare module '@strapi/strapi' {
43
46
  createGraphQLExtension: (factory: (strapi: Strapi) => GraphQLExtension) => GraphQLExtension;
44
47
  }
45
48
  }
49
+ /**
50
+ * Extend Nexus's field definition to include a middleware array.
51
+ */
52
+ declare module 'nexus/dist/core' {
53
+ /**
54
+ * Extends Nexus's OutputFieldConfig to include a `middleware` property.
55
+ */
56
+ interface NexusOutputFieldConfig<TypeName extends string, FieldName extends string> {
57
+ extensions?: {
58
+ middlewares?: Middleware[];
59
+ } & GraphQLFieldConfig<any, any>['extensions'];
60
+ /**
61
+ * A function that determines if the current user is authorized to access this field.
62
+ *
63
+ * @param parent The parent object.
64
+ * @param args The arguments passed to the field.
65
+ * @param context The context object.
66
+ * @param info The GraphQLResolveInfo object.
67
+ */
68
+ authorize?: <Parent extends Object, Args extends Object, Context = ResolveContext>(parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo) => boolean | Promise<boolean>;
69
+ }
70
+ interface GraphQLFieldExtensions<_TSource, _TContext, _TArgs> {
71
+ /**
72
+ * An array of middleware functions to apply to this field.
73
+ */
74
+ middleware?: Middleware[];
75
+ }
76
+ }
@@ -1,4 +1,4 @@
1
- import { type Strapi } from '@strapi/strapi';
1
+ import type { Strapi } from '@strapi/strapi';
2
2
  declare const _default: ({ strapi }: {
3
3
  strapi: Strapi;
4
4
  }) => Promise<void>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const nexus_1 = require("nexus");
4
+ const utils_1 = require("./utils");
4
5
  exports.default = async ({ strapi }) => {
5
6
  const fileService = strapi
6
7
  .plugin('burotwosix-graphql-plugin')
@@ -13,17 +14,26 @@ exports.default = async ({ strapi }) => {
13
14
  ];
14
15
  graphQlExtensionService.use(() => ({
15
16
  plugins: [
16
- (0, nexus_1.fieldAuthorizePlugin)()
17
+ (0, nexus_1.fieldAuthorizePlugin)(),
18
+ (0, utils_1.nexusMiddlewarePlugin)(),
17
19
  ]
18
20
  }));
19
21
  for (const extension of extensions) {
20
22
  (extension === null || extension === void 0 ? void 0 : extension.init) && extension.init();
21
23
  graphQlExtensionService.use(() => {
22
- var _a, _b, _c, _d, _e, _f;
24
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
23
25
  return ({
24
- types: (_b = (_a = extension === null || extension === void 0 ? void 0 : extension.getTypes) === null || _a === void 0 ? void 0 : _a.call(extension)) !== null && _b !== void 0 ? _b : [],
25
- resolvers: (_d = (_c = extension === null || extension === void 0 ? void 0 : extension.resolvers) === null || _c === void 0 ? void 0 : _c.call(extension)) !== null && _d !== void 0 ? _d : { Query: {}, Mutation: {} },
26
- resolversConfig: (_f = (_e = extension === null || extension === void 0 ? void 0 : extension.getResolverConfig) === null || _e === void 0 ? void 0 : _e.call(extension)) !== null && _f !== void 0 ? _f : {}
26
+ typeDefs: (_b = (_a = extension === null || extension === void 0 ? void 0 : extension.typeDefs) === null || _a === void 0 ? void 0 : _a.call(extension)) !== null && _b !== void 0 ? _b : '',
27
+ types: [
28
+ ...((_d = (_c = extension === null || extension === void 0 ? void 0 : extension.getTypes) === null || _c === void 0 ? void 0 : _c.call(extension)) !== null && _d !== void 0 ? _d : []),
29
+ ...((_f = (_e = extension === null || extension === void 0 ? void 0 : extension.types) === null || _e === void 0 ? void 0 : _e.call(extension)) !== null && _f !== void 0 ? _f : []),
30
+ ],
31
+ plugins: (_h = (_g = extension === null || extension === void 0 ? void 0 : extension.plugins) === null || _g === void 0 ? void 0 : _g.call(extension)) !== null && _h !== void 0 ? _h : [],
32
+ resolvers: (_k = (_j = extension === null || extension === void 0 ? void 0 : extension.resolvers) === null || _j === void 0 ? void 0 : _j.call(extension)) !== null && _k !== void 0 ? _k : { Query: {}, Mutation: {} },
33
+ resolversConfig: {
34
+ ...(_m = (_l = extension === null || extension === void 0 ? void 0 : extension.getResolverConfig) === null || _l === void 0 ? void 0 : _l.call(extension)) !== null && _m !== void 0 ? _m : {},
35
+ ...(_p = (_o = extension === null || extension === void 0 ? void 0 : extension.resolversConfig) === null || _o === void 0 ? void 0 : _o.call(extension)) !== null && _p !== void 0 ? _p : {},
36
+ },
27
37
  });
28
38
  });
29
39
  }
@@ -1,3 +1,6 @@
1
+ import type { ResolveContext } from './utils';
2
+ import type { GraphQLResolveInfo } from 'graphql';
3
+ import type { Strapi } from '@strapi/strapi';
1
4
  export interface GraphQLExtension {
2
5
  /**
3
6
  * Called when the extension is initialized, use this to perform any initialization logic
@@ -5,23 +8,69 @@ export interface GraphQLExtension {
5
8
  * @see https://docs.strapi.io/developer-docs/latest/plugins/graphql.html#disabling-operations-in-the-shadow-crud
6
9
  */
7
10
  init?: () => void;
11
+ /**
12
+ * Return the type definitions for the extension as GraphQL SDL
13
+ */
14
+ typeDefs?: () => string;
8
15
  /**
9
16
  * Return array the types for the extension
10
17
  * Use Nexus to define types
18
+ *
19
+ * @deprecated Use types() instead
11
20
  */
12
- getTypes: () => any[];
21
+ getTypes?: () => any[];
22
+ /**
23
+ * Return array the types for the extension
24
+ * Use Nexus to define types
25
+ */
26
+ types?: () => any[];
27
+ /**
28
+ * Return optional array of nexus plugins
29
+ *
30
+ * @see https://nexusjs.org/docs/plugins
31
+ */
32
+ plugins?: () => any[];
13
33
  /**
14
34
  * Return resolvers for the extension
15
35
  * Return an object with Query and Mutation resolvers
16
36
  */
17
- resolvers: () => {
18
- Query: any;
19
- Mutation: any;
37
+ resolvers?: () => {
38
+ Query?: Record<string, ResolverFunction>;
39
+ Mutation?: Record<string, ResolverFunction>;
20
40
  };
41
+ /**
42
+ * Return resolver config for the extension
43
+ * This is used to configure middlewares and other resolver options
44
+ * @see https://docs.strapi.io/developer-docs/latest/plugins/graphql.html#extending-the-schema
45
+ *
46
+ * @deprecated Use resolversConfig() instead
47
+ */
48
+ getResolverConfig?: () => any;
21
49
  /**
22
50
  * Return resolver config for the extension
23
51
  * This is used to configure middlewares and other resolver options
24
52
  * @see https://docs.strapi.io/developer-docs/latest/plugins/graphql.html#extending-the-schema
25
53
  */
26
- getResolverConfig: () => any;
54
+ resolversConfig?: () => Record<string, ResolverConfigOption>;
27
55
  }
56
+ type ResolverConfigOption = {
57
+ auth?: boolean | undefined;
58
+ policies?: string[] | PolicyFunction[];
59
+ middlewares?: MiddlewareFunction[];
60
+ };
61
+ type PolicyFunctionContext = {
62
+ parent: any;
63
+ args: any;
64
+ context: ResolveContext;
65
+ info: GraphQLResolveInfo;
66
+ state: ResolveContext['state'];
67
+ http: any;
68
+ };
69
+ type PolicyFunctionOptions = {
70
+ strapi: Strapi;
71
+ };
72
+ type PolicyFunction = (context: PolicyFunctionContext, config: any, opts: PolicyFunctionOptions) => boolean | Promise<boolean>;
73
+ type MiddlewareFunction = (next: MiddlewareNextFunction, parent: any, args: any, context: ResolveContext, info: GraphQLResolveInfo) => any | Promise<any>;
74
+ type MiddlewareNextFunction = (parent: any, args: any, context: ResolveContext, info: GraphQLResolveInfo) => Promise<any>;
75
+ type ResolverFunction = (parent: any, args: any, context: ResolveContext, info: GraphQLResolveInfo) => any | Promise<any>;
76
+ export {};
@@ -6,3 +6,15 @@
6
6
  import { Entity, type ResolveArgs } from './types';
7
7
  export declare const resolveEntityCollection: <T extends Object>(contentType: string, resolveArgs: ResolveArgs) => Promise<Entity<T>[]>;
8
8
  export declare const resolveEntityRelationCollection: <T extends Object>(contentType: string, relationFieldName: keyof T, resolveArgs: ResolveArgs) => Promise<Entity<T>[]>;
9
+ type EntityResponse<T extends Object> = {
10
+ value: Entity<T> | null;
11
+ info: {
12
+ args: Record<string, any>;
13
+ resourceUID: string;
14
+ };
15
+ };
16
+ export default function toEntityResponseCollection<T extends Object>(items: T[], { args, resourceUID }: {
17
+ args: Record<string, any>;
18
+ resourceUID: string;
19
+ }): EntityResponse<T>[];
20
+ export {};
@@ -33,3 +33,11 @@ const resolveEntityRelationCollection = async (contentType, relationFieldName, r
33
33
  return find(resolveArgs.parent, resolveArgs.args, resolveArgs.context);
34
34
  };
35
35
  exports.resolveEntityRelationCollection = resolveEntityRelationCollection;
36
+ function toEntityResponseCollection(items, { args, resourceUID }) {
37
+ const { toEntityResponseCollection } = strapi.plugin('graphql').service('format').returnTypes;
38
+ return toEntityResponseCollection(items, {
39
+ args,
40
+ resourceUID
41
+ });
42
+ }
43
+ exports.default = toEntityResponseCollection;
@@ -1,4 +1,6 @@
1
1
  export * from './types';
2
2
  export * from './single-type';
3
3
  export * from './collection-type';
4
+ export * from './middleware';
5
+ export * from './misc';
4
6
  export * from './override';
@@ -17,4 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./types"), exports);
18
18
  __exportStar(require("./single-type"), exports);
19
19
  __exportStar(require("./collection-type"), exports);
20
+ __exportStar(require("./middleware"), exports);
21
+ __exportStar(require("./misc"), exports);
20
22
  __exportStar(require("./override"), exports);
@@ -0,0 +1,17 @@
1
+ import 'nexus';
2
+ import { GraphQLResolveInfo } from 'graphql';
3
+ import { ResolveContext } from './types';
4
+ /**
5
+ * The Resolver type represents a GraphQL resolver function.
6
+ */
7
+ export type Resolver = <Parent extends Object, Args extends Object, Context = ResolveContext>(parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo) => any | Promise<any>;
8
+ /**
9
+ * Middleware is a function that takes a resolver and returns a new resolver.
10
+ */
11
+ export type Middleware = (resolver: Resolver) => Resolver;
12
+ export declare const nexusMiddlewarePlugin: () => import("nexus/dist/plugin").NexusPlugin;
13
+ /**
14
+ * Logging Middleware
15
+ * Logs the execution of the resolver.
16
+ */
17
+ export declare const loggingMiddleware: Middleware;