vscode-apollo 1.19.3 → 2.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.
Files changed (179) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +14 -0
  3. package/.circleci/config.yml +91 -0
  4. package/.eslintrc.js +10 -0
  5. package/.git-blame-ignore-revs +2 -0
  6. package/.gitattributes +1 -0
  7. package/.github/workflows/release.yml +95 -0
  8. package/.gitleaks.toml +26 -0
  9. package/.nvmrc +1 -0
  10. package/.prettierrc +5 -0
  11. package/.vscode/launch.json +66 -0
  12. package/.vscode/settings.json +16 -0
  13. package/.vscode/tasks.json +60 -0
  14. package/.vscodeignore +28 -1
  15. package/CHANGELOG.md +250 -1
  16. package/CODEOWNERS +4 -0
  17. package/LICENSE +2 -2
  18. package/README.md +104 -55
  19. package/codegen.yml +12 -0
  20. package/graphql.configuration.json +5 -1
  21. package/images/IconRun.svg +8 -0
  22. package/images/marketplace/apollo-wordmark.png +0 -0
  23. package/jest.config.ts +21 -0
  24. package/jest.e2e.config.js +17 -0
  25. package/package.json +102 -23
  26. package/renovate.json +30 -0
  27. package/sampleWorkspace/clientSchema/apollo.config.cjs +10 -0
  28. package/sampleWorkspace/clientSchema/src/clientSchema.js +16 -0
  29. package/sampleWorkspace/clientSchema/src/test.js +18 -0
  30. package/sampleWorkspace/fixtures/starwarsSchema.graphql +299 -0
  31. package/sampleWorkspace/httpSchema/apollo.config.ts +8 -0
  32. package/sampleWorkspace/httpSchema/src/test.js +9 -0
  33. package/sampleWorkspace/localSchema/apollo.config.js +8 -0
  34. package/sampleWorkspace/localSchema/src/test.js +8 -0
  35. package/sampleWorkspace/localSchemaArray/apollo.config.js +12 -0
  36. package/sampleWorkspace/localSchemaArray/planets.graphql +20 -0
  37. package/sampleWorkspace/localSchemaArray/src/test.js +12 -0
  38. package/sampleWorkspace/sampleWorkspace.code-workspace +20 -0
  39. package/sampleWorkspace/spotifyGraph/apollo.config.mjs +5 -0
  40. package/sampleWorkspace/spotifyGraph/src/test.js +11 -0
  41. package/src/__e2e__/mockServer.js +117 -0
  42. package/src/__e2e__/mocks.js +13094 -0
  43. package/src/__e2e__/run.js +23 -0
  44. package/src/__e2e__/runTests.js +44 -0
  45. package/src/__e2e__/setup.js +1 -0
  46. package/src/__e2e__/vscode-environment.js +16 -0
  47. package/src/__e2e__/vscode.js +1 -0
  48. package/src/__mocks__/fs.js +3 -0
  49. package/src/__tests__/statusBar.test.ts +8 -7
  50. package/src/build.js +57 -0
  51. package/src/debug.ts +2 -5
  52. package/src/env/index.ts +1 -0
  53. package/src/env/typescript-utility-types.ts +2 -0
  54. package/src/extension.ts +265 -170
  55. package/src/language-server/__e2e__/clientSchema.e2e.ts +147 -0
  56. package/src/language-server/__e2e__/httpSchema.e2e.ts +21 -0
  57. package/src/language-server/__e2e__/localSchema.e2e.ts +25 -0
  58. package/src/language-server/__e2e__/localSchemaArray.e2e.ts +31 -0
  59. package/src/language-server/__e2e__/studioGraph.e2e.ts +65 -0
  60. package/src/language-server/__e2e__/utils.ts +151 -0
  61. package/src/language-server/__tests__/diagnostics.test.ts +86 -0
  62. package/src/language-server/__tests__/document.test.ts +187 -0
  63. package/src/language-server/__tests__/fileSet.test.ts +46 -0
  64. package/src/language-server/__tests__/fixtures/starwarsSchema.ts +1917 -0
  65. package/src/language-server/config/__tests__/config.ts +54 -0
  66. package/src/language-server/config/__tests__/loadConfig.ts +384 -0
  67. package/src/language-server/config/__tests__/utils.ts +99 -0
  68. package/src/language-server/config/config.ts +284 -0
  69. package/src/language-server/config/index.ts +3 -0
  70. package/src/language-server/config/loadConfig.ts +101 -0
  71. package/src/language-server/config/utils.ts +45 -0
  72. package/src/language-server/diagnostics.ts +118 -0
  73. package/src/language-server/document.ts +277 -0
  74. package/src/language-server/engine/index.ts +123 -0
  75. package/src/language-server/engine/operations/frontendUrlRoot.ts +15 -0
  76. package/src/language-server/engine/operations/schemaTagsAndFieldStats.ts +32 -0
  77. package/src/language-server/errors/__tests__/NoMissingClientDirectives.test.ts +225 -0
  78. package/src/language-server/errors/logger.ts +58 -0
  79. package/src/language-server/errors/validation.ts +274 -0
  80. package/src/language-server/fileSet.ts +63 -0
  81. package/src/language-server/format.ts +48 -0
  82. package/src/language-server/graphqlTypes.ts +16741 -0
  83. package/src/language-server/index.ts +28 -0
  84. package/src/language-server/languageProvider.ts +795 -0
  85. package/src/language-server/loadingHandler.ts +47 -0
  86. package/src/language-server/project/base.ts +406 -0
  87. package/src/language-server/project/client.ts +568 -0
  88. package/src/language-server/project/defaultClientSchema.ts +70 -0
  89. package/src/language-server/providers/schema/__tests__/file.ts +191 -0
  90. package/src/language-server/providers/schema/base.ts +15 -0
  91. package/src/language-server/providers/schema/endpoint.ts +138 -0
  92. package/src/language-server/providers/schema/engine.ts +204 -0
  93. package/src/language-server/providers/schema/file.ts +176 -0
  94. package/src/language-server/providers/schema/index.ts +59 -0
  95. package/src/language-server/server.ts +274 -0
  96. package/src/language-server/typings/graphql.d.ts +27 -0
  97. package/src/language-server/utilities/__tests__/graphql.test.ts +399 -0
  98. package/src/language-server/utilities/__tests__/uri.ts +55 -0
  99. package/src/language-server/utilities/debouncer.ts +8 -0
  100. package/src/language-server/utilities/debug.ts +90 -0
  101. package/src/language-server/utilities/graphql.ts +433 -0
  102. package/src/language-server/utilities/index.ts +3 -0
  103. package/src/language-server/utilities/source.ts +182 -0
  104. package/src/language-server/utilities/uri.ts +19 -0
  105. package/src/language-server/workspace.ts +254 -0
  106. package/src/languageServerClient.ts +22 -15
  107. package/src/messages.ts +75 -0
  108. package/src/statusBar.ts +5 -5
  109. package/src/tools/__tests__/buildServiceDefinition.test.ts +491 -0
  110. package/src/tools/__tests__/snapshotSerializers/astSerializer.ts +19 -0
  111. package/src/tools/__tests__/snapshotSerializers/graphQLTypeSerializer.ts +14 -0
  112. package/src/tools/buildServiceDefinition.ts +241 -0
  113. package/src/tools/index.ts +6 -0
  114. package/src/tools/schema/index.ts +2 -0
  115. package/src/tools/schema/resolveObject.ts +18 -0
  116. package/src/tools/schema/resolverMap.ts +23 -0
  117. package/src/tools/utilities/graphql.ts +22 -0
  118. package/src/tools/utilities/index.ts +3 -0
  119. package/src/tools/utilities/invariant.ts +5 -0
  120. package/src/tools/utilities/predicates.ts +5 -0
  121. package/src/utils.ts +7 -21
  122. package/syntaxes/graphql.dart.json +2 -4
  123. package/syntaxes/graphql.ex.json +1 -4
  124. package/syntaxes/graphql.js.json +3 -3
  125. package/syntaxes/graphql.json +13 -9
  126. package/syntaxes/graphql.lua.json +51 -0
  127. package/syntaxes/graphql.rb.json +1 -1
  128. package/tsconfig.build.json +11 -0
  129. package/tsconfig.json +22 -7
  130. package/create-server-symlink.js +0 -8
  131. package/lib/debug.d.ts +0 -11
  132. package/lib/debug.d.ts.map +0 -1
  133. package/lib/debug.js +0 -48
  134. package/lib/debug.js.map +0 -1
  135. package/lib/extension.d.ts +0 -4
  136. package/lib/extension.d.ts.map +0 -1
  137. package/lib/extension.js +0 -187
  138. package/lib/extension.js.map +0 -1
  139. package/lib/languageServerClient.d.ts +0 -4
  140. package/lib/languageServerClient.d.ts.map +0 -1
  141. package/lib/languageServerClient.js +0 -57
  142. package/lib/languageServerClient.js.map +0 -1
  143. package/lib/statusBar.d.ts +0 -24
  144. package/lib/statusBar.d.ts.map +0 -1
  145. package/lib/statusBar.js +0 -46
  146. package/lib/statusBar.js.map +0 -1
  147. package/lib/testRunner/index.d.ts +0 -3
  148. package/lib/testRunner/index.d.ts.map +0 -1
  149. package/lib/testRunner/index.js +0 -49
  150. package/lib/testRunner/index.js.map +0 -1
  151. package/lib/testRunner/jest-config.d.ts +0 -14
  152. package/lib/testRunner/jest-config.d.ts.map +0 -1
  153. package/lib/testRunner/jest-config.js +0 -18
  154. package/lib/testRunner/jest-config.js.map +0 -1
  155. package/lib/testRunner/jest-vscode-environment.d.ts +0 -2
  156. package/lib/testRunner/jest-vscode-environment.d.ts.map +0 -1
  157. package/lib/testRunner/jest-vscode-environment.js +0 -19
  158. package/lib/testRunner/jest-vscode-environment.js.map +0 -1
  159. package/lib/testRunner/jest-vscode-framework-setup.d.ts +0 -1
  160. package/lib/testRunner/jest-vscode-framework-setup.d.ts.map +0 -1
  161. package/lib/testRunner/jest-vscode-framework-setup.js +0 -3
  162. package/lib/testRunner/jest-vscode-framework-setup.js.map +0 -1
  163. package/lib/testRunner/vscode-test-script.d.ts +0 -2
  164. package/lib/testRunner/vscode-test-script.d.ts.map +0 -1
  165. package/lib/testRunner/vscode-test-script.js +0 -23
  166. package/lib/testRunner/vscode-test-script.js.map +0 -1
  167. package/lib/utils.d.ts +0 -18
  168. package/lib/utils.d.ts.map +0 -1
  169. package/lib/utils.js +0 -52
  170. package/lib/utils.js.map +0 -1
  171. package/src/testRunner/README.md +0 -23
  172. package/src/testRunner/index.ts +0 -72
  173. package/src/testRunner/jest-config.ts +0 -17
  174. package/src/testRunner/jest-vscode-environment.ts +0 -25
  175. package/src/testRunner/jest-vscode-framework-setup.ts +0 -10
  176. package/src/testRunner/jest.d.ts +0 -37
  177. package/src/testRunner/vscode-test-script.ts +0 -38
  178. package/tsconfig.test.json +0 -4
  179. package/tsconfig.tsbuildinfo +0 -2486
