@apollo/gateway 0.48.0 → 0.49.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 (60) hide show
  1. package/README.md +7 -5
  2. package/dist/__generated__/graphqlTypes.d.ts +4 -0
  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 +6 -2
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +1 -0
  8. package/dist/config.js.map +1 -1
  9. package/dist/executeQueryPlan.d.ts.map +1 -1
  10. package/dist/executeQueryPlan.js +4 -3
  11. package/dist/executeQueryPlan.js.map +1 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +23 -10
  15. package/dist/index.js.map +1 -1
  16. package/dist/schema-helper/index.js +5 -1
  17. package/dist/schema-helper/index.js.map +1 -1
  18. package/dist/schema-helper/resolverMap.d.ts +2 -2
  19. package/dist/schema-helper/resolverMap.d.ts.map +1 -1
  20. package/dist/supergraphManagers/IntrospectAndCompose/index.js.map +1 -1
  21. package/dist/supergraphManagers/LegacyFetcher/index.js +1 -1
  22. package/dist/supergraphManagers/LegacyFetcher/index.js.map +1 -1
  23. package/dist/supergraphManagers/LocalCompose/index.js +1 -1
  24. package/dist/supergraphManagers/LocalCompose/index.js.map +1 -1
  25. package/dist/supergraphManagers/UplinkFetcher/index.d.ts +4 -1
  26. package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -1
  27. package/dist/supergraphManagers/UplinkFetcher/index.js +22 -4
  28. package/dist/supergraphManagers/UplinkFetcher/index.js.map +1 -1
  29. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts +7 -2
  30. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +1 -1
  31. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js +37 -33
  32. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +1 -1
  33. package/dist/supergraphManagers/index.d.ts +1 -0
  34. package/dist/supergraphManagers/index.d.ts.map +1 -1
  35. package/dist/supergraphManagers/index.js +3 -1
  36. package/dist/supergraphManagers/index.js.map +1 -1
  37. package/package.json +6 -5
  38. package/src/__generated__/graphqlTypes.ts +11 -2
  39. package/src/__tests__/CucumberREADME.md +1 -0
  40. package/src/__tests__/build-query-plan-fragmentization.feature +10 -0
  41. package/src/__tests__/build-query-plan.feature +84 -16
  42. package/src/__tests__/buildQueryPlan.test.ts +272 -1
  43. package/src/__tests__/gateway/lifecycle-hooks.test.ts +3 -3
  44. package/src/__tests__/gateway/reporting.test.ts +4 -0
  45. package/src/__tests__/gateway/supergraphSdl.test.ts +3 -3
  46. package/src/__tests__/integration/abstract-types.test.ts +3 -3
  47. package/src/__tests__/integration/configuration.test.ts +0 -11
  48. package/src/__tests__/integration/nockMocks.ts +3 -2
  49. package/src/__tests__/integration/requires.test.ts +1 -1
  50. package/src/__tests__/integration/value-types.test.ts +1 -1
  51. package/src/config.ts +11 -6
  52. package/src/executeQueryPlan.ts +4 -0
  53. package/src/index.ts +16 -7
  54. package/src/schema-helper/resolverMap.ts +2 -2
  55. package/src/supergraphManagers/LegacyFetcher/index.ts +1 -1
  56. package/src/supergraphManagers/LocalCompose/index.ts +1 -1
  57. package/src/supergraphManagers/UplinkFetcher/__tests__/loadSupergraphSdlFromStorage.test.ts +123 -28
  58. package/src/supergraphManagers/UplinkFetcher/index.ts +39 -18
  59. package/src/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts +40 -27
  60. package/src/supergraphManagers/index.ts +1 -0
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  loadSupergraphSdlFromStorage,
3
- loadSupergraphSdlFromUplinks
3
+ loadSupergraphSdlFromUplinks,
4
+ UplinkFetcherError,
4
5
  } from '../loadSupergraphSdlFromStorage';
5
6
  import { getDefaultFetcher } from '../../..';
