@apollo/gateway 0.44.0 → 0.45.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.
- package/CHANGELOG.md +14 -3
- package/dist/__generated__/graphqlTypes.d.ts +13 -12
- package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
- package/dist/__generated__/graphqlTypes.js.map +1 -1
- package/dist/config.d.ts +3 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -17
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -37
- package/dist/index.js.map +1 -1
- package/dist/loadSupergraphSdlFromStorage.d.ts +13 -5
- package/dist/loadSupergraphSdlFromStorage.d.ts.map +1 -1
- package/dist/loadSupergraphSdlFromStorage.js +34 -7
- package/dist/loadSupergraphSdlFromStorage.js.map +1 -1
- package/dist/outOfBandReporter.d.ts +10 -12
- package/dist/outOfBandReporter.d.ts.map +1 -1
- package/dist/outOfBandReporter.js +70 -73
- package/dist/outOfBandReporter.js.map +1 -1
- package/package.json +9 -9
- package/src/__generated__/graphqlTypes.ts +13 -12
- package/src/__tests__/gateway/reporting.test.ts +5 -3
- package/src/__tests__/integration/configuration.test.ts +32 -11
- package/src/__tests__/integration/networkRequests.test.ts +22 -22
- package/src/__tests__/integration/nockMocks.ts +12 -6
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +101 -377
- package/src/__tests__/nockAssertions.ts +20 -0
- package/src/config.ts +10 -43
- package/src/index.ts +36 -56
- package/src/loadSupergraphSdlFromStorage.ts +54 -8
- package/src/outOfBandReporter.ts +87 -89
- package/dist/legacyLoadServicesFromStorage.d.ts +0 -20
- package/dist/legacyLoadServicesFromStorage.d.ts.map +0 -1
- package/dist/legacyLoadServicesFromStorage.js +0 -62
- package/dist/legacyLoadServicesFromStorage.js.map +0 -1
- package/src/__tests__/integration/legacyNetworkRequests.test.ts +0 -279
- package/src/__tests__/integration/legacyNockMocks.ts +0 -113
- package/src/legacyLoadServicesFromStorage.ts +0 -170
package/src/config.ts
CHANGED
|
@@ -135,31 +135,16 @@ export interface RemoteGatewayConfig extends GatewayConfigBase {
|
|
|
135
135
|
| ((service: ServiceEndpointDefinition) => Promise<HeadersInit> | HeadersInit);
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
|
|
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.
|
|
153
|
-
* to the previous mechanism for managed federation.
|
|
141
|
+
* Apollo staff.
|
|
154
142
|
*/
|
|
155
|
-
schemaConfigDeliveryEndpoint?: string;
|
|
143
|
+
schemaConfigDeliveryEndpoint?: string; // deprecated
|
|
144
|
+
uplinkEndpoints?: string[];
|
|
145
|
+
uplinkMaxRetries?: number;
|
|
156
146
|
}
|
|
157
147
|
|
|
158
|
-
// TODO(trevor:cloudconfig): This union is no longer needed
|
|
159
|
-
export type ManagedGatewayConfig =
|
|
160
|
-
| LegacyManagedGatewayConfig
|
|
161
|
-
| PrecomposedManagedGatewayConfig;
|
|
162
|
-
|
|
163
148
|
interface ManuallyManagedServiceDefsGatewayConfig extends GatewayConfigBase {
|
|
164
149
|
experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions;
|
|
165
150
|
}
|
|
@@ -216,30 +201,12 @@ export function isManuallyManagedConfig(
|
|
|
216
201
|
export function isManagedConfig(
|
|
217
202
|
config: GatewayConfig,
|
|
218
203
|
): 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
204
|
return (
|
|
241
|
-
'schemaConfigDeliveryEndpoint' in config
|
|
242
|
-
config
|
|
205
|
+
'schemaConfigDeliveryEndpoint' in config ||
|
|
206
|
+
(!isRemoteConfig(config) &&
|
|
207
|
+
!isLocalConfig(config) &&
|
|
208
|
+
!isSupergraphSdlConfig(config) &&
|
|
209
|
+
!isManuallyManagedConfig(config))
|
|
243
210
|
);
|
|
244
211
|
}
|
|
245
212
|
|
package/src/index.ts
CHANGED
|
@@ -66,12 +66,9 @@ import {
|
|
|
66
66
|
ServiceDefinitionUpdate,
|
|
67
67
|
SupergraphSdlUpdate,
|
|
68
68
|
CompositionUpdate,
|
|
69
|
-
isPrecomposedManagedConfig,
|
|
70
|
-
isLegacyManagedConfig,
|
|
71
69
|
} from './config';
|
|
72
|
-
import { loadSupergraphSdlFromStorage } from './loadSupergraphSdlFromStorage';
|
|
73
|
-
import { getServiceDefinitionsFromStorage } from './legacyLoadServicesFromStorage';
|
|
74
70
|
import { buildComposedSchema } from '@apollo/query-planner';
|
|
71
|
+
import { loadSupergraphSdlFromUplinks } from './loadSupergraphSdlFromStorage';
|
|
75
72
|
import { SpanStatusCode } from '@opentelemetry/api';
|
|
76
73
|
import { OpenTelemetrySpanNames, tracer } from './utilities/opentelemetry';
|
|
77
74
|
import { CoreSchema } from '@apollo/core-schema';
|
|
@@ -114,20 +111,6 @@ export function getDefaultFetcher() {
|
|
|
114
111
|
});
|
|
115
112
|
}
|
|
116
113
|
|
|
117
|
-
/**
|
|
118
|
-
* TODO(trevor:cloudconfig): Stop exporting this
|
|
119
|
-
* @deprecated This will be removed in a future version of @apollo/gateway
|
|
120
|
-
*/
|
|
121
|
-
export const getDefaultGcsFetcher = deprecate(
|
|
122
|
-
getDefaultFetcher,
|
|
123
|
-
`'getDefaultGcsFetcher' is deprecated. Use 'getDefaultFetcher' instead.`,
|
|
124
|
-
);
|
|
125
|
-
/**
|
|
126
|
-
* TODO(trevor:cloudconfig): Stop exporting this
|
|
127
|
-
* @deprecated This will be removed in a future version of @apollo/gateway
|
|
128
|
-
*/
|
|
129
|
-
export const GCS_RETRY_COUNT = 5;
|
|
130
|
-
|
|
131
114
|
export const HEALTH_CHECK_QUERY =
|
|
132
115
|
'query __ApolloServiceHealthCheck__ { __typename }';
|
|
133
116
|
export const SERVICE_DEFINITION_QUERY =
|
|
@@ -198,6 +181,8 @@ export class ApolloGateway implements GraphQLService {
|
|
|
198
181
|
private fetcher: typeof fetch;
|
|
199
182
|
private compositionId?: string;
|
|
200
183
|
private state: GatewayState;
|
|
184
|
+
private errorReportingEndpoint: string | undefined =
|
|
185
|
+
process.env.APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT ?? undefined;
|
|
201
186
|
|
|
202
187
|
// Observe query plan, service info, and operation info prior to execution.
|
|
203
188
|
// The information made available here will give insight into the resulting
|
|
@@ -215,12 +200,11 @@ export class ApolloGateway implements GraphQLService {
|
|
|
215
200
|
private updateServiceDefinitions: Experimental_UpdateComposition;
|
|
216
201
|
// how often service defs should be loaded/updated (in ms)
|
|
217
202
|
private experimental_pollInterval?: number;
|
|
218
|
-
// Configure the
|
|
219
|
-
// *
|
|
220
|
-
// * `null` will revert the gateway to legacy mode (polling GCS and composing the schema itself).
|
|
203
|
+
// Configure the endpoints by which gateway will access its precomposed schema.
|
|
204
|
+
// * An array of URLs means use these endpoints to obtain schema, if one is unavailable then try the next.
|
|
221
205
|
// * `undefined` means the gateway is not using managed federation
|
|
222
|
-
|
|
223
|
-
private
|
|
206
|
+
private uplinkEndpoints?: string[];
|
|
207
|
+
private uplinkMaxRetries?: number;
|
|
224
208
|
|
|
225
209
|
constructor(config?: GatewayConfig) {
|
|
226
210
|
this.config = {
|
|
@@ -248,19 +232,23 @@ export class ApolloGateway implements GraphQLService {
|
|
|
248
232
|
this.experimental_pollInterval = config?.experimental_pollInterval;
|
|
249
233
|
|
|
250
234
|
// 1. If config is set to a `string`, use it
|
|
251
|
-
// 2. If
|
|
252
|
-
// 3. If
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
235
|
+
// 2. If the env var is set, use that
|
|
236
|
+
// 3. If config is `undefined`, use the default uplink URLs
|
|
237
|
+
if (isManagedConfig(this.config)) {
|
|
238
|
+
const rawEndpointsString = process.env.APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT;
|
|
239
|
+
const envEndpoints = rawEndpointsString?.split(",") ?? null;
|
|
240
|
+
|
|
241
|
+
if (this.config.schemaConfigDeliveryEndpoint && !this.config.uplinkEndpoints) {
|
|
242
|
+
this.uplinkEndpoints = [this.config.schemaConfigDeliveryEndpoint];
|
|
243
|
+
} else {
|
|
244
|
+
this.uplinkEndpoints = this.config.uplinkEndpoints ??
|
|
245
|
+
envEndpoints ?? [
|
|
246
|
+
'https://uplink.api.apollographql.com/',
|
|
247
|
+
'https://aws.uplink.api.apollographql.com/'
|
|
248
|
+
];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
this.uplinkMaxRetries = this.config.uplinkMaxRetries ?? this.uplinkEndpoints.length * 3;
|
|
264
252
|
}
|
|
265
253
|
|
|
266
254
|
if (isManuallyManagedConfig(this.config)) {
|
|
@@ -980,30 +968,22 @@ export class ApolloGateway implements GraphQLService {
|
|
|
980
968
|
);
|
|
981
969
|
}
|
|
982
970
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
971
|
+
const result = await loadSupergraphSdlFromUplinks({
|
|
972
|
+
graphRef: this.apolloConfig!.graphRef!,
|
|
973
|
+
apiKey: this.apolloConfig!.key!,
|
|
974
|
+
endpoints: this.uplinkEndpoints!,
|
|
975
|
+
errorReportingEndpoint: this.errorReportingEndpoint,
|
|
976
|
+
fetcher: this.fetcher,
|
|
977
|
+
compositionId: this.compositionId ?? null,
|
|
978
|
+
maxRetries: this.uplinkMaxRetries!,
|
|
979
|
+
});
|
|
992
980
|
|
|
993
|
-
|
|
981
|
+
return (
|
|
982
|
+
result ?? {
|
|
994
983
|
id: this.compositionId!,
|
|
995
984
|
supergraphSdl: this.supergraphSdl!,
|
|
996
985
|
}
|
|
997
|
-
|
|
998
|
-
return getServiceDefinitionsFromStorage({
|
|
999
|
-
graphRef: this.apolloConfig!.graphRef!,
|
|
1000
|
-
apiKeyHash: this.apolloConfig!.keyHash!,
|
|
1001
|
-
federationVersion: config.federationVersion || 1,
|
|
1002
|
-
fetcher: this.fetcher,
|
|
1003
|
-
});
|
|
1004
|
-
} else {
|
|
1005
|
-
throw new Error('Programming error: unhandled configuration');
|
|
1006
|
-
}
|
|
986
|
+
);
|
|
1007
987
|
}
|
|
1008
988
|
|
|
1009
989
|
private maybeWarnOnConflictingConfig() {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { fetch, Response, Request } from 'apollo-server-env';
|
|
2
2
|
import { GraphQLError } from 'graphql';
|
|
3
|
-
import {
|
|
3
|
+
import { SupergraphSdlUpdate } from './config';
|
|
4
|
+
import { submitOutOfBandReportIfConfigured } from './outOfBandReporter';
|
|
4
5
|
import { SupergraphSdlQuery } from './__generated__/graphqlTypes';
|
|
5
6
|
|
|
6
7
|
// Magic /* GraphQL */ comment below is for codegen, do not remove
|
|
@@ -38,19 +39,63 @@ const { name, version } = require('../package.json');
|
|
|
38
39
|
|
|
39
40
|
const fetchErrorMsg = "An error occurred while fetching your schema from Apollo: ";
|
|
40
41
|
|
|
42
|
+
let fetchCounter = 0;
|
|
43
|
+
|
|
44
|
+
export async function loadSupergraphSdlFromUplinks({
|
|
45
|
+
graphRef,
|
|
46
|
+
apiKey,
|
|
47
|
+
endpoints,
|
|
48
|
+
errorReportingEndpoint,
|
|
49
|
+
fetcher,
|
|
50
|
+
compositionId,
|
|
51
|
+
maxRetries,
|
|
52
|
+
}: {
|
|
53
|
+
graphRef: string;
|
|
54
|
+
apiKey: string;
|
|
55
|
+
endpoints: string[];
|
|
56
|
+
errorReportingEndpoint: string | undefined,
|
|
57
|
+
fetcher: typeof fetch;
|
|
58
|
+
compositionId: string | null;
|
|
59
|
+
maxRetries: number
|
|
60
|
+
}) : 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({
|
|
67
|
+
graphRef,
|
|
68
|
+
apiKey,
|
|
69
|
+
endpoint: endpoints[fetchCounter++ % endpoints.length],
|
|
70
|
+
errorReportingEndpoint,
|
|
71
|
+
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;
|
|
82
|
+
}
|
|
83
|
+
|
|
41
84
|
export async function loadSupergraphSdlFromStorage({
|
|
42
85
|
graphRef,
|
|
43
86
|
apiKey,
|
|
44
87
|
endpoint,
|
|
88
|
+
errorReportingEndpoint,
|
|
45
89
|
fetcher,
|
|
46
90
|
compositionId,
|
|
47
91
|
}: {
|
|
48
92
|
graphRef: string;
|
|
49
93
|
apiKey: string;
|
|
50
94
|
endpoint: string;
|
|
95
|
+
errorReportingEndpoint?: string;
|
|
51
96
|
fetcher: typeof fetch;
|
|
52
97
|
compositionId: string | null;
|
|
53
|
-
}) {
|
|
98
|
+
}) : Promise<SupergraphSdlUpdate | null> {
|
|
54
99
|
let result: Response;
|
|
55
100
|
const requestDetails = {
|
|
56
101
|
method: 'POST',
|
|
@@ -72,19 +117,19 @@ export async function loadSupergraphSdlFromStorage({
|
|
|
72
117
|
|
|
73
118
|
const request: Request = new Request(endpoint, requestDetails);
|
|
74
119
|
|
|
75
|
-
const
|
|
76
|
-
const startTime = new Date()
|
|
120
|
+
const startTime = new Date();
|
|
77
121
|
try {
|
|
78
122
|
result = await fetcher(endpoint, requestDetails);
|
|
79
123
|
} catch (e) {
|
|
80
124
|
const endTime = new Date();
|
|
81
125
|
|
|
82
|
-
await
|
|
126
|
+
await submitOutOfBandReportIfConfigured({
|
|
83
127
|
error: e,
|
|
84
128
|
request,
|
|
129
|
+
endpoint: errorReportingEndpoint,
|
|
85
130
|
startedAt: startTime,
|
|
86
131
|
endedAt: endTime,
|
|
87
|
-
fetcher
|
|
132
|
+
fetcher,
|
|
88
133
|
});
|
|
89
134
|
|
|
90
135
|
throw new Error(fetchErrorMsg + (e.message ?? e));
|
|
@@ -109,13 +154,14 @@ export async function loadSupergraphSdlFromStorage({
|
|
|
109
154
|
);
|
|
110
155
|
}
|
|
111
156
|
} else {
|
|
112
|
-
await
|
|
157
|
+
await submitOutOfBandReportIfConfigured({
|
|
113
158
|
error: new Error(fetchErrorMsg + result.status + ' ' + result.statusText),
|
|
114
159
|
request,
|
|
160
|
+
endpoint: errorReportingEndpoint,
|
|
115
161
|
response: result,
|
|
116
162
|
startedAt: startTime,
|
|
117
163
|
endedAt: endTime,
|
|
118
|
-
fetcher
|
|
164
|
+
fetcher,
|
|
119
165
|
});
|
|
120
166
|
throw new Error(fetchErrorMsg + result.status + ' ' + result.statusText);
|
|
121
167
|
}
|
package/src/outOfBandReporter.ts
CHANGED
|
@@ -27,102 +27,100 @@ interface OobReportMutationFailure {
|
|
|
27
27
|
data?: OobReportMutation;
|
|
28
28
|
errors: GraphQLError[];
|
|
29
29
|
}
|
|
30
|
-
export class OutOfBandReporter {
|
|
31
|
-
static endpoint: string | null = process.env.APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT || null;
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
31
|
+
export async function submitOutOfBandReportIfConfigured({
|
|
32
|
+
error,
|
|
33
|
+
request,
|
|
34
|
+
endpoint,
|
|
35
|
+
response,
|
|
36
|
+
startedAt,
|
|
37
|
+
endedAt,
|
|
38
|
+
tags,
|
|
39
|
+
fetcher,
|
|
40
|
+
}: {
|
|
41
|
+
error: Error;
|
|
42
|
+
request: Request;
|
|
43
|
+
endpoint: string | undefined;
|
|
44
|
+
response?: Response;
|
|
45
|
+
startedAt: Date;
|
|
46
|
+
endedAt: Date;
|
|
47
|
+
tags?: string[];
|
|
48
|
+
fetcher: typeof fetch;
|
|
49
|
+
}) {
|
|
50
|
+
// don't send report if the endpoint url is not configured
|
|
51
|
+
if (!endpoint) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
55
|
+
let errorCode: ErrorCode;
|
|
56
|
+
if (!response) {
|
|
57
|
+
errorCode = ErrorCode.ConnectionFailed;
|
|
58
|
+
} else {
|
|
59
|
+
// possible error situations to check against
|
|
60
|
+
switch (response.status) {
|
|
61
|
+
case 400:
|
|
62
|
+
case 413:
|
|
63
|
+
case 422:
|
|
64
|
+
errorCode = ErrorCode.InvalidBody;
|
|
65
|
+
break;
|
|
66
|
+
case 408:
|
|
67
|
+
case 504:
|
|
68
|
+
errorCode = ErrorCode.Timeout;
|
|
69
|
+
break;
|
|
70
|
+
case 502:
|
|
71
|
+
case 503:
|
|
72
|
+
errorCode = ErrorCode.ConnectionFailed;
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
errorCode = ErrorCode.Other;
|
|
78
76
|
}
|
|
77
|
+
}
|
|
79
78
|
|
|
80
|
-
|
|
79
|
+
const responseBody: string | undefined = await response?.text();
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
},
|
|
92
|
-
response: response
|
|
93
|
-
? {
|
|
94
|
-
httpStatusCode: response.status,
|
|
95
|
-
body: responseBody,
|
|
96
|
-
}
|
|
97
|
-
: null,
|
|
98
|
-
startedAt: startedAt.toISOString(),
|
|
99
|
-
endedAt: endedAt.toISOString(),
|
|
100
|
-
tags: tags,
|
|
81
|
+
const variables: OobReportMutationVariables = {
|
|
82
|
+
input: {
|
|
83
|
+
error: {
|
|
84
|
+
code: errorCode,
|
|
85
|
+
message: error.message,
|
|
86
|
+
},
|
|
87
|
+
request: {
|
|
88
|
+
url: request.url,
|
|
89
|
+
body: await request.text(),
|
|
101
90
|
},
|
|
102
|
-
|
|
91
|
+
response: response
|
|
92
|
+
? {
|
|
93
|
+
httpStatusCode: response.status,
|
|
94
|
+
body: responseBody,
|
|
95
|
+
}
|
|
96
|
+
: null,
|
|
97
|
+
startedAt: startedAt.toISOString(),
|
|
98
|
+
endedAt: endedAt.toISOString(),
|
|
99
|
+
tags: tags,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
103
102
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
} catch (e) {
|
|
125
|
-
throw new Error(`Out-of-band error reporting failed: ${e.message ?? e}`);
|
|
103
|
+
try {
|
|
104
|
+
const oobResponse = await fetcher(endpoint, {
|
|
105
|
+
method: 'POST',
|
|
106
|
+
body: JSON.stringify({
|
|
107
|
+
query: OUT_OF_BAND_REPORTER_QUERY,
|
|
108
|
+
variables,
|
|
109
|
+
}),
|
|
110
|
+
headers: {
|
|
111
|
+
'apollographql-client-name': name,
|
|
112
|
+
'apollographql-client-version': version,
|
|
113
|
+
'user-agent': `${name}/${version}`,
|
|
114
|
+
'content-type': 'application/json',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
const parsedResponse: OobReportMutationResult = await oobResponse.json();
|
|
118
|
+
if (!parsedResponse?.data?.reportError) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Out-of-band error reporting failed: ${oobResponse.status} ${oobResponse.statusText}`,
|
|
121
|
+
);
|
|
126
122
|
}
|
|
123
|
+
} catch (e) {
|
|
124
|
+
throw new Error(`Out-of-band error reporting failed: ${e.message ?? e}`);
|
|
127
125
|
}
|
|
128
126
|
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { fetch } from 'apollo-server-env';
|
|
2
|
-
import { ServiceDefinitionUpdate } from './config';
|
|
3
|
-
interface ImplementingServiceLocation {
|
|
4
|
-
name: string;
|
|
5
|
-
path: string;
|
|
6
|
-
}
|
|
7
|
-
export interface CompositionMetadata {
|
|
8
|
-
formatVersion: number;
|
|
9
|
-
id: string;
|
|
10
|
-
implementingServiceLocations: ImplementingServiceLocation[];
|
|
11
|
-
schemaHash: string;
|
|
12
|
-
}
|
|
13
|
-
export declare function getServiceDefinitionsFromStorage({ graphRef, apiKeyHash, federationVersion, fetcher, }: {
|
|
14
|
-
graphRef: string;
|
|
15
|
-
apiKeyHash: string;
|
|
16
|
-
federationVersion: number;
|
|
17
|
-
fetcher: typeof fetch;
|
|
18
|
-
}): Promise<ServiceDefinitionUpdate>;
|
|
19
|
-
export {};
|
|
20
|
-
//# sourceMappingURL=legacyLoadServicesFromStorage.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"legacyLoadServicesFromStorage.d.ts","sourceRoot":"","sources":["../src/legacyLoadServicesFromStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAiBnD,UAAU,2BAA2B;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,4BAA4B,EAAE,2BAA2B,EAAE,CAAC;IAC5D,UAAU,EAAE,MAAM,CAAC;CACpB;AAsED,wBAAsB,gCAAgC,CAAC,EACrD,QAAQ,EACR,UAAU,EACV,iBAAiB,EACjB,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,KAAK,CAAC;CACvB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA4DnC"}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getServiceDefinitionsFromStorage = void 0;
|
|
4
|
-
const graphql_1 = require("graphql");
|
|
5
|
-
const envOverridePartialSchemaBaseUrl = 'APOLLO_PARTIAL_SCHEMA_BASE_URL';
|
|
6
|
-
const envOverrideStorageSecretBaseUrl = 'APOLLO_STORAGE_SECRET_BASE_URL';
|
|
7
|
-
const urlFromEnvOrDefault = (envKey, fallback) => (process.env[envKey] || fallback).replace(/\/$/, '');
|
|
8
|
-
const urlPartialSchemaBase = urlFromEnvOrDefault(envOverridePartialSchemaBaseUrl, 'https://federation.api.apollographql.com/');
|
|
9
|
-
const urlStorageSecretBase = urlFromEnvOrDefault(envOverrideStorageSecretBaseUrl, 'https://storage-secrets.api.apollographql.com/');
|
|
10
|
-
function getStorageSecretUrl(graphId, apiKeyHash) {
|
|
11
|
-
return `${urlStorageSecretBase}/${graphId}/storage-secret/${apiKeyHash}.json`;
|
|
12
|
-
}
|
|
13
|
-
function fetchApolloGcs(fetcher, ...args) {
|
|
14
|
-
const [input, init] = args;
|
|
15
|
-
const url = (typeof input === 'object' && input.url) || input;
|
|
16
|
-
return fetcher(input, init)
|
|
17
|
-
.catch((fetchError) => {
|
|
18
|
-
throw new Error('Cannot access Apollo storage: ' + fetchError);
|
|
19
|
-
})
|
|
20
|
-
.then(async (response) => {
|
|
21
|
-
if (response.ok || response.status === 304) {
|
|
22
|
-
return response;
|
|
23
|
-
}
|
|
24
|
-
const body = await response.text();
|
|
25
|
-
if (response.status === 403 && body.includes('AccessDenied')) {
|
|
26
|
-
throw new Error('Unable to authenticate with Apollo storage ' +
|
|
27
|
-
'while fetching ' +
|
|
28
|
-
url +
|
|
29
|
-
'. Ensure that the API key is ' +
|
|
30
|
-
'configured properly and that a federated service has been ' +
|
|
31
|
-
'pushed. For details, see ' +
|
|
32
|
-
'https://go.apollo.dev/g/resolve-access-denied.');
|
|
33
|
-
}
|
|
34
|
-
throw new Error('Could not communicate with Apollo storage: ' + body);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
async function getServiceDefinitionsFromStorage({ graphRef, apiKeyHash, federationVersion, fetcher, }) {
|
|
38
|
-
const at = graphRef.indexOf('@');
|
|
39
|
-
const graphId = at === -1 ? graphRef : graphRef.substring(0, at);
|
|
40
|
-
const graphVariant = at === -1 ? 'current' : graphRef.substring(at + 1);
|
|
41
|
-
const storageSecretUrl = getStorageSecretUrl(graphId, apiKeyHash);
|
|
42
|
-
const secret = await fetchApolloGcs(fetcher, storageSecretUrl).then((res) => res.json());
|
|
43
|
-
const baseUrl = `${urlPartialSchemaBase}/${secret}/${graphVariant}/v${federationVersion}`;
|
|
44
|
-
const compositionConfigResponse = await fetchApolloGcs(fetcher, `${baseUrl}/composition-config-link`);
|
|
45
|
-
if (compositionConfigResponse.status === 304) {
|
|
46
|
-
return { isNewSchema: false };
|
|
47
|
-
}
|
|
48
|
-
const linkFileResult = await compositionConfigResponse.json();
|
|
49
|
-
const compositionMetadata = await fetchApolloGcs(fetcher, `${urlPartialSchemaBase}/${linkFileResult.configPath}`).then((res) => res.json());
|
|
50
|
-
const serviceDefinitions = await Promise.all(compositionMetadata.implementingServiceLocations.map(async ({ name, path }) => {
|
|
51
|
-
const { url, partialSchemaPath } = await fetcher(`${urlPartialSchemaBase}/${path}`).then((response) => response.json());
|
|
52
|
-
const sdl = await fetcher(`${urlPartialSchemaBase}/${partialSchemaPath}`).then((response) => response.text());
|
|
53
|
-
return { name, url, typeDefs: (0, graphql_1.parse)(sdl) };
|
|
54
|
-
}));
|
|
55
|
-
return {
|
|
56
|
-
serviceDefinitions,
|
|
57
|
-
compositionMetadata,
|
|
58
|
-
isNewSchema: true,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
exports.getServiceDefinitionsFromStorage = getServiceDefinitionsFromStorage;
|
|
62
|
-
//# sourceMappingURL=legacyLoadServicesFromStorage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"legacyLoadServicesFromStorage.js","sourceRoot":"","sources":["../src/legacyLoadServicesFromStorage.ts"],"names":[],"mappings":"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"}
|