@apollo/gateway 2.0.0-alpha.1 → 2.0.0-alpha.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.
Files changed (61) hide show
  1. package/README.md +1 -1
  2. package/dist/__generated__/graphqlTypes.d.ts +13 -11
  3. package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
  4. package/dist/__generated__/graphqlTypes.js.map +1 -1
  5. package/dist/config.d.ts +2 -9
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +6 -17
  8. package/dist/config.js.map +1 -1
  9. package/dist/datasources/types.d.ts +1 -1
  10. package/dist/datasources/types.d.ts.map +1 -1
  11. package/dist/executeQueryPlan.d.ts.map +1 -1
  12. package/dist/executeQueryPlan.js +4 -4
  13. package/dist/executeQueryPlan.js.map +1 -1
  14. package/dist/index.d.ts +1 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +14 -28
  17. package/dist/index.js.map +1 -1
  18. package/dist/loadSupergraphSdlFromStorage.d.ts +4 -3
  19. package/dist/loadSupergraphSdlFromStorage.d.ts.map +1 -1
  20. package/dist/loadSupergraphSdlFromStorage.js +7 -3
  21. package/dist/loadSupergraphSdlFromStorage.js.map +1 -1
  22. package/dist/operationContext.js +0 -1
  23. package/dist/operationContext.js.map +1 -1
  24. package/dist/utilities/array.js +1 -1
  25. package/dist/utilities/array.js.map +1 -1
  26. package/package.json +8 -9
  27. package/src/__generated__/graphqlTypes.ts +13 -11
  28. package/src/__tests__/buildQueryPlan.test.ts +1 -1
  29. package/src/__tests__/executeQueryPlan.test.ts +572 -76
  30. package/src/__tests__/execution-utils.ts +2 -4
  31. package/src/__tests__/gateway/composedSdl.test.ts +1 -1
  32. package/src/__tests__/gateway/executor.test.ts +2 -0
  33. package/src/__tests__/gateway/lifecycle-hooks.test.ts +8 -4
  34. package/src/__tests__/gateway/opentelemetry.test.ts +1 -0
  35. package/src/__tests__/gateway/queryPlanCache.test.ts +3 -0
  36. package/src/__tests__/integration/aliases.test.ts +1 -0
  37. package/src/__tests__/integration/configuration.test.ts +3 -21
  38. package/src/__tests__/integration/logger.test.ts +1 -1
  39. package/src/__tests__/integration/networkRequests.test.ts +53 -28
  40. package/src/__tests__/integration/nockMocks.ts +33 -5
  41. package/src/__tests__/loadServicesFromRemoteEndpoint.test.ts +2 -2
  42. package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +36 -6
  43. package/src/config.ts +8 -43
  44. package/src/core/__tests__/core.test.ts +6 -6
  45. package/src/datasources/types.ts +1 -1
  46. package/src/executeQueryPlan.ts +4 -7
  47. package/src/index.ts +22 -50
  48. package/src/loadServicesFromRemoteEndpoint.ts +1 -1
  49. package/src/loadSupergraphSdlFromStorage.ts +7 -4
  50. package/src/make-fetch-happen.d.ts +1 -1
  51. package/src/operationContext.ts +2 -2
  52. package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +1 -1
  53. package/src/utilities/array.ts +1 -1
  54. package/CHANGELOG.md +0 -452
  55. package/dist/legacyLoadServicesFromStorage.d.ts +0 -20
  56. package/dist/legacyLoadServicesFromStorage.d.ts.map +0 -1
  57. package/dist/legacyLoadServicesFromStorage.js +0 -62
  58. package/dist/legacyLoadServicesFromStorage.js.map +0 -1
  59. package/src/__tests__/integration/legacyNetworkRequests.test.ts +0 -279
  60. package/src/__tests__/integration/legacyNockMocks.ts +0 -113
  61. package/src/legacyLoadServicesFromStorage.ts +0 -170
@@ -8,6 +8,7 @@ import {
8
8
  mockOutOfBandReporterUrl,
9
9
  mockOutOfBandReportRequestSuccess,
10
10
  mockSupergraphSdlRequestSuccess,
11
+ mockSupergraphSdlRequestIfAfterUnchanged,
11
12
  } from './integration/nockMocks';