6
7
  import {
@@ -62,7 +63,9 @@ describe('loadSupergraphSdlFromStorage', () => {
62
63
  errorReportingEndpoint: undefined,
63
64
  fetcher,
64
65
  compositionId: "originalId-1234",
65
- maxRetries: 1
66
+ maxRetries: 1,
67
+ roundRobinSeed: 0,
68
+ earliestFetchTime: null,
66
69
  });
67
70
 
68
71
  expect(result).toMatchObject({
@@ -84,10 +87,14 @@ describe('loadSupergraphSdlFromStorage', () => {
84
87
  errorReportingEndpoint: undefined,
85
88
  fetcher,
86
89
  compositionId: "originalId-1234",
87
- maxRetries: 1
90
+ maxRetries: 1,
91
+ roundRobinSeed: 0,
92
+ earliestFetchTime: null,
88
93
  }),
89
- ).rejects.toThrowErrorMatchingInlineSnapshot(
90
- `"An error occurred while fetching your schema from Apollo: 500 Internal Server Error"`,
94
+ ).rejects.toThrowError(
95
+ new UplinkFetcherError(
96
+ "An error occurred while fetching your schema from Apollo: 500 Internal Server Error",
97
+ )
91
98
  );
92
99
  })
93
100
 
@@ -105,8 +112,10 @@ describe('loadSupergraphSdlFromStorage', () => {
105
112
  fetcher,
106
113
  compositionId: null,
107
114
  }),
108
- ).rejects.toThrowErrorMatchingInlineSnapshot(
109
- `"An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0"`,
115
+ ).rejects.toThrowError(
116
+ new UplinkFetcherError(
117
+ "An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0"
118
+ )
110
119
  );
111
120
  });
112
121
 
@@ -129,7 +138,9 @@ describe('loadSupergraphSdlFromStorage', () => {
129
138
  fetcher,
130
139
  compositionId: null,
131
140
  }),
132
- ).rejects.toThrowError(message);
141
+ ).rejects.toThrowError(
142
+ new UplinkFetcherError(`An error occurred while fetching your schema from Apollo: \n${message}`)
143
+ );
133
144
  });
134
145
 
135
146
  it("throws on non-OK status codes when `errors` isn't present in a JSON response", async () => {
@@ -146,8 +157,10 @@ describe('loadSupergraphSdlFromStorage', () => {
146
157
  fetcher,
147
158
  compositionId: null,
148
159
  }),
149
- ).rejects.toThrowErrorMatchingInlineSnapshot(
150
- `"An error occurred while fetching your schema from Apollo: 500 Internal Server Error"`,
160
+ ).rejects.toThrowError(
161
+ new UplinkFetcherError(
162
+ "An error occurred while fetching your schema from Apollo: 500 Internal Server Error"
163
+ )
151
164
  );
152
165
  });
153
166
 
@@ -166,8 +179,10 @@ describe('loadSupergraphSdlFromStorage', () => {
166
179
  fetcher,
167
180
  compositionId: null,
168
181
  }),
169
- ).rejects.toThrowErrorMatchingInlineSnapshot(
170
- `"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
182
+ ).rejects.toThrowError(
183
+ new UplinkFetcherError(
184
+ "An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input",
185
+ )
171
186
  );
172
187
  });
173
188
 
@@ -185,8 +200,10 @@ describe('loadSupergraphSdlFromStorage', () => {
185
200
  fetcher,
186
201
  compositionId: null,
187
202
  }),
188
- ).rejects.toThrowErrorMatchingInlineSnapshot(
189
- `"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
203
+ ).rejects.toThrowError(
204
+ new UplinkFetcherError(
205
+ "An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input",
206
+ )
190
207
  );
191
208
  });
192
209
 
@@ -204,8 +221,10 @@ describe('loadSupergraphSdlFromStorage', () => {
204
221
  fetcher,
205
222
  compositionId: null,
206
223
  }),
207
- ).rejects.toThrowErrorMatchingInlineSnapshot(
208
- `"An error occurred while fetching your schema from Apollo: 413 Payload Too Large"`,
224
+ ).rejects.toThrowError(
225
+ new UplinkFetcherError(
226
+ "An error occurred while fetching your schema from Apollo: 413 Payload Too Large",
227
+ )
209
228
  );
210
229
  });
211
230
 
@@ -223,8 +242,10 @@ describe('loadSupergraphSdlFromStorage', () => {
223
242
  fetcher,
224
243
  compositionId: null,
225
244
  }),
226
- ).rejects.toThrowErrorMatchingInlineSnapshot(
227
- `"An error occurred while fetching your schema from Apollo: 422 Unprocessable Entity"`,
245
+ ).rejects.toThrowError(
246
+ new UplinkFetcherError(
247
+ "An error occurred while fetching your schema from Apollo: 422 Unprocessable Entity",
248
+ )
228
249
  );
