@tinkerstack/graphql-annotation 0.0.4 → 0.0.6

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
@@ -1,138 +1,138 @@
1
- <center>
2
- <img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fcdn.icon-icons.com%2Ficons2%2F2699%2FPNG%2F512%2Fgraphql_logo_icon_171045.png&f=1&nofb=1&ipt=e40678a4804af7f493102aa8bcc97bacbfdfee9dac86e14c75ab7afb00a237b5" height="150px">
3
- <h1>GraphQL Annotation</h1>
4
- <p>A set of tools for extending GraphQL stitching capabilities through annotations</p>
5
- </center>
6
-
7
- ---
8
-
9
- ## Who is this intended for?
10
-
11
- This library is designed to solve a specific scenario in mind:
12
-
13
- 1. There's a primary `Gateway` and separately developed `SubGateway`s, both of each uses `graphql`.
14
- 2. Front-end or external non-backend consumers interact with `SubGateway` resolvers stitched through `Gateway`
15
- 3. Resolvers at `SubGateway` requires additional resource/guard/processing from `Gateway`.
16
- 4. `SubGateway` team does not have access to `Gateway` nor can they run a local instance.
17
- 5. `SubGateway` team **does not require** `Gateway` features during development, only during deployment.
18
-
19
- Available solutions often utilize `Remote-Produce-Calls (RPCs)` libraries to let `SubGateway` invoke `Gateway` methods through HTTP transport, which unfortunately fails point 4 and 5, of which this library answers through `annotations`.
20
-
21
- **However**, if `SubGateway` needs to make additional calls to `Gateway` for mutation or other purposes, then this library should only be considered as a mean of optimization and you are better off just running an `RPC` library at the small of performance and back-and-forth.
22
-
23
- **TL;DR:** Only use this library if you HAVE TO achieve complete isolation between `Gateway` and `SubGateway` development cycle.
24
-
25
- ## Usage
26
-
27
- You can find examples in `src/examples` for more details. Note that `graphql-annotation` should be replaced with workspace name in internal projects.
28
-
29
- ```ts
30
- // gateway
31
-
32
- import {
33
- GraphQLAnnotationModule,
34
- GraphQLAnnotationSchemaLoader
35
- } from "graphql-annotation";
36
-
37
- @Module({
38
- imports: [
39
- GraphQLAnnotationModule.forRoot(),
40
- GraphQLModule.forRootAsync<ApolloDriverConfig>({
41
- driver: ApolloDriver,
42
- useFactory: (loader: GraphQLAnnotatedSchemaLoader) => ({
43
- async transformSchema(schema) {
44
- return stitchSchemas({
45
- subschemas: [
46
- { schema },
47
- {
48
- // Load external annotated schemas
49
- schema: await loader.load({
50
- example: "http://localhost:3031/graphql",
51
- }),
52
- },
53
- ],
54
- });
55
- },
56
- }),
57
- inject: [GraphQLAnnotatedSchemaLoader],
58
- }),
59
- ],
60
- })
61
- export class GatewayAppModule {}
62
-
63
-
64
- // It is recommended that you wrap the `Annotate` decorator in a function and in the gateway to ensure `gateway` team knows that's implemented. `sub-gateway` team could reference this through github submodule.
65
-
66
- export type RoleGroups = ("user" | "admin" | "super-admin")[];
67
- export const ProtectedResolver = (roles: RoleGroups) =>
68
- Annotate("protected", { data: { roles } });
69
-
70
- export const InjectableArg = (argName: string, resourceType: string) =>
71
- Annotate("resource", { data: { resourceType }, parameter: argName });
72
-
73
- @Injectable()
74
- export class ExampleGuard implements CanActivate {
75
- canActivate(context: ExecutionContext) {
76
- // Do something with your execution context
77
- return true;
78
- }
79
- }
80
-
81
- @Resolver()
82
- export class SubgatewayResolver {
83
- // NOTE: You can use normal nest and graphql decorators.
84
- // Just note that `ResolveAnnotation` must be in a `Resolver`
85
-
86
- @UseGuards(ExampleGuard)
87
- @ResolveAnnotation("protected")
88
- verifyUser(context: ExecutionContext, next: () => void) {}
89
-
90
- // If empty would use function name as annotation tag
91
- @ResolveAnnotation()
92
- resource(
93
- // WARN: this is NOT validated like in graphql though
94
- @Args("resourceType") resourceType: string,
95
- @Context() context: GraphQLExecutionContext,
96
- ) {
97
- return "this-is-gateway-provided-username";
98
- }
99
- }
100
-
101
- // ---------------------------------------------
102
-
103
- // sub-gateway
104
- @Module({
105
- imports: [
106
- GraphQLModule.forRoot<ApolloDriverConfig>({
107
- /* Put your graphql config here*/
108
- }),
109
- GraphQLAnnotationModule.forRoot({
110
- serveAnnotations: true,
111
- // Name is only for identification at the time of writing, which does not support annotation filtering.
112
- serveConfig: { name: "<subgateway-a>" },
113
- }),
114
- ExampleProducerModule,
115
- ],
116
- })
117
- export class SubGatewayAppModule {}
118
-
119
- @Resolver()
120
- export class ExampleProducerResolver {
121
- @Query(() => [String])
122
- @ProtectedResolver(["admin"])
123
- testProtectedQuery() {
124
- return ["This resolver should only be available to if guard check passed"];
125
- }
126
- @Query(() => [String])
127
- testQueryWithParam(
128
- @InjectableArg("username", "session:username")
129
- username: string
130
- ) {
131
- return [`Received params: ${username}`];
132
- }
133
- @Query(() => [String])
134
- testPublicQuery() {
135
- return ["This resolver should be available to everyone"];
136
- }
137
- }
138
- ```
1
+ <center>
2
+ <img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fcdn.icon-icons.com%2Ficons2%2F2699%2FPNG%2F512%2Fgraphql_logo_icon_171045.png&f=1&nofb=1&ipt=e40678a4804af7f493102aa8bcc97bacbfdfee9dac86e14c75ab7afb00a237b5" height="150px">
3
+ <h1>GraphQL Annotation</h1>
4
+ <p>A set of tools for extending GraphQL stitching capabilities through annotations</p>
5
+ </center>
6
+
7
+ ---
8
+
9
+ ## Who is this intended for?
10
+
11
+ This library is designed to solve a specific scenario in mind:
12
+
13
+ 1. There's a primary `Gateway` and separately developed `SubGateway`s, both of each uses `graphql`.
14
+ 2. Front-end or external non-backend consumers interact with `SubGateway` resolvers stitched through `Gateway`
15
+ 3. Resolvers at `SubGateway` requires additional resource/guard/processing from `Gateway`.
16
+ 4. `SubGateway` team does not have access to `Gateway` nor can they run a local instance.
17
+ 5. `SubGateway` team **does not require** `Gateway` features during development, only during deployment.
18
+
19
+ Available solutions often utilize `Remote-Produce-Calls (RPCs)` libraries to let `SubGateway` invoke `Gateway` methods through HTTP transport, which unfortunately fails point 4 and 5, of which this library answers through `annotations`.
20
+
21
+ **However**, if `SubGateway` needs to make additional calls to `Gateway` for mutation or other purposes, then this library should only be considered as a mean of optimization and you are better off just running an `RPC` library at the small of performance and back-and-forth.
22
+
23
+ **TL;DR:** Only use this library if you HAVE TO achieve complete isolation between `Gateway` and `SubGateway` development cycle.
24
+
25
+ ## Usage
26
+
27
+ You can find examples in `src/examples` for more details. Note that `graphql-annotation` should be replaced with workspace name in internal projects.
28
+
29
+ ```ts
30
+ // gateway
31
+
32
+ import {
33
+ GraphQLAnnotationModule,
34
+ GraphQLAnnotationSchemaLoader
35
+ } from "graphql-annotation";
36
+
37
+ @Module({
38
+ imports: [
39
+ GraphQLAnnotationModule.forRoot(),
40
+ GraphQLModule.forRootAsync<ApolloDriverConfig>({
41
+ driver: ApolloDriver,
42
+ useFactory: (loader: GraphQLAnnotatedSchemaLoader) => ({
43
+ async transformSchema(schema) {
44
+ return stitchSchemas({
45
+ subschemas: [
46
+ { schema },
47
+ {
48
+ // Load external annotated schemas
49
+ schema: await loader.load({
50
+ example: "http://localhost:3031/graphql",
51
+ }),
52
+ },
53
+ ],
54
+ });
55
+ },
56
+ }),
57
+ inject: [GraphQLAnnotatedSchemaLoader],
58
+ }),
59
+ ],
60
+ })
61
+ export class GatewayAppModule {}
62
+
63
+
64
+ // It is recommended that you wrap the `Annotate` decorator in a function and in the gateway to ensure `gateway` team knows that's implemented. `sub-gateway` team could reference this through github submodule.
65
+
66
+ export type RoleGroups = ("user" | "admin" | "super-admin")[];
67
+ export const ProtectedResolver = (roles: RoleGroups) =>
68
+ Annotate("protected", { data: { roles } });
69
+
70
+ export const InjectableArg = (argName: string, resourceType: string) =>
71
+ Annotate("resource", { data: { resourceType }, parameter: argName });
72
+
73
+ @Injectable()
74
+ export class ExampleGuard implements CanActivate {
75
+ canActivate(context: ExecutionContext) {
76
+ // Do something with your execution context
77
+ return true;
78
+ }
79
+ }
80
+
81
+ @Resolver()
82
+ export class SubgatewayResolver {
83
+ // NOTE: You can use normal nest and graphql decorators.
84
+ // Just note that `ResolveAnnotation` must be in a `Resolver`
85
+
86
+ @UseGuards(ExampleGuard)
87
+ @ResolveAnnotation("protected")
88
+ verifyUser(context: ExecutionContext, next: () => void) {}
89
+
90
+ // If empty would use function name as annotation tag
91
+ @ResolveAnnotation()
92
+ resource(
93
+ // WARN: this is NOT validated like in graphql though
94
+ @Args("resourceType") resourceType: string,
95
+ @Context() context: GraphQLExecutionContext,
96
+ ) {
97
+ return "this-is-gateway-provided-username";
98
+ }
99
+ }
100
+
101
+ // ---------------------------------------------
102
+
103
+ // sub-gateway
104
+ @Module({
105
+ imports: [
106
+ GraphQLModule.forRoot<ApolloDriverConfig>({
107
+ /* Put your graphql config here*/
108
+ }),
109
+ GraphQLAnnotationModule.forRoot({
110
+ serveAnnotations: true,
111
+ // Name is only for identification at the time of writing, which does not support annotation filtering.
112
+ serveConfig: { name: "<subgateway-a>" },
113
+ }),
114
+ ExampleProducerModule,
115
+ ],
116
+ })
117
+ export class SubGatewayAppModule {}
118
+
119
+ @Resolver()
120
+ export class ExampleProducerResolver {
121
+ @Query(() => [String])
122
+ @ProtectedResolver(["admin"])
123
+ testProtectedQuery() {
124
+ return ["This resolver should only be available to if guard check passed"];
125
+ }
126
+ @Query(() => [String])
127
+ testQueryWithParam(
128
+ @InjectableArg("username", "session:username")
129
+ username: string
130
+ ) {
131
+ return [`Received params: ${username}`];
132
+ }
133
+ @Query(() => [String])
134
+ testPublicQuery() {
135
+ return ["This resolver should be available to everyone"];
136
+ }
137
+ }
138
+ ```
package/dist/index.js CHANGED
@@ -373,7 +373,7 @@ var GraphQLAnnotatedSchemaLoader = class {
373
373
  }