@@ -0,0 +1,191 @@
1
+ import { FileSchemaProvider } from "../file";
2
+ import * as path from "path";
3
+ import * as fs from "fs";
4
+ import { Debug } from "../../../utilities";
5
+ import { URI } from "vscode-uri";
6
+
7
+ const makeNestedDir = (dir: string) => {
8
+ if (fs.existsSync(dir)) return;
9
+
10
+ try {
11
+ fs.mkdirSync(dir);
12
+ } catch (err: any) {
13
+ if (err.code == "ENOENT") {
14
+ makeNestedDir(path.dirname(dir)); //create parent dir
15
+ makeNestedDir(dir); //create dir
16
+ }
17
+ }
18
+ };
19
+
20
+ const deleteFolderRecursive = (path: string) => {
21
+ // don't delete files on windows -- will get a resource locked error
22
+ if (require("os").type().includes("Windows")) {
23
+ return;
24
+ }
25
+
26
+ if (fs.existsSync(path)) {
27
+ fs.readdirSync(path).forEach(function (file, index) {
28
+ var curPath = path + "/" + file;
29
+ if (fs.lstatSync(curPath).isDirectory()) {
30
+ // recurse
31
+ deleteFolderRecursive(curPath);
32
+ } else {
33
+ // delete file
34
+ fs.unlinkSync(curPath);
35
+ }
36
+ });
37
+ fs.rmdirSync(path);
38
+ }
39
+ };
40
+
41
+ const writeFilesToDir = (dir: string, files: Record<string, string>) => {
42
+ Object.keys(files).forEach((key) => {
43
+ if (key.includes("/")) makeNestedDir(path.dirname(key));
44
+ fs.writeFileSync(`${dir}/${key}`, files[key]);
45
+ });
46
+ };
47
+
48
+ describe("FileSchemaProvider", () => {
49
+ let dir: string;
50
+ let dirPath: string;
51
+
52
+ // set up a temp dir
53
+ beforeEach(() => {
54
+ dir = fs.mkdtempSync("__tmp__");
55
+ dirPath = `${process.cwd()}/${dir}`;
56
+ });
57
+
58
+ // clean up our temp dir
59
+ afterEach(() => {
60
+ if (dir) {
61
+ deleteFolderRecursive(dir);
62
+ }
63
+ });
64
+
65
+ describe("resolveFederatedServiceSDL", () => {
66
+ it("finds and loads sdl from graphql file for a federated service", async () => {
67
+ writeFilesToDir(dir, {
68
+ "schema.graphql": `
69
+ extend type Query {
70
+ myProduct: Product
71
+ }
72
+
73
+ type Product @key(fields: "id") {
74
+ id: ID
75
+ sku: ID
76
+ name: String
77
+ }
78
+ `,
79
+ });
80
+
81
+ const provider = new FileSchemaProvider(
82
+ {
83
+ path: "./schema.graphql",
84
+ },
85
+ URI.from({ scheme: "file", path: dirPath }),
86
+ );
87
+ const sdl = await provider.resolveFederatedServiceSDL();
88
+ expect(sdl).toMatchInlineSnapshot;
89
+ });
90
+
91
+ it("finds and loads sdl from multiple graphql files for a federated service", async () => {
92
+ writeFilesToDir(dir, {
93
+ "schema.graphql": `
94
+ extend type Query {
95
+ myProduct: Product
96
+ }
97
+
98
+ type Product @key(fields: "id") {
99
+ id: ID
100
+ sku: ID
101
+ name: String
102
+ }`,
103
+ "schema2.graphql": `
104
+ extend type Product {
105
+ weight: Float
106
+ }`,
107
+ });
108
+
109
+ const provider = new FileSchemaProvider(
110
+ {
111
+ paths: ["schema.graphql", "schema2.graphql"],
112
+ },
113
+ URI.from({ scheme: "file", path: dirPath }),
114
+ );
115
+ const sdl = await provider.resolveFederatedServiceSDL();
116
+ expect(sdl).toMatchInlineSnapshot(`
117
+ "directive @key(fields: _FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
118
+
119
+ directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
120
+
121
+ directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
122
+
123
+ directive @external(reason: String) on OBJECT | FIELD_DEFINITION
124
+
125
+ directive @tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
126
+
127
+ directive @extends on OBJECT | INTERFACE
128
+
129
+ type Query {
130
+ _entities(representations: [_Any!]!): [_Entity]!
131
+ _service: _Service!
132
+ }
133
+
134
+ extend type Query {
135
+ myProduct: Product
136
+ }
137
+
138
+ type Product
139
+ @key(fields: \\"id\\")
140
+ {
141
+ id: ID
142
+ sku: ID
143
+ name: String
144
+ }
145
+
146
+ extend type Product {
147
+ weight: Float
148
+ }
149
+
150
+ scalar _FieldSet
151
+
152
+ scalar _Any
153
+
154
+ type _Service {
155
+ sdl: String
156
+ }
157
+
158
+ union _Entity = Product"
159
+ `);
160
+ });
161
+
162
+ it("errors when sdl file is not a graphql file", async () => {
163
+ const toWrite = `
164
+ module.exports = \`
165
+ extend type Query {
166
+ myProduct: Product
167
+ }
168
+
169
+ type Product @key(fields: "id") {
170
+ id: ID
171
+ sku: ID
172
+ name: string
173
+ }\`
174
+ `;
175
+ writeFilesToDir(dir, {
176
+ "schema.js": toWrite,
177
+ });
178
+
179
+ // noop -- just spy on and silence the error
180
+ const errorSpy = jest.spyOn(Debug, "error");
181
+ errorSpy.mockImplementation(() => {});
182
+
183
+ const provider = new FileSchemaProvider(
184
+ { path: "./schema.js" },
185
+ URI.from({ scheme: "file", path: dirPath }),
186
+ );
187
+ const sdl = await provider.resolveFederatedServiceSDL();
188
+ expect(errorSpy).toBeCalledTimes(2);
189
+ });
190
+ });
191
+ });
@@ -0,0 +1,15 @@
1
+ import { GraphQLSchema } from "graphql";
2
+ import { NotificationHandler } from "vscode-languageserver/node";
3
+
4
+ export interface SchemaResolveConfig {
5
+ tag?: string;
6
+ force?: boolean;
7
+ }
8
+ export type SchemaChangeUnsubscribeHandler = () => void;
9
+ export interface GraphQLSchemaProvider {
10
+ resolveSchema(config?: SchemaResolveConfig): Promise<GraphQLSchema>;
11
+ onSchemaChange(
12
+ handler: NotificationHandler<GraphQLSchema>,
13
+ ): SchemaChangeUnsubscribeHandler;
14
+ resolveFederatedServiceSDL(): Promise<string | void>;
15
+ }
@@ -0,0 +1,138 @@
1
+ // IntrospectionSchemaProvider (http => IntrospectionResult => schema)
2
+ import { NotificationHandler } from "vscode-languageserver/node";
3
+
4
+ import { execute as linkExecute } from "@apollo/client/link/core";
5
+ import { toPromise } from "@apollo/client/link/utils";
6
+ import { createHttpLink, HttpOptions } from "@apollo/client/link/http";
7
+ import {
8
+ GraphQLSchema,
9
+ buildClientSchema,
10
+ getIntrospectionQuery,
11
+ ExecutionResult,
12
+ IntrospectionQuery,
13
+ parse,
14
+ } from "graphql";
15
+ import { Agent as HTTPSAgent } from "https";
16
+ import { RemoteServiceConfig } from "../../config";
17
+ import { GraphQLSchemaProvider, SchemaChangeUnsubscribeHandler } from "./base";
18
+ import { Debug } from "../../utilities";
19
+ import { isString } from "util";
20
+
21
+ export class EndpointSchemaProvider implements GraphQLSchemaProvider {
22
+ private schema?: GraphQLSchema;
23
+ private federatedServiceSDL?: string;
24
+
25
+ constructor(private config: Exclude<RemoteServiceConfig, "name">) {}
26
+ async resolveSchema() {
27
+ if (this.schema) return this.schema;
28
+ const { skipSSLValidation, url, headers } = this.config;
29
+ const options: HttpOptions = {
30
+ uri: url,
31
+ };
32
+ if (url.startsWith("https:") && skipSSLValidation) {
33
+ options.fetchOptions = {
34
+ agent: new HTTPSAgent({ rejectUnauthorized: false }),
35
+ };
36
+ }
37
+
38
+ const { data, errors } = (await toPromise(
39
+ linkExecute(createHttpLink(options), {
40
+ query: parse(getIntrospectionQuery()),
41
+ context: { headers },
42
+ }),
43
+ ).catch((e) => {
44
+ // html response from introspection
45
+ if (isString(e.message) && e.message.includes("token <")) {
46
+ throw new Error(
47
+ "Apollo tried to introspect a running GraphQL service at " +
48
+ url +
49
+ "\nIt expected a JSON schema introspection result, but got an HTML response instead." +
50
+ "\nYou may need to add headers to your request or adjust your endpoint url.\n" +
51
+ "-----------------------------\n" +
52
+ "For more information, please refer to: https://go.apollo.dev/t/config \n\n" +
53
+ "The following error occurred:\n-----------------------------\n" +
54
+ e.message,
55
+ );
56
+ }
57
+
58
+ // 404 with a non-default url
59
+ if (isString(e.message) && e.message.includes("ECONNREFUSED")) {
60
+ throw new Error(
61
+ "Failed to connect to a running GraphQL endpoint at " +
62
+ url +
63
+ "\nThis may be because you didn't start your service or the endpoint URL is incorrect.",
64
+ );
65
+ }
66
+ throw new Error(e);
67
+ })) as ExecutionResult<IntrospectionQuery>;
68
+
69
+ if (errors && errors.length) {
70
+ // XXX better error handling of GraphQL errors
71
+ throw new Error(errors.map(({ message }: Error) => message).join("\n"));
72
+ }
73
+
74
+ if (!data) {
75
+ throw new Error("No data received from server introspection.");
76
+ }
77
+
78
+ this.schema = buildClientSchema(data);
79
+ return this.schema;
80
+ }
81
+
82
+ onSchemaChange(
83
+ _handler: NotificationHandler<GraphQLSchema>,
84
+ ): SchemaChangeUnsubscribeHandler {
85
+ throw new Error("Polling of endpoint not implemented yet");
86
+ return () => {};
87
+ }
88
+
89
+ async resolveFederatedServiceSDL() {
90
+ if (this.federatedServiceSDL) return this.federatedServiceSDL;
91
+
92
+ const { skipSSLValidation, url, headers } = this.config;
93
+ const options: HttpOptions = {
94
+ uri: url,
95
+ fetch,
96
+ };
97
+ if (url.startsWith("https:") && skipSSLValidation) {
98
+ options.fetchOptions = {
99
+ agent: new HTTPSAgent({ rejectUnauthorized: false }),
100
+ };
101
+ }
102
+
103
+ const getFederationInfoQuery = `
104
+ query getFederationInfo {
105
+ _service {
106
+ sdl
107
+ }
108
+ }
109
+ `;
110
+
111
+ const { data, errors } = (await toPromise(
112
+ linkExecute(createHttpLink(options), {
113
+ query: parse(getFederationInfoQuery),
114
+ context: { headers },
115
+ }),
116
+ )) as ExecutionResult<{ _service: { sdl: string } }>;
117
+
118
+ if (errors && errors.length) {
119
+ return Debug.error(
120
+ errors.map(({ message }: Error) => message).join("\n"),
121
+ );
122
+ }
123
+
124
+ if (!data || !data._service) {
125
+ return Debug.error(
126
+ "No data received from server when querying for _service.",
127
+ );
128
+ }
129
+
130
+ this.federatedServiceSDL = data._service.sdl;
131
+ return data._service.sdl;
132
+ }
133
+
134
+ // public async isFederatedSchema() {
135
+ // const schema = this.schema || (await this.resolveSchema());
136
+ // return false;
137
+ // }
138
+ }
@@ -0,0 +1,204 @@
1
+ // EngineSchemaProvider (engine schema reg => schema)
2
+ import { NotificationHandler } from "vscode-languageserver/node";
3
+ import gql from "graphql-tag";
4
+ import { GraphQLSchema, IntrospectionQuery, buildClientSchema } from "graphql";
5
+ import { ApolloEngineClient, ClientIdentity } from "../../engine";
6
+ import { ClientConfig, keyEnvVar } from "../../config";
7
+ import {
8
+ GraphQLSchemaProvider,
9
+ SchemaChangeUnsubscribeHandler,
10
+ SchemaResolveConfig,
11
+ } from "./base";
12
+
13
+ import {
14
+ GetSchemaByTagQuery,
15
+ GetSchemaByTagQueryVariables,
16
+ } from "../../graphqlTypes";
17
+ import { Debug } from "../../utilities";
18
+ import { TypedDocumentNode } from "@apollo/client/core";
19
+
20
+ export class EngineSchemaProvider implements GraphQLSchemaProvider {
21
+ private schema?: GraphQLSchema;
22
+ private client?: ApolloEngineClient;
23
+
24
+ constructor(
25
+ private config: ClientConfig,
26
+ private clientIdentity: ClientIdentity,
27
+ ) {}
28
+
29
+ async resolveSchema(override: SchemaResolveConfig) {
30
+ if (this.schema && (!override || !override.force)) return this.schema;
31
+ const { engine, client } = this.config;
32
+
33
+ if (!this.config.graph) {
34
+ throw new Error(
35
+ `No graph ID found for client. Please specify a graph ID via the config or the --graph flag`,
36
+ );
37
+ }
38
+
39
+ // create engine client
40
+ if (!this.client) {
41
+ if (!engine.apiKey) {
42
+ throw new Error(
43
+ `No API key found. Please set ${keyEnvVar} or use --key`,
44
+ );
45
+ }
46
+ this.client = new ApolloEngineClient(
47
+ engine.apiKey,
48
+ engine.endpoint,
49
+ this.clientIdentity,
50
+ );
51
+ }
52
+
53
+ const { data, errors } = await this.client.query({
54
+ query: SCHEMA_QUERY,
55
+ variables: {
56
+ id: this.config.graph,
57
+ tag: override && override.tag ? override.tag : this.config.variant,
58
+ },
59
+ fetchPolicy: "no-cache",
60
+ });
61
+ if (errors) {
62
+ // XXX better error handling of GraphQL errors
63
+ throw new Error(errors.map(({ message }) => message).join("\n"));
64
+ }
65
+
66
+ if (!(data && data.service && data.service.__typename === "Service")) {
67
+ throw new Error(
68
+ `Unable to get schema from the Apollo registry for graph ${this.config.graph}`,
69
+ );
70
+ }
71
+
72
+ this.schema = buildClientSchema(
73
+ data.service.schema as unknown as IntrospectionQuery,
74
+ );
75
+ return this.schema;
76
+ }
77
+
78
+ onSchemaChange(
79
+ _handler: NotificationHandler<GraphQLSchema>,
80
+ ): SchemaChangeUnsubscribeHandler {
81
+ throw new Error("Polling of Apollo not implemented yet");
82
+ return () => {};
83
+ }
84
+
85
+ async resolveFederatedServiceSDL() {
86
+ Debug.error(
87
+ "Cannot resolve a federated service's SDL from Apollo. Use an endpoint or a file instead",
88
+ );
89
+ return;
90
+ }
91
+ }
92
+
93
+ export const SCHEMA_QUERY: TypedDocumentNode<
94
+ GetSchemaByTagQuery,
95
+ GetSchemaByTagQueryVariables
96
+ > = gql`
97
+ query GetSchemaByTag($tag: String!, $id: ID!) {
98
+ service(id: $id) {
99
+ ... on Service {
100
+ __typename
101
+ schema(tag: $tag) {
102
+ hash
103
+ __schema: introspection {
104
+ queryType {
105
+ name
106
+ }
107
+ mutationType {
108
+ name
109
+ }
110
+ subscriptionType {
111
+ name
112
+ }
113
+ types(filter: { includeBuiltInTypes: true }) {
114
+ ...IntrospectionFullType
115
+ }
116
+ directives {
117
+ name
118
+ description
119
+ locations
120
+ args {
121
+ ...IntrospectionInputValue
122
+ }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+
130
+ fragment IntrospectionFullType on IntrospectionType {
131
+ kind
132
+ name
133
+ description
134
+ fields {
135
+ name
136
+ description
137
+ args {
138
+ ...IntrospectionInputValue
139
+ }
140
+ type {
141
+ ...IntrospectionTypeRef
142
+ }
143
+ isDeprecated
144
+ deprecationReason
145
+ }
146
+ inputFields {
147
+ ...IntrospectionInputValue
148
+ }
149
+ interfaces {
150
+ ...IntrospectionTypeRef
151
+ }
152
+ enumValues(includeDeprecated: true) {
153
+ name
154
+ description
155
+ isDeprecated
156
+ deprecationReason
157
+ }
158
+ possibleTypes {
159
+ ...IntrospectionTypeRef
160
+ }
161
+ }
162
+
163
+ fragment IntrospectionInputValue on IntrospectionInputValue {
164
+ name
165
+ description
166
+ type {
167
+ ...IntrospectionTypeRef
168
+ }
169
+ defaultValue
170
+ }
171
+
172
+ fragment IntrospectionTypeRef on IntrospectionType {
173
+ kind
174
+ name
175
+ ofType {
176
+ kind
177
+ name
178
+ ofType {
179
+ kind
180
+ name
181
+ ofType {
182
+ kind
183
+ name
184
+ ofType {
185
+ kind
186
+ name
187
+ ofType {
188
+ kind
189
+ name
190
+ ofType {
191
+ kind
192
+ name
193
+ ofType {
194
+ kind
195
+ name
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ }
202
+ }
203
+ }
204
+ `;