229
250
  });
230
251
 
@@ -242,8 +263,10 @@ describe('loadSupergraphSdlFromStorage', () => {
242
263
  fetcher,
243
264
  compositionId: null,
244
265
  }),
245
- ).rejects.toThrowErrorMatchingInlineSnapshot(
246
- `"An error occurred while fetching your schema from Apollo: 408 Request Timeout"`,
266
+ ).rejects.toThrowError(
267
+ new UplinkFetcherError(
268
+ "An error occurred while fetching your schema from Apollo: 408 Request Timeout",
269
+ )
247
270
  );
248
271
  });
249
272
  });
@@ -263,8 +286,10 @@ describe('loadSupergraphSdlFromStorage', () => {
263
286
  fetcher,
264
287
  compositionId: null,
265
288
  }),
266
- ).rejects.toThrowErrorMatchingInlineSnapshot(
267
- `"An error occurred while fetching your schema from Apollo: 504 Gateway Timeout"`,
289
+ ).rejects.toThrowError(
290
+ new UplinkFetcherError(
291
+ "An error occurred while fetching your schema from Apollo: 504 Gateway Timeout",
292
+ )
268
293
  );
269
294
  });
270
295
 
@@ -282,8 +307,10 @@ describe('loadSupergraphSdlFromStorage', () => {
282
307
  fetcher,
283
308
  compositionId: null,
284
309
  }),
285
- ).rejects.toThrowErrorMatchingInlineSnapshot(
286
- `"An error occurred while fetching your schema from Apollo: request to https://example1.cloud-config-url.com/cloudconfig/ failed, reason: no response"`,
310
+ ).rejects.toThrowError(
311
+ new UplinkFetcherError(
312
+ "An error occurred while fetching your schema from Apollo: request to https://example1.cloud-config-url.com/cloudconfig/ failed, reason: no response",
313
+ )
287
314
  );
288
315
  });
289
316
 
@@ -301,8 +328,10 @@ describe('loadSupergraphSdlFromStorage', () => {
301
328
  fetcher,
302
329
  compositionId: null,
303
330
  }),
304
- ).rejects.toThrowErrorMatchingInlineSnapshot(
305
- `"An error occurred while fetching your schema from Apollo: 502 Bad Gateway"`,
331
+ ).rejects.toThrowError(
332
+ new UplinkFetcherError(
333
+ "An error occurred while fetching your schema from Apollo: 502 Bad Gateway",
334
+ )
306
335
  );
307
336
  });
308
337
 
@@ -320,8 +349,10 @@ describe('loadSupergraphSdlFromStorage', () => {
320
349
  fetcher,
321
350
  compositionId: null,
322
351
  }),
323
- ).rejects.toThrowErrorMatchingInlineSnapshot(
324
- `"An error occurred while fetching your schema from Apollo: 503 Service Unavailable"`,
352
+ ).rejects.toThrowError(
353
+ new UplinkFetcherError(
354
+ "An error occurred while fetching your schema from Apollo: 503 Service Unavailable",
355
+ )
325
356
  );
326
357
  });
327
358
 
@@ -341,3 +372,67 @@ describe('loadSupergraphSdlFromStorage', () => {
341
372
  });
342
373
  });
343
374
 