12
13
  import mockedEnv from 'mocked-env';
13
14
 
@@ -30,6 +31,8 @@ describe('loadSupergraphSdlFromStorage', () => {
30
31
  apiKey,
31
32
  endpoint: mockCloudConfigUrl,
32
33
  fetcher,
34
+ compositionId: null,
35
+
33
36
  });
34
37
 
35
38
  expect(result).toMatchInlineSnapshot(`
@@ -190,12 +193,12 @@ describe('loadSupergraphSdlFromStorage', () => {
190
193
  scalar join__FieldSet
191
194
 
192
195
  enum join__Graph {
193
- ACCOUNTS @join__graph(name: \\"accounts\\", url: \\"https://accounts.api.com\\")
194
- BOOKS @join__graph(name: \\"books\\", url: \\"https://books.api.com\\")
195
- DOCUMENTS @join__graph(name: \\"documents\\", url: \\"https://documents.api.com\\")
196
- INVENTORY @join__graph(name: \\"inventory\\", url: \\"https://inventory.api.com\\")
197
- PRODUCT @join__graph(name: \\"product\\", url: \\"https://product.api.com\\")
198
- REVIEWS @join__graph(name: \\"reviews\\", url: \\"https://reviews.api.com\\")
196
+ ACCOUNTS @join__graph(name: \\"accounts\\", url: \\"https://accounts.api.com.invalid\\")
197
+ BOOKS @join__graph(name: \\"books\\", url: \\"https://books.api.com.invalid\\")
198
+ DOCUMENTS @join__graph(name: \\"documents\\", url: \\"https://documents.api.com.invalid\\")
199
+ INVENTORY @join__graph(name: \\"inventory\\", url: \\"https://inventory.api.com.invalid\\")
200
+ PRODUCT @join__graph(name: \\"product\\", url: \\"https://product.api.com.invalid\\")
201
+ REVIEWS @join__graph(name: \\"reviews\\", url: \\"https://reviews.api.com.invalid\\")
199
202
  }
200
203
 
201
204
  scalar JSON
@@ -433,6 +436,8 @@ describe('loadSupergraphSdlFromStorage', () => {
433
436
  apiKey,
434
437
  endpoint: mockCloudConfigUrl,
435
438
  fetcher,
439
+ compositionId: null,
440
+
436
441
  }),
437
442
  ).rejects.toThrowErrorMatchingInlineSnapshot(
438
443
  `"An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0"`,
@@ -455,6 +460,7 @@ describe('loadSupergraphSdlFromStorage', () => {
455
460
  apiKey,
456
461
  endpoint: mockCloudConfigUrl,
457
462
  fetcher,
463
+ compositionId: null,
458
464
  }),
459
465
  ).rejects.toThrowError(message);
460
466
  });
@@ -469,6 +475,7 @@ describe('loadSupergraphSdlFromStorage', () => {
469
475
  apiKey,
470
476
  endpoint: mockCloudConfigUrl,
471
477
  fetcher,
478
+ compositionId: null,
472
479
  }),
473
480
  ).rejects.toThrowErrorMatchingInlineSnapshot(
474
481
  `"An error occurred while fetching your schema from Apollo: 500 Internal Server Error"`,
@@ -487,6 +494,7 @@ describe('loadSupergraphSdlFromStorage', () => {
487
494
  apiKey,
488
495
  endpoint: mockCloudConfigUrl,
489
496
  fetcher,
497
+ compositionId: null,
490
498
  }),
491
499
  ).rejects.toThrowErrorMatchingInlineSnapshot(
492
500
  `"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
@@ -508,6 +516,7 @@ describe('loadSupergraphSdlFromStorage', () => {
508
516
  apiKey,
509
517
  endpoint: mockCloudConfigUrl,
510
518
  fetcher,
519
+ compositionId: null,
511
520
  }),
512
521
  ).rejects.toThrowErrorMatchingInlineSnapshot(
513
522
  `"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
@@ -529,6 +538,7 @@ describe('loadSupergraphSdlFromStorage', () => {
529
538
  apiKey,
530
539
  endpoint: mockCloudConfigUrl,
531
540
  fetcher,
541
+ compositionId: null,
532
542
  }),
533
543
  ).rejects.toThrowErrorMatchingInlineSnapshot(
534
544
  `"An error occurred while fetching your schema from Apollo: 413 Payload Too Large"`,
@@ -550,6 +560,7 @@ describe('loadSupergraphSdlFromStorage', () => {
550
560
  apiKey,
551
561
  endpoint: mockCloudConfigUrl,
552
562
  fetcher,
563
+ compositionId: null,
553
564
  }),
554
565
  ).rejects.toThrowErrorMatchingInlineSnapshot(
555
566
  `"An error occurred while fetching your schema from Apollo: 422 Unprocessable Entity"`,
@@ -571,6 +582,7 @@ describe('loadSupergraphSdlFromStorage', () => {
571
582
  apiKey,
572
583
  endpoint: mockCloudConfigUrl,
573
584
  fetcher,
585
+ compositionId: null,
574
586
  }),
575
587
  ).rejects.toThrowErrorMatchingInlineSnapshot(
576
588
  `"An error occurred while fetching your schema from Apollo: 408 Request Timeout"`,
@@ -593,6 +605,7 @@ describe('loadSupergraphSdlFromStorage', () => {
593
605
  apiKey,
594
606
  endpoint: mockCloudConfigUrl,
595
607
  fetcher,
608
+ compositionId: null,
596
609
  }),
597
610
  ).rejects.toThrowErrorMatchingInlineSnapshot(
598
611
  `"An error occurred while fetching your schema from Apollo: 504 Gateway Timeout"`,
@@ -614,6 +627,7 @@ describe('loadSupergraphSdlFromStorage', () => {
614
627
  apiKey,
615
628
  endpoint: mockCloudConfigUrl,
616
629
  fetcher,
630
+ compositionId: null,
617
631
  }),
618
632
  ).rejects.toThrowErrorMatchingInlineSnapshot(
619
633
  `"An error occurred while fetching your schema from Apollo: request to https://example.cloud-config-url.com/cloudconfig/ failed, reason: no response"`,
@@ -635,6 +649,7 @@ describe('loadSupergraphSdlFromStorage', () => {
635
649
  apiKey,
636
650
  endpoint: mockCloudConfigUrl,
637
651
  fetcher,
652
+ compositionId: null,
638
653
  }),
639
654
  ).rejects.toThrowErrorMatchingInlineSnapshot(
640
655
  `"An error occurred while fetching your schema from Apollo: 502 Bad Gateway"`,
@@ -656,9 +671,24 @@ describe('loadSupergraphSdlFromStorage', () => {
656
671
  apiKey,
657
672
  endpoint: mockCloudConfigUrl,
658
673
  fetcher,
674
+ compositionId: null,
659
675
  }),
660
676
  ).rejects.toThrowErrorMatchingInlineSnapshot(
661
677
  `"An error occurred while fetching your schema from Apollo: 503 Service Unavailable"`,
662
678
  );
663
679
  });
680
+
681
+ it('successfully responds to SDL unchanged by returning null', async () => {
682
+ mockSupergraphSdlRequestIfAfterUnchanged("id-1234");
683
+
684
+ const fetcher = getDefaultFetcher();
685
+ const result = await loadSupergraphSdlFromStorage({
686
+ graphRef,
687
+ apiKey,
688
+ endpoint: mockCloudConfigUrl,
689
+ fetcher,
690
+ compositionId: "id-1234",
691
+ });
692
+ expect(result).toBeNull();
693
+ });
664
694
  });
package/src/config.ts CHANGED
@@ -2,11 +2,11 @@ import { GraphQLError, GraphQLSchema } from "graphql";
2
2
  import { HeadersInit } from "node-fetch";
3
3
  import { fetch } from 'apollo-server-env';
4
4
  import { GraphQLRequestContextExecutionDidStart, Logger } from "apollo-server-types";
5
- import { ServiceDefinition } from "@apollo/federation";
6
5
  import { GraphQLDataSource } from './datasources/types';
7
6
  import { QueryPlan } from '@apollo/query-planner';
8
7
  import { OperationContext } from './operationContext';
9
8
  import { ServiceMap } from './executeQueryPlan';
9
+ import { ServiceDefinition } from "@apollo/federation-internals";
10
10
 
11
11
  export type ServiceEndpointDefinition = Pick<ServiceDefinition, 'name' | 'url'>;
12
12
 
@@ -135,31 +135,14 @@ export interface RemoteGatewayConfig extends GatewayConfigBase {
135
135
  | ((service: ServiceEndpointDefinition) => Promise<HeadersInit> | HeadersInit);
136
136
  }
137
137
 
138
- // TODO(trevor:cloudconfig): This type goes away
139
- export interface LegacyManagedGatewayConfig extends GatewayConfigBase {
140
- federationVersion?: number;
141
- /**
142
- * Setting this to null will cause the gateway to use the old mechanism for
143
- * managed federation via GCS + composition.
144
- */
145
- schemaConfigDeliveryEndpoint: null;
146
- }
147
-
148
- // TODO(trevor:cloudconfig): This type becomes the only managed config
149
- export interface PrecomposedManagedGatewayConfig extends GatewayConfigBase {
138
+ export interface ManagedGatewayConfig extends GatewayConfigBase {
150
139
  /**
151
140
  * This configuration option shouldn't be used unless by recommendation from
152
- * Apollo staff. This can also be set to `null` (see above) in order to revert
153
- * to the previous mechanism for managed federation.
141
+ * Apollo staff.
154
142
  */
155
143
  schemaConfigDeliveryEndpoint?: string;
156
144
  }
157
145
 
158
- // TODO(trevor:cloudconfig): This union is no longer needed
159
- export type ManagedGatewayConfig =
160
- | LegacyManagedGatewayConfig
161
- | PrecomposedManagedGatewayConfig;
162
-
163
146
  interface ManuallyManagedServiceDefsGatewayConfig extends GatewayConfigBase {
164
147
  experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions;
165
148
  }
@@ -216,30 +199,12 @@ export function isManuallyManagedConfig(
216
199
  export function isManagedConfig(
217
200
  config: GatewayConfig,
218
201
  ): config is ManagedGatewayConfig {
219
- return isPrecomposedManagedConfig(config) || isLegacyManagedConfig(config);
220
- }
221
-
222
- // TODO(trevor:cloudconfig): This merges with `isManagedConfig`
223
- export function isPrecomposedManagedConfig(
224
- config: GatewayConfig,
225
- ): config is PrecomposedManagedGatewayConfig {
226
- return (
227
- !isLegacyManagedConfig(config) &&
228
- (('schemaConfigDeliveryEndpoint' in config &&
229
- typeof config.schemaConfigDeliveryEndpoint === 'string') ||
230
- (!isRemoteConfig(config) &&
231
- !isLocalConfig(config) &&
232
- !isSupergraphSdlConfig(config) &&
233
- !isManuallyManagedConfig(config)))
234
- );
235
- }
236
-
237
- export function isLegacyManagedConfig(
238
- config: GatewayConfig,
239
- ): config is LegacyManagedGatewayConfig {
240
202
  return (
241
- 'schemaConfigDeliveryEndpoint' in config &&
242
- config.schemaConfigDeliveryEndpoint === null
203
+ 'schemaConfigDeliveryEndpoint' in config ||
204
+ (!isRemoteConfig(config) &&
205
+ !isLocalConfig(config) &&
206
+ !isSupergraphSdlConfig(config) &&
207
+ !isManuallyManagedConfig(config))
243
208
  );
244
209
  }
245
210
 
@@ -41,7 +41,7 @@ describe('core v0.1', () => {
41
41
  scalar join__FieldSet
42
42
 
43
43
  enum join__Graph {
44
- WORLD @join__graph(name: "world", url: "https://world.api.com")
44
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
45
45
  }
46
46
 
47
47
  type Query {
@@ -97,7 +97,7 @@ describe('core v0.1', () => {
97
97
  scalar join__FieldSet
98
98
 
99
99
  enum join__Graph {
100
- WORLD @join__graph(name: "world", url: "https://world.api.com")
100
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
101
101
  }
102
102
 
103
103
  type Query {
@@ -173,7 +173,7 @@ describe('core v0.2', () => {
173
173
  scalar join__FieldSet
174
174
 
175
175
  enum join__Graph {
176
- WORLD @join__graph(name: "world", url: "https://world.api.com")
176
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
177
177
  }
178
178
 
179
179
  type Query {
@@ -243,7 +243,7 @@ describe('core v0.2', () => {
243
243
  scalar join__FieldSet
244
244
 
245
245
  enum join__Graph {
246
- WORLD @join__graph(name: "world", url: "https://world.api.com")
246
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
247
247
  }
248
248
 
249
249
  type Query {
@@ -315,7 +315,7 @@ describe('core v0.2', () => {
315
315
  scalar join__FieldSet
316
316
 
317
317
  enum join__Graph {
318
- WORLD @join__graph(name: "world", url: "https://world.api.com")
318
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
319
319
  }
320
320
 
321
321
  type Query {
@@ -391,7 +391,7 @@ describe('core v0.2', () => {
391
391
  scalar join__FieldSet
392
392
 
393
393
  enum join__Graph {
394
- WORLD @join__graph(name: "world", url: "https://world.api.com")
394
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
395
395
  }
396
396
 
397
397
  type Query {
@@ -47,6 +47,6 @@ export type GraphQLDataSourceProcessOptions<
47
47
  /**
48
48
  * Mostly provided for historical reasons.
49
49
  */
50
- context: {};
50
+ context: Record<string, any>;
51
51
  }
52
52
  );
@@ -14,7 +14,6 @@ import {
14
14
  GraphQLSchema,
15
15
  } from 'graphql';
16
16
  import { Trace, google } from 'apollo-reporting-protobuf';
17
- import { defaultRootOperationNameLookup } from '@apollo/federation';
18
17
  import { GraphQLDataSource, GraphQLDataSourceRequestKind } from './datasources/types';
19
18
  import { OperationContext } from './operationContext';
20
19
  import {
@@ -30,6 +29,7 @@ import { deepMerge } from './utilities/deepMerge';
30
29
  import { isNotNullOrUndefined } from './utilities/array';
31
30
  import { SpanStatusCode } from "@opentelemetry/api";
32
31
  import { OpenTelemetrySpanNames, tracer } from "./utilities/opentelemetry";
32
+ import { defaultRootName } from '@apollo/federation-internals';
33
33
 
34
34
  export type ServiceMap = {
35
35
  [serviceName: string]: GraphQLDataSource;
@@ -85,7 +85,7 @@ export async function executeQueryPlan<TContext>(
85
85
  }
86
86
  }
87
87
 
88
- let result = await tracer.startActiveSpan(OpenTelemetrySpanNames.POST_PROCESSING, async (span) => {
88
+ const result = await tracer.startActiveSpan(OpenTelemetrySpanNames.POST_PROCESSING, async (span) => {
89
89
 
90
90
  // FIXME: Re-executing the query is a pretty heavy handed way of making sure
91
91
  // only explicitly requested fields are included and field ordering follows
@@ -278,7 +278,7 @@ async function executeFetch<TContext>(
278
278
 
279
279
  if (entities.length < 1) return;
280
280
 
281
- let variables = Object.create(null);
281
+ const variables = Object.create(null);
282
282
  if (fetch.variableUsages) {
283
283
  for (const variableName of fetch.variableUsages) {
284
284
  const providedVariables = context.requestContext.request.variables;
@@ -450,10 +450,7 @@ async function executeFetch<TContext>(
450
450
  // to have the default names (Query, Mutation, Subscription) even
451
451
  // if the implementing services choose different names, so we override
452
452
  // whatever the implementing service reported here.
453
- const rootTypeName =
454
- defaultRootOperationNameLookup[
455
- context.operationContext.operation.operation
456
- ];
453
+ const rootTypeName = defaultRootName(context.operationContext.operation.operation);
457
454
  traceNode.trace.root?.child?.forEach((child) => {
458
455
  child.parentType = rootTypeName;
459
456
  });
package/src/index.ts CHANGED
@@ -12,9 +12,6 @@ import {
12
12
  GraphQLSchema,
13
13
  VariableDefinitionNode,
14
14
  } from 'graphql';
15
- import {
16
- ServiceDefinition,
17
- } from '@apollo/federation';
18
15
  import loglevel from 'loglevel';
19
16
 
20
17
  import { buildOperationContext, OperationContext } from './operationContext';
@@ -59,11 +56,8 @@ import {
59
56
  ServiceDefinitionUpdate,
60
57
  SupergraphSdlUpdate,
61
58
  CompositionUpdate,
62
- isPrecomposedManagedConfig,
63
- isLegacyManagedConfig,
64
59
  } from './config';
65
60
  import { loadSupergraphSdlFromStorage } from './loadSupergraphSdlFromStorage';
66
- import { getServiceDefinitionsFromStorage } from './legacyLoadServicesFromStorage';
67
61
  import { SpanStatusCode } from '@opentelemetry/api';
68
62
  import { OpenTelemetrySpanNames, tracer } from './utilities/opentelemetry';
69
63
 
@@ -71,6 +65,7 @@ import {
71
65
  buildSupergraphSchema,
72
66
  operationFromDocument,
73
67
  Schema,
68
+ ServiceDefinition,
74
69
  } from '@apollo/federation-internals';
75
70
  import { composeServices } from '@apollo/composition'
76
71
 
@@ -87,6 +82,8 @@ type WarnedStates = {
87
82
  remoteWithLocalConfig?: boolean;
88
83
  };
89
84
 
85
+ export { ServiceDefinition } from '@apollo/federation-internals';
86
+
90
87
  export function getDefaultFetcher() {
91
88
  const { name, version } = require('../package.json');
92
89
  return fetcher.defaults({
@@ -111,20 +108,6 @@ export function getDefaultFetcher() {
111
108
  });
112
109
  }
113
110
 
114
- /**
115
- * TODO(trevor:cloudconfig): Stop exporting this
116
- * @deprecated This will be removed in a future version of @apollo/gateway
117
- */
118
- export const getDefaultGcsFetcher = deprecate(
119
- getDefaultFetcher,
120
- `'getDefaultGcsFetcher' is deprecated. Use 'getDefaultFetcher' instead.`,
121
- );
122
- /**
123
- * TODO(trevor:cloudconfig): Stop exporting this
124
- * @deprecated This will be removed in a future version of @apollo/gateway
125
- */
126
- export const GCS_RETRY_COUNT = 5;
127
-
128
111
  export const HEALTH_CHECK_QUERY =
129
112
  'query __ApolloServiceHealthCheck__ { __typename }';
130
113
  export const SERVICE_DEFINITION_QUERY =
@@ -220,10 +203,8 @@ export class ApolloGateway implements GraphQLService {
220
203
  private experimental_pollInterval?: number;
221
204
  // Configure the endpoint by which gateway will access its precomposed schema.
222
205
  // * `string` means use that endpoint
223
- // * `null` will revert the gateway to legacy mode (polling GCS and composing the schema itself).
224
206
  // * `undefined` means the gateway is not using managed federation
225
- // TODO(trevor:cloudconfig): `null` should be disallowed in the future.
226
- private schemaConfigDeliveryEndpoint?: string | null;
207
+ private schemaConfigDeliveryEndpoint?: string;
227
208
 
228
209
  constructor(config?: GatewayConfig) {
229
210
  this.config = {
@@ -251,19 +232,14 @@ export class ApolloGateway implements GraphQLService {
251
232
  this.experimental_pollInterval = config?.experimental_pollInterval;
252
233
 
253
234
  // 1. If config is set to a `string`, use it
254
- // 2. If config is explicitly set to `null`, fallback to GCS
255
- // 3. If the env var is set, use that
256
- // 4. If config is `undefined`, use the default uplink URL
257
-
258
- // This if case unobviously handles 1, 2, and 4.
259
- if (isPrecomposedManagedConfig(this.config)) {
235
+ // 2. If the env var is set, use that
236
+ // 3. If config is `undefined`, use the default uplink URL
237
+ if (isManagedConfig(this.config)) {
260
238
  const envEndpoint = process.env.APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT;
261
239
  this.schemaConfigDeliveryEndpoint =
262
240
  this.config.schemaConfigDeliveryEndpoint ??
263
241
  envEndpoint ??
264
242
  'https://uplink.api.apollographql.com/';
265
- } else if (isLegacyManagedConfig(this.config)) {
266
- this.schemaConfigDeliveryEndpoint = null;
267
243
  }
268
244
 
269
245
  if (isManuallyManagedConfig(this.config)) {
@@ -617,7 +593,7 @@ export class ApolloGateway implements GraphQLService {
617
593
  legacyDontNotifyOnSchemaChangeListeners: boolean = false,
618
594
  ): void {
619
595
  if (this.queryPlanStore) this.queryPlanStore.flush();
620
- this.apiSchema = coreSchema.toAPISchema();
596
+ this.apiSchema = coreSchema.toAPISchema();
621
597
  this.schema = wrapSchemaWithAliasResolver(this.apiSchema.toGraphQLJSSchema());
622
598
  this.queryPlanner = new QueryPlanner(coreSchema);
623
599
 
@@ -940,24 +916,20 @@ export class ApolloGateway implements GraphQLService {
940
916
  );
941
917
  }
942
918
 
943
- // TODO(trevor:cloudconfig): This condition goes away completely
944
- if (isPrecomposedManagedConfig(config)) {
945
- return loadSupergraphSdlFromStorage({
946
- graphRef: this.apolloConfig!.graphRef!,
947
- apiKey: this.apolloConfig!.key!,
948
- endpoint: this.schemaConfigDeliveryEndpoint!,
949
- fetcher: this.fetcher,
950
- });
951
- } else if (isLegacyManagedConfig(config)) {
952
- return getServiceDefinitionsFromStorage({
953
- graphRef: this.apolloConfig!.graphRef!,
954
- apiKeyHash: this.apolloConfig!.keyHash!,
955
- federationVersion: config.federationVersion || 1,
956
- fetcher: this.fetcher,
957
- });
958
- } else {
959
- throw new Error('Programming error: unhandled configuration');
960
- }
919
+ const result = await loadSupergraphSdlFromStorage({
920
+ graphRef: this.apolloConfig!.graphRef!,
921
+ apiKey: this.apolloConfig!.key!,
922
+ endpoint: this.schemaConfigDeliveryEndpoint!,
923
+ fetcher: this.fetcher,
924
+ compositionId: this.compositionId ?? null,
925
+ });
926
+
927
+ return (
928
+ result ?? {
929
+ id: this.compositionId!,
930
+ supergraphSdl: this.supergraphSdl!,
931
+ }
932
+ );
961
933
  }
962
934
 
963
935
  private maybeWarnOnConflictingConfig() {
@@ -4,7 +4,7 @@ import { Headers, HeadersInit } from 'node-fetch';
4
4
  import { GraphQLDataSource, GraphQLDataSourceRequestKind } from './datasources/types';
5
5
  import { SERVICE_DEFINITION_QUERY } from './';
6
6
  import { CompositionUpdate, ServiceEndpointDefinition } from './config';
7
- import { ServiceDefinition } from '@apollo/federation';
7
+ import { ServiceDefinition } from '@apollo/federation-internals';
8
8
 
9
9
  type Service = ServiceEndpointDefinition & {
10
10
  dataSource: GraphQLDataSource;
@@ -5,8 +5,8 @@ import { SupergraphSdlQuery } from './__generated__/graphqlTypes';
5
5
 
6
6
  // Magic /* GraphQL */ comment below is for codegen, do not remove
7
7
  export const SUPERGRAPH_SDL_QUERY = /* GraphQL */`#graphql
8
- query SupergraphSdl($apiKey: String!, $ref: String!) {
9
- routerConfig(ref: $ref, apiKey: $apiKey) {
8
+ query SupergraphSdl($apiKey: String!, $ref: String!, $ifAfterId: ID) {
9
+ routerConfig(ref: $ref, apiKey: $apiKey, ifAfterId: $ifAfterId) {
10
10
  __typename
11
11
  ... on RouterConfigResult {
12
12
  id
@@ -43,11 +43,13 @@ export async function loadSupergraphSdlFromStorage({
43
43
  apiKey,
44
44
  endpoint,
45
45
  fetcher,
46
+ compositionId,
46
47
  }: {
47
48
  graphRef: string;
48
49
  apiKey: string;
49
50
  endpoint: string;
50
51
  fetcher: typeof fetch;
52
+ compositionId: string | null;
51
53
  }) {
52
54
  let result: Response;
53
55
  const requestDetails = {
@@ -57,6 +59,7 @@ export async function loadSupergraphSdlFromStorage({
57
59
  variables: {
58
60
  ref: graphRef,
59
61
  apiKey,
62
+ ifAfterId: compositionId,
60
63
  },
61
64
  }),
62
65
  headers: {
@@ -124,13 +127,13 @@ export async function loadSupergraphSdlFromStorage({
124
127
  supergraphSdl,
125
128
  // messages,
126
129
  } = routerConfig;
127
-
128
- // `supergraphSdl` should not be nullable in the schema, but it currently is
129
130
  return { id, supergraphSdl: supergraphSdl! };
130
131
  } else if (routerConfig.__typename === 'FetchError') {
131
132
  // FetchError case
132
133
  const { code, message } = routerConfig;
133
134
  throw new Error(`${code}: ${message}`);
135
+ } else if (routerConfig.__typename === 'Unchanged') {
136
+ return null;
134
137
  } else {
135
138
  throw new Error('Programming error: unhandled response failure');
136
139
  }
@@ -36,7 +36,7 @@ declare module 'make-fetch-happen' {
36
36
  }
37
37
 
38
38
  export interface CacheManager {
39
- delete(req: Request): Promise<Boolean>;
39
+ delete(req: Request): Promise<boolean>;
40
40
  put(req: Request, res: Response): Promise<Response>;
41
41
  match(req: Request): Promise<Response | undefined>;
42
42
  }
@@ -20,7 +20,7 @@ interface BuildOperationContextOptions {
20
20
  schema: GraphQLSchema;
21
21
  operationDocument: DocumentNode;
22
22
  operationName?: string;
23
- };
23
+ }
24
24
 
25
25
  export function buildOperationContext({
26
26
  schema,
@@ -28,7 +28,7 @@ export function buildOperationContext({
28
28
  operationName,
29
29
  }: BuildOperationContextOptions): OperationContext {
30
30
  let operation: OperationDefinitionNode | undefined;
31
- let operationCount: number = 0;
31
+ let operationCount = 0;
32
32
  const fragments: {
33
33
  [fragmentName: string]: FragmentDefinitionNode;
34
34
  } = Object.create(null);
@@ -56,7 +56,7 @@ describe('cleanErrorOfInaccessibleNames', () => {
56
56
  },
57
57
  });
58
58
 
59
- const cleaned = cleanErrorOfInaccessibleNames(schema, result.errors?.[0]!);
59
+ const cleaned = cleanErrorOfInaccessibleNames(schema, result.errors![0]!);
60
60
  expect(cleaned.message).toMatchInlineSnapshot(
61
61
  `"Abstract type \\"Foo\\" was resolve to a type [inaccessible type] that does not exist inside schema."`,
62
62
  );
@@ -27,7 +27,7 @@ export function findAndExtract<T>(
27
27
  const index = array.findIndex(predicate);
28
28
  if (index === -1) return [undefined, array];
29
29
 
30
- let remaining = array.slice(0, index);
30
+ const remaining = array.slice(0, index);
31
31
  if (index < array.length - 1) {
32
32
  remaining.push(...array.slice(index + 1));
33
33
  }