@tinkerstack/graphql-annotation 0.0.0

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.
@@ -0,0 +1,22 @@
1
+
2
+ > @tinkerstack/graphql-annotation@1.0.0 build C:\Users\mori\Documents\Work\tinkerstack\packages\graphql-annotation
3
+ > tsup
4
+
5
+ CLI Building entry: src/index.ts
6
+ CLI Using tsconfig: tsconfig.build.json
7
+ CLI tsup v8.5.1
8
+ CLI Using tsup config: C:\Users\mori\Documents\Work\tinkerstack\packages\graphql-annotation\tsup.config.ts
9
+ CLI Target: es2022
10
+ CLI Cleaning output folder
11
+ ESM Build start
12
+ CJS Build start
13
+ ESM You have emitDecoratorMetadata enabled but @swc/core was not installed, skipping swc plugin
14
+ CJS You have emitDecoratorMetadata enabled but @swc/core was not installed, skipping swc plugin
15
+ ESM dist\index.mjs 15.83 KB
16
+ ESM ⚡️ Build success in 36ms
17
+ CJS dist\index.js 17.66 KB
18
+ CJS ⚡️ Build success in 35ms
19
+ DTS Build start
20
+ DTS ⚡️ Build success in 1773ms
21
+ DTS dist\index.d.mts 2.89 KB
22
+ DTS dist\index.d.ts 2.89 KB
package/README.md ADDED
@@ -0,0 +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
+ ```
@@ -0,0 +1,76 @@
1
+ import { DiscoveryService, MetadataScanner, ExternalContextCreator } from '@nestjs/core';
2
+ import { GraphQLSchema } from 'graphql';
3
+ import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
4
+ import { DynamicModule } from '@nestjs/common';
5
+
6
+ declare function Annotate(name: string, opts?: {
7
+ data?: Record<string, any>;
8
+ parameter?: undefined;
9
+ }): MethodDecorator;
10
+ declare function Annotate(name: string, opts: {
11
+ data?: Record<string, any>;
12
+ parameter: string;
13
+ }): ParameterDecorator & MethodDecorator;
14
+ declare function ResolveAnnotation(): MethodDecorator;
15
+ declare function ResolveAnnotation(annotation: string): MethodDecorator;
16
+
17
+ declare const ANNOTATION_METADATA = "graphql-annotation";
18
+ interface MethodInfo {
19
+ type: "method";
20
+ name: string;
21
+ }
22
+ interface ParameterInfo {
23
+ type: "parameter";
24
+ paramIndex: number;
25
+ paramName: string;
26
+ }
27
+ type AnnotationTarget = MethodInfo | ParameterInfo;
28
+ interface AnnotationInfo<T = unknown> {
29
+ annotation: string;
30
+ target: AnnotationTarget;
31
+ data: T;
32
+ }
33
+ declare const ANNOTATION_RESOLVER_METADATA = "graphql-annotation-resolver";
34
+ interface AnnotationResolverMetadata {
35
+ annotation: string;
36
+ }
37
+ type SourceName = string;
38
+ type RemoteURL = string;
39
+ type AnnotationSchemaSources = Record<SourceName, RemoteURL>;
40
+ type ResolverName = string;
41
+ type GraphQLResolversAnnotations = Record<ResolverName, AnnotationInfo[]>;
42
+ declare const GRAPHQL_ANNOTATION_RESOLVER_METADATA = "graphql-annotation-provider";
43
+ type GraphQLAnnotationResolverMetadata = {
44
+ name: string;
45
+ };
46
+
47
+ declare class ResolverDiscoveryService {
48
+ private readonly discoveryService;
49
+ constructor(discoveryService: DiscoveryService);
50
+ explore(): InstanceWrapper[];
51
+ }
52
+
53
+ declare class GraphQLAnnotatedSchemaLoader {
54
+ private readonly resolverDiscoveryService;
55
+ private readonly metadataScanner;
56
+ private readonly externalContextCreator;
57
+ private _logger;
58
+ constructor(resolverDiscoveryService: ResolverDiscoveryService, metadataScanner: MetadataScanner, externalContextCreator: ExternalContextCreator);
59
+ load(sources: AnnotationSchemaSources): Promise<GraphQLSchema>;
60
+ private discoverAnnotationResolvers;
61
+ private batchLoadSources;
62
+ private loadAnnotations;
63
+ private embedAnnotationResolversToSchema;
64
+ }
65
+
66
+ declare class GraphQLAnnotationModule {
67
+ static forRoot(opts?: {
68
+ serveAnnotations?: false;
69
+ }): DynamicModule;
70
+ static forRoot(opts: {
71
+ serveAnnotations: true;
72
+ serveConfig: GraphQLAnnotationResolverMetadata;
73
+ }): DynamicModule;
74
+ }
75
+
76
+ export { ANNOTATION_METADATA, ANNOTATION_RESOLVER_METADATA, Annotate, type AnnotationInfo, type AnnotationResolverMetadata, type AnnotationSchemaSources, type AnnotationTarget, GRAPHQL_ANNOTATION_RESOLVER_METADATA, GraphQLAnnotatedSchemaLoader, GraphQLAnnotationModule, type GraphQLAnnotationResolverMetadata, type GraphQLResolversAnnotations, type MethodInfo, type ParameterInfo, ResolveAnnotation, type ResolverName };
@@ -0,0 +1,76 @@
1
+ import { DiscoveryService, MetadataScanner, ExternalContextCreator } from '@nestjs/core';
2
+ import { GraphQLSchema } from 'graphql';
3
+ import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
4
+ import { DynamicModule } from '@nestjs/common';
5
+
6
+ declare function Annotate(name: string, opts?: {
7
+ data?: Record<string, any>;
8
+ parameter?: undefined;
9
+ }): MethodDecorator;
10
+ declare function Annotate(name: string, opts: {
11
+ data?: Record<string, any>;
12
+ parameter: string;
13
+ }): ParameterDecorator & MethodDecorator;
14
+ declare function ResolveAnnotation(): MethodDecorator;
15
+ declare function ResolveAnnotation(annotation: string): MethodDecorator;
16
+
17
+ declare const ANNOTATION_METADATA = "graphql-annotation";
18
+ interface MethodInfo {
19
+ type: "method";
20
+ name: string;
21
+ }
22
+ interface ParameterInfo {
23
+ type: "parameter";
24
+ paramIndex: number;
25
+ paramName: string;
26
+ }
27
+ type AnnotationTarget = MethodInfo | ParameterInfo;
28
+ interface AnnotationInfo<T = unknown> {
29
+ annotation: string;
30
+ target: AnnotationTarget;
31
+ data: T;
32
+ }
33
+ declare const ANNOTATION_RESOLVER_METADATA = "graphql-annotation-resolver";
34
+ interface AnnotationResolverMetadata {
35
+ annotation: string;
36
+ }
37
+ type SourceName = string;
38
+ type RemoteURL = string;
39
+ type AnnotationSchemaSources = Record<SourceName, RemoteURL>;
40
+ type ResolverName = string;
41
+ type GraphQLResolversAnnotations = Record<ResolverName, AnnotationInfo[]>;
42
+ declare const GRAPHQL_ANNOTATION_RESOLVER_METADATA = "graphql-annotation-provider";
43
+ type GraphQLAnnotationResolverMetadata = {
44
+ name: string;
45
+ };
46
+
47
+ declare class ResolverDiscoveryService {
48
+ private readonly discoveryService;
49
+ constructor(discoveryService: DiscoveryService);
50
+ explore(): InstanceWrapper[];
51
+ }
52
+
53
+ declare class GraphQLAnnotatedSchemaLoader {
54
+ private readonly resolverDiscoveryService;
55
+ private readonly metadataScanner;
56
+ private readonly externalContextCreator;
57
+ private _logger;
58
+ constructor(resolverDiscoveryService: ResolverDiscoveryService, metadataScanner: MetadataScanner, externalContextCreator: ExternalContextCreator);
59
+ load(sources: AnnotationSchemaSources): Promise<GraphQLSchema>;
60
+ private discoverAnnotationResolvers;
61
+ private batchLoadSources;
62
+ private loadAnnotations;
63
+ private embedAnnotationResolversToSchema;
64
+ }
65
+
66
+ declare class GraphQLAnnotationModule {
67
+ static forRoot(opts?: {
68
+ serveAnnotations?: false;
69
+ }): DynamicModule;
70
+ static forRoot(opts: {
71
+ serveAnnotations: true;
72
+ serveConfig: GraphQLAnnotationResolverMetadata;
73
+ }): DynamicModule;
74
+ }
75
+
76
+ export { ANNOTATION_METADATA, ANNOTATION_RESOLVER_METADATA, Annotate, type AnnotationInfo, type AnnotationResolverMetadata, type AnnotationSchemaSources, type AnnotationTarget, GRAPHQL_ANNOTATION_RESOLVER_METADATA, GraphQLAnnotatedSchemaLoader, GraphQLAnnotationModule, type GraphQLAnnotationResolverMetadata, type GraphQLResolversAnnotations, type MethodInfo, type ParameterInfo, ResolveAnnotation, type ResolverName };