UNPKG

4.05 kBJavaScriptView Raw
1import { ApolloLink, concat, execute } from '@apollo/client/link/core';
2import { createUploadLink, isExtractableFile, formDataAppendFile } from 'apollo-upload-client';
3import FormData from 'form-data';
4import { fetch } from 'cross-fetch';
5import { Observable } from '@apollo/client/utilities';
6import { toPromise } from '@apollo/client/core';
7import { observableToAsyncIterable } from '@graphql-tools/utils';
8import { GraphQLScalarType, GraphQLError } from 'graphql';
9import isPromise from 'is-promise';
10
11function getFinalPromise(object) {
12 return Promise.resolve(object).then(resolvedObject => {
13 if (resolvedObject == null) {
14 return resolvedObject;
15 }
16 if (Array.isArray(resolvedObject)) {
17 return Promise.all(resolvedObject.map(o => getFinalPromise(o)));
18 }
19 else if (typeof resolvedObject === 'object') {
20 const keys = Object.keys(resolvedObject);
21 return Promise.all(keys.map(key => getFinalPromise(resolvedObject[key]))).then(awaitedValues => {
22 for (let i = 0; i < keys.length; i++) {
23 resolvedObject[keys[i]] = awaitedValues[i];
24 }
25 return resolvedObject;
26 });
27 }
28 return resolvedObject;
29 });
30}
31class AwaitVariablesLink extends ApolloLink {
32 request(operation, forward) {
33 return new Observable(observer => {
34 let subscription;
35 getFinalPromise(operation.variables)
36 .then(resolvedVariables => {
37 operation.variables = resolvedVariables;
38 subscription = forward(operation).subscribe({
39 next: observer.next.bind(observer),
40 error: observer.error.bind(observer),
41 complete: observer.complete.bind(observer),
42 });
43 })
44 .catch(observer.error.bind(observer));
45 return () => {
46 if (subscription != null) {
47 subscription.unsubscribe();
48 }
49 };
50 });
51 }
52}
53
54const createServerHttpLink = (options) => concat(new AwaitVariablesLink(), createUploadLink({
55 ...options,
56 fetch,
57 FormData,
58 isExtractableFile: (value) => isExtractableFile(value) || (value === null || value === void 0 ? void 0 : value.createReadStream),
59 formDataAppendFile: (form, index, file) => {
60 if (file.createReadStream != null) {
61 form.append(index, file.createReadStream(), {
62 filename: file.filename,
63 contentType: file.mimetype,
64 });
65 }
66 else {
67 formDataAppendFile(form, index, file);
68 }
69 },
70}));
71
72const linkToExecutor = (link) => async (params) => {
73 const { document, variables, extensions, context, operationType, operationName, info } = params;
74 const observable = execute(link, {
75 query: document,
76 variables,
77 context: {
78 graphqlContext: context,
79 graphqlResolveInfo: info,
80 clientAwareness: {},
81 },
82 extensions,
83 operationName,
84 });
85 if (operationType === 'subscription') {
86 return observableToAsyncIterable(observable)[Symbol.asyncIterator]();
87 }
88 return toPromise(observable);
89};
90
91const GraphQLUpload = new GraphQLScalarType({
92 name: 'Upload',
93 description: 'The `Upload` scalar type represents a file upload.',
94 parseValue: value => {
95 if (value != null && isPromise(value.promise)) {
96 // graphql-upload v10
97 return value.promise;
98 }
99 else if (isPromise(value)) {
100 // graphql-upload v9
101 return value;
102 }
103 throw new GraphQLError('Upload value invalid.');
104 },
105 // serialization requires to support schema stitching
106 serialize: value => value,
107 parseLiteral: ast => {
108 throw new GraphQLError('Upload literal unsupported.', ast);
109 },
110});
111
112export { AwaitVariablesLink, GraphQLUpload, createServerHttpLink, linkToExecutor };