374
374
  });
375
375
  const [loaded, failed] = split(await Promise.allSettled(pending), (q) => q.status === "fulfilled");
376
- const shouldThrow = opts?.ignoreMissingSources ?? true;
376
+ const shouldThrow = !(opts?.ignoreMissingSources ?? false);
377
377
  if (failed.length > 0) {
378
378
  if (shouldThrow) throw new Error(`Failed to load ${failed.length} schema(s) from sources.`);
379
379
  else this._logger.warn(`Failed to load ${failed.length}, ignoring.`);
package/dist/index.mjs CHANGED
@@ -344,7 +344,7 @@ var GraphQLAnnotatedSchemaLoader = class {
344
344
  }
345
345
  });
346
346
  const [loaded, failed] = split(await Promise.allSettled(pending), (q) => q.status === "fulfilled");
347
- const shouldThrow = opts?.ignoreMissingSources ?? true;
347
+ const shouldThrow = !(opts?.ignoreMissingSources ?? false);
348
348
  if (failed.length > 0) {
349
349
  if (shouldThrow) throw new Error(`Failed to load ${failed.length} schema(s) from sources.`);
350
350
  else this._logger.warn(`Failed to load ${failed.length}, ignoring.`);
package/nest-cli.json CHANGED
@@ -1,9 +1,9 @@
1
- {
2
- "$schema": "https://json.schemastore.org/nest-cli",
3
- "collection": "@nestjs/schematics",
4
- "sourceRoot": "src",
5
- "entryFile": "example/main",
6
- "compilerOptions": {
7
- "tsConfigPath": "tsconfig.json"
8
- }
1
+ {
2
+ "$schema": "https://json.schemastore.org/nest-cli",
3
+ "collection": "@nestjs/schematics",
4
+ "sourceRoot": "src",
5
+ "entryFile": "example/main",
6
+ "compilerOptions": {
7
+ "tsConfigPath": "tsconfig.json"
8
+ }
9
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinkerstack/graphql-annotation",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Better type-safe-able graphql directives",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -17,7 +17,12 @@
17
17
  "graphql-request": "^7.2.0"
18
18
  },
19
19
  "publishConfig": {
20
- "access": "public"
20
+ "access": "public",
21
+ "provenance": true
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/plasteek/tinkerstack.git"
21
26
  },
22
27
  "peerDependencies": {
23
28
  "@nestjs/common": "^10 || ^11",
@@ -1,38 +1,38 @@
1
- import { Module } from "@nestjs/common";
2
- import { GraphQLModule } from "@nestjs/graphql";
3
-
4
- import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
5
- import { ExampleConsumerModule } from "./consumer.example";
6
- import { GraphQLAnnotatedSchemaLoader } from "@/modules/core/annotation.loader";
7
- import { GraphQLAnnotationModule } from "@/modules/core/annotation.module";
8
- import { stitchSchemas } from "@graphql-tools/stitch";
9
-
10
- @Module({
11
- imports: [
12
- ExampleConsumerModule,
13
- GraphQLAnnotationModule.forRoot(),
14
- GraphQLModule.forRootAsync<ApolloDriverConfig>({
15
- driver: ApolloDriver,
16
- useFactory: (loader: GraphQLAnnotatedSchemaLoader) => ({
17
- graphiql: true,
18
- playground: true,
19
- autoSchemaFile: "./src/example/consumer/consumer.schema.gql",
20
- async transformSchema(schema) {
21
- return stitchSchemas({
22
- subschemas: [
23
- { schema },
24
- {
25
- // Load external annotated schemas
26
- schema: await loader.load({
27
- example: "http://localhost:3031/graphql",
28
- }),
29
- },
30
- ],
31
- });
32
- },
33
- }),
34
- inject: [GraphQLAnnotatedSchemaLoader],
35
- }),
36
- ],
37
- })
38
- export class ExampleConsumerApp {}
1
+ import { Module } from "@nestjs/common";
2
+ import { GraphQLModule } from "@nestjs/graphql";
3
+
4
+ import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
5
+ import { ExampleConsumerModule } from "./consumer.example";
6
+ import { GraphQLAnnotatedSchemaLoader } from "@/modules/core/annotation.loader";
7
+ import { GraphQLAnnotationModule } from "@/modules/core/annotation.module";
8
+ import { stitchSchemas } from "@graphql-tools/stitch";
9
+
10
+ @Module({
11
+ imports: [
12
+ ExampleConsumerModule,
13
+ GraphQLAnnotationModule.forRoot(),
14
+ GraphQLModule.forRootAsync<ApolloDriverConfig>({
15
+ driver: ApolloDriver,
16
+ useFactory: (loader: GraphQLAnnotatedSchemaLoader) => ({
17
+ graphiql: true,
18
+ playground: true,
19
+ autoSchemaFile: "./src/example/consumer/consumer.schema.gql",
20
+ async transformSchema(schema) {
21
+ return stitchSchemas({
22
+ subschemas: [
23
+ { schema },
24
+ {
25
+ // Load external annotated schemas
26
+ schema: await loader.load({
27
+ example: "http://localhost:3031/graphql",
28
+ }),
29
+ },
30
+ ],
31
+ });
32
+ },
33
+ }),
34
+ inject: [GraphQLAnnotatedSchemaLoader],
35
+ }),
36
+ ],
37
+ })
38
+ export class ExampleConsumerApp {}
@@ -1,57 +1,57 @@
1
- import { Annotate, ResolveAnnotation } from "@/modules/core";
2
- import {
3
- CanActivate,
4
- ExecutionContext,
5
- Injectable,
6
- Module,
7
- UseGuards,
8
- } from "@nestjs/common";
9
- import {
10
- Args,
11
- Context,
12
- GraphQLExecutionContext,
13
- Query,
14
- Resolver,
15
- } from "@nestjs/graphql";
16
-
17
- // Export for external
18
- export type RoleGroups = ("user" | "admin" | "super-admin")[];
19
- export const ProtectedResolver = (roles: RoleGroups) =>
20
- Annotate("protected", { data: { roles } });
21
- export const InjectableArg = (argName: string, resourceType: string) =>
22
- Annotate("resource", { data: { resourceType }, parameter: argName });
23
-
24
- @Injectable()
25
- export class ExampleGuard implements CanActivate {
26
- canActivate(context: ExecutionContext) {
27
- // Do something with your execution context
28
- return true;
29
- }
30
- }
31
-
32
- @Resolver()
33
- export class ExampleConsumerResolver {
34
- @Query(() => [String])
35
- exampleOut() {
36
- return ["this is from consumer"];
37
- }
38
-
39
- @UseGuards(ExampleGuard)
40
- @ResolveAnnotation("protected")
41
- verifyUser(context: ExecutionContext, next: () => void) {
42
- console.log("I AM HERE");
43
- }
44
-
45
- // Should use the name
46
- @ResolveAnnotation("resource")
47
- resolveResource(
48
- @Args("resourceType") resourceType: string,
49
- @Context() context: GraphQLExecutionContext,
50
- ) {
51
- console.log(resourceType);
52
- return "this-is-gateway-provided-username";
53
- }
54
- }
55
-
56
- @Module({ providers: [ExampleConsumerResolver] })
57
- export class ExampleConsumerModule {}
1
+ import { Annotate, ResolveAnnotation } from "@/modules/core";
2
+ import {
3
+ CanActivate,
4
+ ExecutionContext,
5
+ Injectable,
6
+ Module,
7
+ UseGuards,
8
+ } from "@nestjs/common";
9
+ import {
10
+ Args,
11
+ Context,
12
+ GraphQLExecutionContext,
13
+ Query,
14
+ Resolver,
15
+ } from "@nestjs/graphql";
16
+
17
+ // Export for external
18
+ export type RoleGroups = ("user" | "admin" | "super-admin")[];
19
+ export const ProtectedResolver = (roles: RoleGroups) =>
20
+ Annotate("protected", { data: { roles } });
21
+ export const InjectableArg = (argName: string, resourceType: string) =>
22
+ Annotate("resource", { data: { resourceType }, parameter: argName });
23
+
24
+ @Injectable()
25
+ export class ExampleGuard implements CanActivate {
26
+ canActivate(context: ExecutionContext) {
27
+ // Do something with your execution context
28
+ return true;
29
+ }
30
+ }
31
+
32
+ @Resolver()
33
+ export class ExampleConsumerResolver {
34
+ @Query(() => [String])
35
+ exampleOut() {
36
+ return ["this is from consumer"];
37
+ }
38
+
39
+ @UseGuards(ExampleGuard)
40
+ @ResolveAnnotation("protected")
41
+ verifyUser(context: ExecutionContext, next: () => void) {
42
+ console.log("I AM HERE");
43
+ }
44
+
45
+ // Should use the name
46
+ @ResolveAnnotation("resource")
47
+ resolveResource(
48
+ @Args("resourceType") resourceType: string,
49
+ @Context() context: GraphQLExecutionContext,
50
+ ) {
51
+ console.log(resourceType);
52
+ return "this-is-gateway-provided-username";
53
+ }
54
+ }
55
+
56
+ @Module({ providers: [ExampleConsumerResolver] })
57
+ export class ExampleConsumerModule {}
@@ -1,23 +1,23 @@
1
- import { NestFactory } from "@nestjs/core";
2
-
3
- import { FastifyAdapter } from "@nestjs/platform-fastify";
4
- import { ExampleProducerApp } from "./producer/producer.app";
5
- import { ConsoleLogger, Type } from "@nestjs/common";
6
- import { ExampleConsumerApp } from "./consumer/consumer.app";
7
-
8
- export async function bootstrap(name: string, module: Type, port: number) {
9
- const app = await NestFactory.create(module, new FastifyAdapter(), {
10
- logger: new ConsoleLogger({ prefix: name }),
11
- });
12
- await app.listen(port);
13
-
14
- console.log(
15
- `Listening on localhost:${port}. Playground: http://localhost:${port}/graphql`
16
- );
17
- }
18
-
19
- async function main() {
20
- await bootstrap("example-producer", ExampleProducerApp, 3031);
21
- await bootstrap("example-consumer", ExampleConsumerApp, 3030);
22
- }
23
- void main();
1
+ import { NestFactory } from "@nestjs/core";
2
+
3
+ import { FastifyAdapter } from "@nestjs/platform-fastify";
4
+ import { ExampleProducerApp } from "./producer/producer.app";
5
+ import { ConsoleLogger, Type } from "@nestjs/common";
6
+ import { ExampleConsumerApp } from "./consumer/consumer.app";
7
+
8
+ export async function bootstrap(name: string, module: Type, port: number) {
9
+ const app = await NestFactory.create(module, new FastifyAdapter(), {
10
+ logger: new ConsoleLogger({ prefix: name }),
11
+ });
12
+ await app.listen(port);
13
+
14
+ console.log(
15
+ `Listening on localhost:${port}. Playground: http://localhost:${port}/graphql`
16
+ );
17
+ }
18
+
19
+ async function main() {
20
+ await bootstrap("example-producer", ExampleProducerApp, 3031);
21
+ await bootstrap("example-consumer", ExampleConsumerApp, 3030);
22
+ }
23
+ void main();
@@ -1,22 +1,22 @@
1
- import { Module } from "@nestjs/common";
2
- import { GraphQLModule } from "@nestjs/graphql";
3
- import { ExampleProducerModule } from "./producer.example";
4
-
5
- import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
6
- import { GraphQLAnnotationModule } from "@/modules/core/annotation.module";
7
-
8
- @Module({
9
- imports: [
10
- GraphQLModule.forRoot<ApolloDriverConfig>({
11
- driver: ApolloDriver,
12
- graphiql: true,
13
- autoSchemaFile: "./src/example/producer/producer.schema.gql",
14
- }),
15
- GraphQLAnnotationModule.forRoot({
16
- serveAnnotations: true,
17
- serveConfig: { name: "producer-example" },
18
- }),
19
- ExampleProducerModule,
20
- ],
21
- })
22
- export class ExampleProducerApp {}
1
+ import { Module } from "@nestjs/common";
2
+ import { GraphQLModule } from "@nestjs/graphql";
3
+ import { ExampleProducerModule } from "./producer.example";
4
+
5
+ import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
6
+ import { GraphQLAnnotationModule } from "@/modules/core/annotation.module";
7
+
8
+ @Module({
9
+ imports: [
10
+ GraphQLModule.forRoot<ApolloDriverConfig>({
11
+ driver: ApolloDriver,
12
+ graphiql: true,
13
+ autoSchemaFile: "./src/example/producer/producer.schema.gql",
14
+ }),
15
+ GraphQLAnnotationModule.forRoot({
16
+ serveAnnotations: true,
17
+ serveConfig: { name: "producer-example" },
18
+ }),
19
+ ExampleProducerModule,
20
+ ],
21
+ })
22
+ export class ExampleProducerApp {}