375
+
376
+ describe("loadSupergraphSdlFromUplinks", () => {
377
+ beforeEach(nockBeforeEach);
378
+ afterEach(nockAfterEach);
379
+
380
+ it("doesn't retry in the unchanged / null case", async () => {
381
+ mockSupergraphSdlRequestIfAfterUnchanged("id-1234", mockCloudConfigUrl1);
382
+
383
+ const fetcher = jest.fn(getDefaultFetcher());
384
+ const result = await loadSupergraphSdlFromUplinks({
385
+ graphRef,
386
+ apiKey,
387
+ endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
388
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
389
+ fetcher: fetcher as any,
390
+ compositionId: "id-1234",
391
+ maxRetries: 5,
392
+ roundRobinSeed: 0,
393
+ earliestFetchTime: null,
394
+ });
395
+
396
+ expect(result).toBeNull();
397
+ expect(fetcher).toHaveBeenCalledTimes(1);
398
+ });
399
+
400
+ it("Waits the correct time before retrying", async () => {
401
+ const timeoutSpy = jest.spyOn(global, 'setTimeout');
402
+
403
+ mockSupergraphSdlRequest('originalId-1234', mockCloudConfigUrl1).reply(500);
404
+ mockSupergraphSdlRequestIfAfter('originalId-1234', mockCloudConfigUrl2).reply(
405
+ 200,
406
+ JSON.stringify({
407
+ data: {
408
+ routerConfig: {
409
+ __typename: 'RouterConfigResult',
410
+ id: 'originalId-1234',
411
+ supergraphSdl: getTestingSupergraphSdl()
412
+ },
413
+ },
414
+ }),
415
+ );
416
+ const fetcher = getDefaultFetcher();
417
+
418
+ await loadSupergraphSdlFromUplinks({
419
+ graphRef,
420
+ apiKey,
421
+ endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
422
+ errorReportingEndpoint: undefined,
423
+ fetcher: fetcher,
424
+ compositionId: "originalId-1234",
425
+ maxRetries: 1,
426
+ roundRobinSeed: 0,
427
+ earliestFetchTime: new Date(Date.now() + 1000),
428
+ });
429
+
430
+ // test if setTimeout was called with a value in range to deal with time jitter
431
+ const setTimeoutCall = timeoutSpy.mock.calls[1][1];
432
+ expect(setTimeoutCall).toBeLessThanOrEqual(1000);
433
+ expect(setTimeoutCall).toBeGreaterThanOrEqual(900);
434
+
435
+ timeoutSpy.mockRestore();
436
+ });
437
+ });
438
+
@@ -6,7 +6,7 @@ import { SubgraphHealthCheckFunction, SupergraphSdlUpdateFunction } from '../..'
6
6
  import { loadSupergraphSdlFromUplinks } from './loadSupergraphSdlFromStorage';
7
7
 
