@graphql-hive/apollo
Version:
GraphQL Hive + Apollo Server
284 lines (283 loc) • 12.8 kB
JavaScript
import { GraphQLError } from 'graphql';
import { autoDisposeSymbol, createCDNArtifactFetcher, createHive as createHiveClient, isHiveClient, joinUrl, } from '@graphql-hive/core';
import { Logger } from '@graphql-hive/logger';
import { version } from './version.js';
export { atLeastOnceSampler, createSchemaFetcher, createServicesFetcher, createSupergraphSDLFetcher, } from '@graphql-hive/core';
export function createSupergraphManager(args) {
var _a, _b, _c, _d;
const logger = (_a = args.logger) !== null && _a !== void 0 ? _a : new Logger({ level: false });
const pollIntervalInMs = (_b = args.pollIntervalInMs) !== null && _b !== void 0 ? _b : 30000;
let endpoints = Array.isArray(args.endpoint) ? args.endpoint : [args.endpoint];
const endpoint = endpoints.map(endpoint => endpoint.endsWith('/supergraph') ? endpoint : joinUrl(endpoint, 'supergraph'));
const artifactsFetcher = createCDNArtifactFetcher({
endpoint: endpoint,
accessKey: args.key,
client: {
name: (_c = args.name) !== null && _c !== void 0 ? _c : '@graphql-hive/apollo',
version: (_d = args.version) !== null && _d !== void 0 ? _d : version,
},
logger,
fetch: args.fetchImplementation,
circuitBreaker: args.circuitBreaker,
});
let timer = null;
return {
async initialize(hooks) {
const initialResult = await artifactsFetcher.fetch();
function poll() {
timer = setTimeout(async () => {
var _a;
try {
const result = await artifactsFetcher.fetch();
if (result.contents) {
(_a = hooks.update) === null || _a === void 0 ? void 0 : _a.call(hooks, result.contents);
}
}
catch (error) {
logger.error({ error }, `Failed to update supergraph.`);
}
poll();
}, pollIntervalInMs);
}
poll();
return {
supergraphSdl: initialResult.contents,
cleanup: async () => {
if (timer) {
clearTimeout(timer);
}
artifactsFetcher.dispose();
},
};
},
};
}
function addRequestWithHeaders(context, http) {
if (!!http && !('request' in context)) {
context.request = {
headers: http.headers,
};
}
return context;
}
export function createHive(clientOrOptions) {
return createHiveClient(Object.assign(Object.assign({}, clientOrOptions), { agent: Object.assign({ name: 'hive-client-yoga', version }, clientOrOptions.agent) }));
}
export function useHive(clientOrOptions) {
const hive = isHiveClient(clientOrOptions) ? clientOrOptions : createHive(clientOrOptions);
void hive.info();
return {
requestDidStart(context) {
var _a;
// `overallCachePolicy` does not exist in v0
const isLegacyV0 = !('overallCachePolicy' in context);
// `context` does not exist in v4, it is `contextValue` instead
const isLegacyV3 = 'context' in context;
let doc;
let didResolveSource = false;
const complete = hive.collectUsage();
const args = {
schema: context.schema,
get document() {
return doc;
},
operationName: context.operationName,
contextValue: addRequestWithHeaders(isLegacyV3 ? context.context : context.contextValue, (_a = context.request) === null || _a === void 0 ? void 0 : _a.http),
variableValues: context.request.variables,
};
if (isLegacyV0) {
return {
didResolveSource() {
didResolveSource = true;
},
willSendResponse(ctx) {
if (!didResolveSource) {
void complete(args, {
action: 'abort',
reason: 'Did not resolve source',
logging: false,
});
return;
}
doc = ctx.document;
void complete(args, ctx.response);
},
};
}
let didFailValidation = false;
if (isLegacyV3) {
return Promise.resolve({
didResolveSource() {
didResolveSource = true;
},
async validationDidStart() {
return function onErrors(errors) {
if (errors === null || errors === void 0 ? void 0 : errors.length) {
didFailValidation = true;
}
};
},
async willSendResponse(ctx) {
if (didFailValidation) {
void complete(args, {
action: 'abort',
reason: 'Validation failed',
logging: false,
});
return;
}
if (!didResolveSource) {
void complete(args, {
action: 'abort',
reason: 'Did not resolve source',
logging: false,
});
return;
}
if (!ctx.document) {
const details = ctx.operationName ? `operationName: ${ctx.operationName}` : '';
void complete(args, {
action: 'abort',
reason: 'Document is not available' + (details ? ` (${details})` : ''),
logging: true,
});
return;
}
doc = ctx.document;
void complete(args, ctx.response);
},
});
}
return (async () => {
var _a;
let persistedDocumentError = null;
let persistedDocumentHash;
if (hive.experimental__persistedDocuments) {
if (((_a = context.request.http) === null || _a === void 0 ? void 0 : _a.body) &&
typeof context.request.http.body === 'object' &&
'documentId' in context.request.http.body &&
typeof context.request.http.body.documentId === 'string') {
persistedDocumentHash = context.request.http.body.documentId;
const document = await hive.experimental__persistedDocuments.resolve(context.request.http.body.documentId);
if (document) {
context.request.query = document;
}
else {
context.request.query = '{__typename}';
persistedDocumentError = new GraphQLError('Persisted document not found.', {
extensions: {
code: 'PERSISTED_DOCUMENT_NOT_FOUND',
http: {
status: 400,
},
},
});
}
}
else if (false ===
(await hive.experimental__persistedDocuments.allowArbitraryDocuments({
headers: {
get(name) {
var _a, _b, _c;
return (_c = (_b = (_a = context.request.http) === null || _a === void 0 ? void 0 : _a.headers) === null || _b === void 0 ? void 0 : _b.get(name)) !== null && _c !== void 0 ? _c : null;
},
},
}))) {
context.request.query = '{__typename}';
persistedDocumentError = new GraphQLError('No persisted document provided.', {
extensions: {
code: 'PERSISTED_DOCUMENT_REQUIRED',
http: {
status: 400,
},
},
});
}
}
// v4
return {
didResolveSource() {
didResolveSource = true;
},
async validationDidStart() {
return function onErrors(errors) {
if (errors === null || errors === void 0 ? void 0 : errors.length) {
didFailValidation = true;
}
};
},
didResolveOperation() {
if (persistedDocumentError) {
throw persistedDocumentError;
}
},
async willSendResponse(ctx) {
if (didFailValidation) {
void complete(args, {
action: 'abort',
reason: 'Validation failed',
logging: false,
}, persistedDocumentHash);
return;
}
if (!didResolveSource) {
void complete(args, {
action: 'abort',
reason: 'Did not resolve source',
logging: false,
}, persistedDocumentHash);
return;
}
if (!ctx.document) {
const details = ctx.operationName ? `operationName: ${ctx.operationName}` : '';
void complete(args, {
action: 'abort',
reason: 'Document is not available' + (details ? ` (${details})` : ''),
logging: true,
}, persistedDocumentHash);
return;
}
doc = ctx.document;
if (ctx.response.body.kind === 'incremental') {
void complete(args, {
action: 'abort',
reason: '@defer and @stream is not supported by Hive',
logging: true,
}, persistedDocumentHash);
}
else {
void complete(args, ctx.response.body.singleResult, persistedDocumentHash);
}
},
};
})();
},
serverWillStart(ctx) {
// `engine` does not exist in v3
const isLegacyV0 = 'engine' in ctx;
hive.reportSchema({ schema: ctx.schema });
if (isLegacyV0) {
return {
async serverWillStop() {
if (hive[autoDisposeSymbol]) {
await hive.dispose();
}
},
};
}
// Works on v3 and v4
return Promise.resolve({
async serverWillStop() {
if (hive[autoDisposeSymbol]) {
await hive.dispose();
}
},
schemaDidLoadOrUpdate(schemaContext) {
if (ctx.schema !== schemaContext.apiSchema) {
hive.reportSchema({ schema: schemaContext.apiSchema });
}
},
});
},
};
}