8
8
  export interface UplinkFetcherOptions {
9
- pollIntervalInMs: number;
9
+ fallbackPollIntervalInMs: number;
10
10
  subgraphHealthCheck?: boolean;
11
11
  graphRef: string;
12
12
  apiKey: string;
@@ -30,6 +30,9 @@ export class UplinkFetcher implements SupergraphManager {
30
30
  private errorReportingEndpoint: string | undefined =
31
31
  process.env.APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT ?? undefined;
32
32
  private compositionId?: string;
33
+ private fetchCount: number = 0;
34
+ private minDelayMs: number | null = null;
35
+ private earliestFetchTime: Date | null = null;
33
36
 
34
37
  constructor(options: UplinkFetcherOptions) {
35
38
  this.config = options;
@@ -45,7 +48,12 @@ export class UplinkFetcher implements SupergraphManager {
45
48
 
46
49
  let initialSupergraphSdl: string | null = null;
47
50
  try {
48
- initialSupergraphSdl = await this.updateSupergraphSdl();
51
+ const result = await this.updateSupergraphSdl();
52
+ initialSupergraphSdl = result?.supergraphSdl || null;
53
+ if (result?.minDelaySeconds) {
54
+ this.minDelayMs = 1000 * result?.minDelaySeconds;
55
+ this.earliestFetchTime = new Date(Date.now() + this.minDelayMs);
56
+ }
49
57
  } catch (e) {
50
58
  this.logUpdateFailure(e);
51
59
  throw e;
@@ -81,6 +89,8 @@ export class UplinkFetcher implements SupergraphManager {
81
89
  fetcher: this.config.fetcher,
82
90
  compositionId: this.compositionId ?? null,
83
91
  maxRetries: this.config.maxRetries,
92
+ roundRobinSeed: this.fetchCount++,
93
+ earliestFetchTime: this.earliestFetchTime,
84
94
  });
85
95
 
86
96
  if (!result) {
@@ -89,7 +99,8 @@ export class UplinkFetcher implements SupergraphManager {
89
99
  this.compositionId = result.id;
90
100
  // the healthCheck fn is only assigned if it's enabled in the config
91
101
  await this.healthCheck?.(result.supergraphSdl);
92
- return result.supergraphSdl;
102
+ const { supergraphSdl, minDelaySeconds } = result;
103
+ return { supergraphSdl, minDelaySeconds };
93
104
  }
94
105
  }
95
106
 
@@ -99,24 +110,34 @@ export class UplinkFetcher implements SupergraphManager {
99
110
  }
100
111
 
101
112
  private poll() {
102
- this.timerRef = setTimeout(async () => {
103
- if (this.state.phase === 'polling') {
104
- const pollingPromise = resolvable();
105
-
106
- this.state.pollingPromise = pollingPromise;
107
- try {
108
- const maybeNewSupergraphSdl = await this.updateSupergraphSdl();
109
- if (maybeNewSupergraphSdl) {
110
- this.update?.(maybeNewSupergraphSdl);
113
+ this.timerRef = setTimeout(
114
+ async () => {
115
+ if (this.state.phase === 'polling') {
116
+ const pollingPromise = resolvable();
117
+
118
+ this.state.pollingPromise = pollingPromise;
119
+ try {
120
+ const result = await this.updateSupergraphSdl();
121
+ const maybeNewSupergraphSdl = result?.supergraphSdl || null;
122
+ if (result?.minDelaySeconds) {
123
+ this.minDelayMs = 1000 * result?.minDelaySeconds;
124
+ this.earliestFetchTime = new Date(Date.now() + this.minDelayMs);
125
+ }
126
+ if (maybeNewSupergraphSdl) {
127
+ this.update?.(maybeNewSupergraphSdl);
128
+ }
129
+ } catch (e) {
130
+ this.logUpdateFailure(e);
111
131
  }
112
- } catch (e) {
113
- this.logUpdateFailure(e);
132
+ pollingPromise.resolve();
114
133
  }
115
- pollingPromise.resolve();
116
- }
117
134
 
118
- this.poll();
119
- }, this.config.pollIntervalInMs);
135
+ this.poll();
136
+ },
137
+ this.minDelayMs
138
+ ? Math.max(this.minDelayMs, this.config.fallbackPollIntervalInMs)
139
+ : this.config.fallbackPollIntervalInMs,
140
+ );
120
141
  }
121
142
 
122
143
  private logUpdateFailure(e: any) {
@@ -1,5 +1,6 @@
1
1
  import { fetch, Response, Request } from 'apollo-server-env';
2
2
  import { GraphQLError } from 'graphql';
3
+ import retry from 'async-retry';
3
4
  import { SupergraphSdlUpdate } from '../../config';
4
5
  import { submitOutOfBandReportIfConfigured } from './outOfBandReporter';
5
6
  import { SupergraphSdlQuery } from '../../__generated__/graphqlTypes';
@@ -12,6 +13,7 @@ export const SUPERGRAPH_SDL_QUERY = /* GraphQL */`#graphql
12
13
  ... on RouterConfigResult {
13
14
  id
14
15
  supergraphSdl: supergraphSDL
16
+ minDelaySeconds
15
17
  }
16
18
  ... on FetchError {
17
19
  code
@@ -39,7 +41,12 @@ const { name, version } = require('../../../package.json');
39
41
 
40
42
  const fetchErrorMsg = "An error occurred while fetching your schema from Apollo: ";
41
43
 
42
- let fetchCounter = 0;
44
+ export class UplinkFetcherError extends Error {
45
+ constructor(message: string) {
46
+ super(message);
47
+ this.name = 'UplinkFetcherError';
48
+ }
49
+ }
43
50
 
44
51
  export async function loadSupergraphSdlFromUplinks({
45
52
  graphRef,
@@ -49,6 +56,8 @@ export async function loadSupergraphSdlFromUplinks({
49
56
  fetcher,
50
57
  compositionId,
51
58
  maxRetries,
59
+ roundRobinSeed,
60
+ earliestFetchTime,
52
61
  }: {
53
62
  graphRef: string;
54
63
  apiKey: string;
@@ -56,29 +65,32 @@ export async function loadSupergraphSdlFromUplinks({
56
65
  errorReportingEndpoint: string | undefined,
57
66
  fetcher: typeof fetch;
58
67
  compositionId: string | null;
59
- maxRetries: number
68
+ maxRetries: number,
69
+ roundRobinSeed: number,
70
+ earliestFetchTime: Date | null
60
71
  }) : Promise<SupergraphSdlUpdate | null> {
61
- let retries = 0;
62
- let lastException = null;
63
- let result: SupergraphSdlUpdate | null = null;
64
- while (retries++ <= maxRetries && result == null) {
65
- try {
66
- result = await loadSupergraphSdlFromStorage({
72
+ // This Promise resolves with either an updated supergraph or null if no change.
73
+ // This Promise can reject in the case that none of the retries are successful,
74
+ // in which case it will reject with the most frequently encountered error.
75
+ return retry(
76
+ () =>
77
+ loadSupergraphSdlFromStorage({
67
78
  graphRef,
68
79
  apiKey,
69
- endpoint: endpoints[fetchCounter++ % endpoints.length],
80
+ endpoint: endpoints[roundRobinSeed++ % endpoints.length],
70
81
  errorReportingEndpoint,
71
82
  fetcher,
72
- compositionId
73
- });
74
- } catch (e) {
75
- lastException = e;
76
- }
77
- }
78
- if (result === null && lastException !== null) {
79
- throw lastException;
80
- }
81
- return result;
83
+ compositionId,
84
+ }),
85
+ {
86
+ retries: maxRetries,
87
+ onRetry: async () => {
88
+ const delayMS = earliestFetchTime ? earliestFetchTime.getTime() - Date.now(): 0;
89
+ if (delayMS > 0) await new Promise(resolve => setTimeout(resolve, delayMS));
90
+ }
91
+ },
92
+ );
93
+
82
94
  }
83
95
 
84
96
  export async function loadSupergraphSdlFromStorage({
@@ -132,7 +144,7 @@ export async function loadSupergraphSdlFromStorage({
132
144
  fetcher,
133
145
  });
134
146
 
135
- throw new Error(fetchErrorMsg + (e.message ?? e));
147
+ throw new UplinkFetcherError(fetchErrorMsg + (e.message ?? e));
136
148
  }
137
149
 
138
150
  const endTime = new Date();
@@ -143,11 +155,11 @@ export async function loadSupergraphSdlFromStorage({
143
155
  response = await result.json();
144
156
  } catch (e) {
145
157
  // Bad response
146
- throw new Error(fetchErrorMsg + result.status + ' ' + e.message ?? e);
158
+ throw new UplinkFetcherError(fetchErrorMsg + result.status + ' ' + e.message ?? e);
147
159
  }
148
160
 
149
161
  if ('errors' in response) {
150
- throw new Error(
162
+ throw new UplinkFetcherError(
151
163
  [fetchErrorMsg, ...response.errors.map((error) => error.message)].join(
152
164
  '\n',
153
165
  ),
@@ -155,7 +167,7 @@ export async function loadSupergraphSdlFromStorage({
155
167
  }
156
168
  } else {
157
169
  await submitOutOfBandReportIfConfigured({
158
- error: new Error(fetchErrorMsg + result.status + ' ' + result.statusText),
170
+ error: new UplinkFetcherError(fetchErrorMsg + result.status + ' ' + result.statusText),
159
171
  request,
160
172
  endpoint: errorReportingEndpoint,
161
173
  response: result,
@@ -163,7 +175,7 @@ export async function loadSupergraphSdlFromStorage({
163
175
  endedAt: endTime,
164
176
  fetcher,
165
177
  });
166
- throw new Error(fetchErrorMsg + result.status + ' ' + result.statusText);
178
+ throw new UplinkFetcherError(fetchErrorMsg + result.status + ' ' + result.statusText);
167
179
  }
168
180
 
169
181
  const { routerConfig } = response.data;
@@ -171,16 +183,17 @@ export async function loadSupergraphSdlFromStorage({
171
183
  const {
172
184
  id,
173
185
  supergraphSdl,
186
+ minDelaySeconds,
174
187
  // messages,
175
188
  } = routerConfig;
176
- return { id, supergraphSdl: supergraphSdl! };
189
+ return { id, supergraphSdl: supergraphSdl!, minDelaySeconds };
177
190
  } else if (routerConfig.__typename === 'FetchError') {
178
191
  // FetchError case
179
192
  const { code, message } = routerConfig;
180
- throw new Error(`${code}: ${message}`);
193
+ throw new UplinkFetcherError(`${code}: ${message}`);
181
194
  } else if (routerConfig.__typename === 'Unchanged') {
182
195
  return null;
183
196
  } else {
184
- throw new Error('Programming error: unhandled response failure');
197
+ throw new UplinkFetcherError('Programming error: unhandled response failure');
185
198
  }
186
199
  }
@@ -2,3 +2,4 @@ export { LocalCompose } from './LocalCompose';
2
2
  export { LegacyFetcher } from './LegacyFetcher';
3
3
  export { IntrospectAndCompose } from './IntrospectAndCompose';
4
4
  export { UplinkFetcher } from './UplinkFetcher';
5
+ export { UplinkFetcherError } from './UplinkFetcher/loadSupergraphSdlFromStorage'