@graphql-mesh/grpc 1.0.0-alpha-3fc47d119.0 → 1.0.0-alpha-20230420181317-a95037648
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/cjs/index.js +454 -0
- package/cjs/package.json +1 -0
- package/cjs/patchLongJs.js +14 -0
- package/cjs/scalars.js +32 -0
- package/cjs/utils.js +96 -0
- package/{index.mjs → esm/index.js} +120 -213
- package/esm/patchLongJs.js +11 -0
- package/esm/scalars.js +27 -0
- package/esm/utils.js +89 -0
- package/package.json +30 -23
- package/typings/index.d.cts +37 -0
- package/{index.d.ts → typings/index.d.ts} +12 -14
- package/typings/patchLongJs.d.ts +1 -0
- package/typings/scalars.d.ts +2 -0
- package/typings/utils.d.cts +7 -0
- package/{utils.d.ts → typings/utils.d.ts} +2 -1
- package/index.js +0 -548
- /package/{patchLongJs.d.ts → typings/patchLongJs.d.cts} +0 -0
- /package/{scalars.d.ts → typings/scalars.d.cts} +0 -0
package/cjs/index.js
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
/* eslint-disable import/no-duplicates */
|
|
5
|
+
const globby_1 = tslib_1.__importDefault(require("globby"));
|
|
6
|
+
const graphql_1 = require("graphql");
|
|
7
|
+
const graphql_compose_1 = require("graphql-compose");
|
|
8
|
+
const graphql_scalars_1 = require("graphql-scalars");
|
|
9
|
+
const lodash_get_1 = tslib_1.__importDefault(require("lodash.get"));
|
|
10
|
+
const lodash_has_1 = tslib_1.__importDefault(require("lodash.has"));
|
|
11
|
+
const protobufjs_1 = tslib_1.__importDefault(require("protobufjs"));
|
|
12
|
+
const index_js_1 = tslib_1.__importDefault(require("protobufjs/ext/descriptor/index.js"));
|
|
13
|
+
const grpc_reflection_js_1 = require("@ardatan/grpc-reflection-js");
|
|
14
|
+
const cross_helpers_1 = require("@graphql-mesh/cross-helpers");
|
|
15
|
+
const cross_helpers_2 = require("@graphql-mesh/cross-helpers");
|
|
16
|
+
const string_interpolation_1 = require("@graphql-mesh/string-interpolation");
|
|
17
|
+
const grpc_js_1 = require("@grpc/grpc-js");
|
|
18
|
+
const proto_loader_1 = require("@grpc/proto-loader");
|
|
19
|
+
require("./patchLongJs.js");
|
|
20
|
+
const utils_js_1 = require("./utils.js");
|
|
21
|
+
const { Root } = protobufjs_1.default;
|
|
22
|
+
const QUERY_METHOD_PREFIXES = ['get', 'list', 'search'];
|
|
23
|
+
class GrpcHandler {
|
|
24
|
+
constructor({ config, baseDir, store, logger, pubsub, }) {
|
|
25
|
+
this.schemaComposer = new graphql_compose_1.SchemaComposer();
|
|
26
|
+
this.logger = logger;
|
|
27
|
+
this.config = config;
|
|
28
|
+
this.baseDir = baseDir;
|
|
29
|
+
this.rootJsonEntries = store.proxy('rootJsonEntries', {
|
|
30
|
+
codify: rootJsonEntries => `
|
|
31
|
+
export default [
|
|
32
|
+
${rootJsonEntries
|
|
33
|
+
.map(({ name, rootJson }) => `
|
|
34
|
+
{
|
|
35
|
+
name: ${JSON.stringify(name)},
|
|
36
|
+
rootJson: ${JSON.stringify(rootJson, null, 2)},
|
|
37
|
+
},
|
|
38
|
+
`)
|
|
39
|
+
.join('\n')}
|
|
40
|
+
];
|
|
41
|
+
`.trim(),
|
|
42
|
+
fromJSON: jsonData => {
|
|
43
|
+
return jsonData.map(({ name, rootJson }) => ({
|
|
44
|
+
name,
|
|
45
|
+
rootJson,
|
|
46
|
+
}));
|
|
47
|
+
},
|
|
48
|
+
toJSON: rootJsonEntries => {
|
|
49
|
+
return rootJsonEntries.map(({ name, rootJson }) => {
|
|
50
|
+
return {
|
|
51
|
+
name,
|
|
52
|
+
rootJson,
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
validate: () => { },
|
|
57
|
+
});
|
|
58
|
+
this.pubsub = pubsub;
|
|
59
|
+
}
|
|
60
|
+
async processReflection(creds) {
|
|
61
|
+
this.logger.debug(`Using the reflection`);
|
|
62
|
+
const grpcReflectionServer = this.config.endpoint;
|
|
63
|
+
this.logger.debug(`Creating gRPC Reflection Client`);
|
|
64
|
+
const reflectionClient = new grpc_reflection_js_1.Client(grpcReflectionServer, creds);
|
|
65
|
+
const subId = this.pubsub.subscribe('destroy', () => {
|
|
66
|
+
reflectionClient.grpcClient.close();
|
|
67
|
+
this.pubsub.unsubscribe(subId);
|
|
68
|
+
});
|
|
69
|
+
const services = await reflectionClient.listServices();
|
|
70
|
+
const userServices = services.filter(service => service && !(service === null || service === void 0 ? void 0 : service.startsWith('grpc.')));
|
|
71
|
+
return userServices.map(async (service) => {
|
|
72
|
+
this.logger.debug(`Resolving root of Service: ${service} from the reflection response`);
|
|
73
|
+
const serviceRoot = await reflectionClient.fileContainingSymbol(service);
|
|
74
|
+
return serviceRoot;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async processDescriptorFile() {
|
|
78
|
+
var _a;
|
|
79
|
+
let fileName;
|
|
80
|
+
let options;
|
|
81
|
+
if (typeof this.config.source === 'object') {
|
|
82
|
+
fileName = this.config.source.file;
|
|
83
|
+
options = {
|
|
84
|
+
...this.config.source.load,
|
|
85
|
+
includeDirs: (_a = this.config.source.load.includeDirs) === null || _a === void 0 ? void 0 : _a.map(includeDir => cross_helpers_1.path.isAbsolute(includeDir) ? includeDir : cross_helpers_1.path.join(this.baseDir, includeDir)),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
fileName = this.config.source;
|
|
90
|
+
}
|
|
91
|
+
const absoluteFilePath = cross_helpers_1.path.isAbsolute(fileName)
|
|
92
|
+
? fileName
|
|
93
|
+
: cross_helpers_1.path.join(this.baseDir, fileName);
|
|
94
|
+
this.logger.debug(`Using the descriptor set from ${absoluteFilePath} `);
|
|
95
|
+
const descriptorSetBuffer = await cross_helpers_2.fs.promises.readFile(absoluteFilePath);
|
|
96
|
+
this.logger.debug(`Reading ${absoluteFilePath} `);
|
|
97
|
+
let decodedDescriptorSet;
|
|
98
|
+
if (absoluteFilePath.endsWith('json')) {
|
|
99
|
+
this.logger.debug(`Parsing ${absoluteFilePath} as json`);
|
|
100
|
+
const descriptorSetJSON = JSON.parse(descriptorSetBuffer.toString());
|
|
101
|
+
decodedDescriptorSet = index_js_1.default.FileDescriptorSet.fromObject(descriptorSetJSON);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
decodedDescriptorSet = index_js_1.default.FileDescriptorSet.decode(descriptorSetBuffer);
|
|
105
|
+
}
|
|
106
|
+
this.logger.debug(`Creating root from descriptor set`);
|
|
107
|
+
const rootFromDescriptor = Root.fromDescriptor(decodedDescriptorSet);
|
|
108
|
+
if (options.includeDirs) {
|
|
109
|
+
if (!Array.isArray(options.includeDirs)) {
|
|
110
|
+
return Promise.reject(new Error('The includeDirs option must be an array'));
|
|
111
|
+
}
|
|
112
|
+
(0, utils_js_1.addIncludePathResolver)(rootFromDescriptor, options.includeDirs);
|
|
113
|
+
}
|
|
114
|
+
return rootFromDescriptor;
|
|
115
|
+
}
|
|
116
|
+
async processProtoFile() {
|
|
117
|
+
var _a, _b;
|
|
118
|
+
this.logger.debug(`Using proto file(s)`);
|
|
119
|
+
let protoRoot = new Root();
|
|
120
|
+
let fileGlob;
|
|
121
|
+
let options = {
|
|
122
|
+
keepCase: true,
|
|
123
|
+
alternateCommentMode: true,
|
|
124
|
+
};
|
|
125
|
+
if (typeof this.config.source === 'object') {
|
|
126
|
+
fileGlob = this.config.source.file;
|
|
127
|
+
options = {
|
|
128
|
+
...options,
|
|
129
|
+
...this.config.source.load,
|
|
130
|
+
includeDirs: (_b = (_a = this.config.source.load) === null || _a === void 0 ? void 0 : _a.includeDirs) === null || _b === void 0 ? void 0 : _b.map(includeDir => cross_helpers_1.path.isAbsolute(includeDir) ? includeDir : cross_helpers_1.path.join(this.baseDir, includeDir)),
|
|
131
|
+
};
|
|
132
|
+
if (options.includeDirs) {
|
|
133
|
+
if (!Array.isArray(options.includeDirs)) {
|
|
134
|
+
throw new Error('The includeDirs option must be an array');
|
|
135
|
+
}
|
|
136
|
+
(0, utils_js_1.addIncludePathResolver)(protoRoot, options.includeDirs);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
fileGlob = this.config.source;
|
|
141
|
+
}
|
|
142
|
+
const fileNames = await (0, globby_1.default)(fileGlob, {
|
|
143
|
+
cwd: this.baseDir,
|
|
144
|
+
});
|
|
145
|
+
this.logger.debug(`Loading proto files(${fileGlob}); \n ${fileNames.join('\n')} `);
|
|
146
|
+
protoRoot = await protoRoot.load(fileNames.map(filePath => cross_helpers_1.path.isAbsolute(filePath) ? filePath : cross_helpers_1.path.join(this.baseDir, filePath)), options);
|
|
147
|
+
this.logger.debug(`Adding proto content to the root`);
|
|
148
|
+
return protoRoot;
|
|
149
|
+
}
|
|
150
|
+
getCachedDescriptorSets(creds) {
|
|
151
|
+
return this.rootJsonEntries.getWithSet(async () => {
|
|
152
|
+
const rootPromises = [];
|
|
153
|
+
this.logger.debug(`Building Roots`);
|
|
154
|
+
if (this.config.source) {
|
|
155
|
+
const filePath = typeof this.config.source === 'string' ? this.config.source : this.config.source.file;
|
|
156
|
+
if (filePath.endsWith('json')) {
|
|
157
|
+
rootPromises.push(this.processDescriptorFile());
|
|
158
|
+
}
|
|
159
|
+
else if (filePath.endsWith('proto')) {
|
|
160
|
+
rootPromises.push(this.processProtoFile());
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const reflectionPromises = await this.processReflection(creds);
|
|
165
|
+
rootPromises.push(...reflectionPromises);
|
|
166
|
+
}
|
|
167
|
+
return Promise.all(rootPromises.map(async (root$, i) => {
|
|
168
|
+
const root = await root$;
|
|
169
|
+
const rootName = root.name || `Root${i}`;
|
|
170
|
+
const rootLogger = this.logger.child(rootName);
|
|
171
|
+
rootLogger.debug(`Resolving entire the root tree`);
|
|
172
|
+
root.resolveAll();
|
|
173
|
+
rootLogger.debug(`Creating artifacts from descriptor set and root`);
|
|
174
|
+
return {
|
|
175
|
+
name: rootName,
|
|
176
|
+
rootJson: root.toJSON({
|
|
177
|
+
keepComments: true,
|
|
178
|
+
}),
|
|
179
|
+
};
|
|
180
|
+
}));
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
async getCredentials() {
|
|
184
|
+
if (this.config.credentialsSsl) {
|
|
185
|
+
this.logger.debug(() => `Using SSL Connection with credentials at ${this.config.credentialsSsl.privateKey} & ${this.config.credentialsSsl.certChain}`);
|
|
186
|
+
const absolutePrivateKeyPath = cross_helpers_1.path.isAbsolute(this.config.credentialsSsl.privateKey)
|
|
187
|
+
? this.config.credentialsSsl.privateKey
|
|
188
|
+
: cross_helpers_1.path.join(this.baseDir, this.config.credentialsSsl.privateKey);
|
|
189
|
+
const absoluteCertChainPath = cross_helpers_1.path.isAbsolute(this.config.credentialsSsl.certChain)
|
|
190
|
+
? this.config.credentialsSsl.certChain
|
|
191
|
+
: cross_helpers_1.path.join(this.baseDir, this.config.credentialsSsl.certChain);
|
|
192
|
+
const sslFiles = [
|
|
193
|
+
cross_helpers_2.fs.promises.readFile(absolutePrivateKeyPath),
|
|
194
|
+
cross_helpers_2.fs.promises.readFile(absoluteCertChainPath),
|
|
195
|
+
];
|
|
196
|
+
if (this.config.credentialsSsl.rootCA !== 'rootCA') {
|
|
197
|
+
const absoluteRootCAPath = cross_helpers_1.path.isAbsolute(this.config.credentialsSsl.rootCA)
|
|
198
|
+
? this.config.credentialsSsl.rootCA
|
|
199
|
+
: cross_helpers_1.path.join(this.baseDir, this.config.credentialsSsl.rootCA);
|
|
200
|
+
sslFiles.unshift(cross_helpers_2.fs.promises.readFile(absoluteRootCAPath));
|
|
201
|
+
}
|
|
202
|
+
const [rootCA, privateKey, certChain] = await Promise.all(sslFiles);
|
|
203
|
+
return grpc_js_1.credentials.createSsl(rootCA, privateKey, certChain);
|
|
204
|
+
}
|
|
205
|
+
else if (this.config.useHTTPS) {
|
|
206
|
+
this.logger.debug(`Using SSL Connection`);
|
|
207
|
+
return grpc_js_1.credentials.createSsl();
|
|
208
|
+
}
|
|
209
|
+
this.logger.debug(`Using insecure connection`);
|
|
210
|
+
return grpc_js_1.credentials.createInsecure();
|
|
211
|
+
}
|
|
212
|
+
walkToFindTypePath(rootJson, pathWithName, baseTypePath) {
|
|
213
|
+
const currentWalkingPath = [...pathWithName];
|
|
214
|
+
while (!(0, lodash_has_1.default)(rootJson.nested, currentWalkingPath.concat(baseTypePath).join('.nested.'))) {
|
|
215
|
+
if (!currentWalkingPath.length) {
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
currentWalkingPath.pop();
|
|
219
|
+
}
|
|
220
|
+
return currentWalkingPath.concat(baseTypePath);
|
|
221
|
+
}
|
|
222
|
+
visit({ nested, name, currentPath, rootJson, creds, grpcObject, rootLogger: logger, }) {
|
|
223
|
+
var _a;
|
|
224
|
+
const pathWithName = [...currentPath, ...name.split('.')].filter(Boolean);
|
|
225
|
+
if ('nested' in nested) {
|
|
226
|
+
for (const key in nested.nested) {
|
|
227
|
+
logger.debug(`Visiting ${currentPath}.nested[${key}]`);
|
|
228
|
+
const currentNested = nested.nested[key];
|
|
229
|
+
this.visit({
|
|
230
|
+
nested: currentNested,
|
|
231
|
+
name: key,
|
|
232
|
+
currentPath: pathWithName,
|
|
233
|
+
rootJson,
|
|
234
|
+
creds,
|
|
235
|
+
grpcObject,
|
|
236
|
+
rootLogger: logger,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const typeName = pathWithName.join('_');
|
|
241
|
+
if ('values' in nested) {
|
|
242
|
+
const enumTypeConfig = {
|
|
243
|
+
name: typeName,
|
|
244
|
+
values: {},
|
|
245
|
+
description: nested.comment,
|
|
246
|
+
};
|
|
247
|
+
const commentMap = nested.comments;
|
|
248
|
+
for (const [key, value] of Object.entries(nested.values)) {
|
|
249
|
+
logger.debug(`Visiting ${currentPath}.nested.values[${key}]`);
|
|
250
|
+
enumTypeConfig.values[key] = {
|
|
251
|
+
value,
|
|
252
|
+
description: commentMap === null || commentMap === void 0 ? void 0 : commentMap[key],
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
this.schemaComposer.createEnumTC(enumTypeConfig);
|
|
256
|
+
}
|
|
257
|
+
else if ('fields' in nested) {
|
|
258
|
+
const inputTypeName = typeName + '_Input';
|
|
259
|
+
const outputTypeName = typeName;
|
|
260
|
+
const description = nested.comment;
|
|
261
|
+
const fieldEntries = Object.entries(nested.fields);
|
|
262
|
+
if (fieldEntries.length) {
|
|
263
|
+
const inputTC = this.schemaComposer.createInputTC({
|
|
264
|
+
name: inputTypeName,
|
|
265
|
+
description,
|
|
266
|
+
fields: {},
|
|
267
|
+
});
|
|
268
|
+
const outputTC = this.schemaComposer.createObjectTC({
|
|
269
|
+
name: outputTypeName,
|
|
270
|
+
description,
|
|
271
|
+
fields: {},
|
|
272
|
+
});
|
|
273
|
+
for (const [fieldName, { type, rule, comment, keyType }] of fieldEntries) {
|
|
274
|
+
logger.debug(`Visiting ${currentPath}.nested.fields[${fieldName}]`);
|
|
275
|
+
const baseFieldTypePath = type.split('.');
|
|
276
|
+
inputTC.addFields({
|
|
277
|
+
[fieldName]: {
|
|
278
|
+
type: () => {
|
|
279
|
+
let fieldInputTypeName;
|
|
280
|
+
if (keyType) {
|
|
281
|
+
fieldInputTypeName = 'JSON';
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
const fieldTypePath = this.walkToFindTypePath(rootJson, pathWithName, baseFieldTypePath);
|
|
285
|
+
fieldInputTypeName = (0, utils_js_1.getTypeName)(this.schemaComposer, fieldTypePath, true);
|
|
286
|
+
}
|
|
287
|
+
return rule === 'repeated' ? `[${fieldInputTypeName}]` : fieldInputTypeName;
|
|
288
|
+
},
|
|
289
|
+
description: comment,
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
outputTC.addFields({
|
|
293
|
+
[fieldName]: {
|
|
294
|
+
type: () => {
|
|
295
|
+
let fieldTypeName;
|
|
296
|
+
if (keyType) {
|
|
297
|
+
fieldTypeName = 'JSON';
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
const fieldTypePath = this.walkToFindTypePath(rootJson, pathWithName, baseFieldTypePath);
|
|
301
|
+
fieldTypeName = (0, utils_js_1.getTypeName)(this.schemaComposer, fieldTypePath, false);
|
|
302
|
+
}
|
|
303
|
+
return rule === 'repeated' ? `[${fieldTypeName}]` : fieldTypeName;
|
|
304
|
+
},
|
|
305
|
+
description: comment,
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
this.schemaComposer.createScalarTC({
|
|
312
|
+
...graphql_scalars_1.GraphQLJSON.toConfig(),
|
|
313
|
+
name: inputTypeName,
|
|
314
|
+
description,
|
|
315
|
+
});
|
|
316
|
+
this.schemaComposer.createScalarTC({
|
|
317
|
+
...graphql_scalars_1.GraphQLJSON.toConfig(),
|
|
318
|
+
name: outputTypeName,
|
|
319
|
+
description,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else if ('methods' in nested) {
|
|
324
|
+
const objPath = pathWithName.join('.');
|
|
325
|
+
const ServiceClient = (0, lodash_get_1.default)(grpcObject, objPath);
|
|
326
|
+
if (typeof ServiceClient !== 'function') {
|
|
327
|
+
throw new Error(`Object at path ${objPath} is not a Service constructor`);
|
|
328
|
+
}
|
|
329
|
+
const client = new ServiceClient((_a = string_interpolation_1.stringInterpolator.parse(this.config.endpoint, { env: cross_helpers_1.process.env })) !== null && _a !== void 0 ? _a : this.config.endpoint, creds);
|
|
330
|
+
const subId = this.pubsub.subscribe('destroy', () => {
|
|
331
|
+
client.close();
|
|
332
|
+
this.pubsub.unsubscribe(subId);
|
|
333
|
+
});
|
|
334
|
+
for (const methodName in nested.methods) {
|
|
335
|
+
const method = nested.methods[methodName];
|
|
336
|
+
const rootFieldName = [...pathWithName, methodName].join('_');
|
|
337
|
+
const fieldConfig = {
|
|
338
|
+
type: () => {
|
|
339
|
+
var _a;
|
|
340
|
+
const baseResponseTypePath = (_a = method.responseType) === null || _a === void 0 ? void 0 : _a.split('.');
|
|
341
|
+
if (baseResponseTypePath) {
|
|
342
|
+
const responseTypePath = this.walkToFindTypePath(rootJson, pathWithName, baseResponseTypePath);
|
|
343
|
+
let typeName = (0, utils_js_1.getTypeName)(this.schemaComposer, responseTypePath, false);
|
|
344
|
+
if (method.responseStream) {
|
|
345
|
+
typeName = `[${typeName}]`;
|
|
346
|
+
}
|
|
347
|
+
return typeName;
|
|
348
|
+
}
|
|
349
|
+
return 'Void';
|
|
350
|
+
},
|
|
351
|
+
description: method.comment,
|
|
352
|
+
};
|
|
353
|
+
fieldConfig.args = {
|
|
354
|
+
input: () => {
|
|
355
|
+
var _a;
|
|
356
|
+
if (method.requestStream) {
|
|
357
|
+
return 'File';
|
|
358
|
+
}
|
|
359
|
+
const baseRequestTypePath = (_a = method.requestType) === null || _a === void 0 ? void 0 : _a.split('.');
|
|
360
|
+
if (baseRequestTypePath) {
|
|
361
|
+
const requestTypePath = this.walkToFindTypePath(rootJson, pathWithName, baseRequestTypePath);
|
|
362
|
+
const requestTypeName = (0, utils_js_1.getTypeName)(this.schemaComposer, requestTypePath, true);
|
|
363
|
+
return requestTypeName;
|
|
364
|
+
}
|
|
365
|
+
return undefined;
|
|
366
|
+
},
|
|
367
|
+
};
|
|
368
|
+
const methodNameLowerCased = methodName.toLowerCase();
|
|
369
|
+
const prefixQueryMethod = this.config.prefixQueryMethod || QUERY_METHOD_PREFIXES;
|
|
370
|
+
const rootTypeComposer = prefixQueryMethod.some(prefix => methodNameLowerCased.startsWith(prefix))
|
|
371
|
+
? this.schemaComposer.Query
|
|
372
|
+
: this.schemaComposer.Mutation;
|
|
373
|
+
rootTypeComposer.addFields({
|
|
374
|
+
[rootFieldName]: {
|
|
375
|
+
...fieldConfig,
|
|
376
|
+
resolve: (root, args, context, info) => (0, utils_js_1.addMetaDataToCall)(client[methodName].bind(client), args.input, {
|
|
377
|
+
root,
|
|
378
|
+
args,
|
|
379
|
+
context,
|
|
380
|
+
env: cross_helpers_1.process.env,
|
|
381
|
+
}, this.config.metaData, !!method.responseStream),
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
const connectivityStateFieldName = pathWithName.join('_') + '_connectivityState';
|
|
386
|
+
this.schemaComposer.Query.addFields({
|
|
387
|
+
[connectivityStateFieldName]: {
|
|
388
|
+
type: 'ConnectivityState',
|
|
389
|
+
args: {
|
|
390
|
+
tryToConnect: {
|
|
391
|
+
type: 'Boolean',
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
resolve: (_, { tryToConnect }) => client.getChannel().getConnectivityState(tryToConnect),
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async getMeshSource() {
|
|
400
|
+
this.config.requestTimeout = this.config.requestTimeout || 200000;
|
|
401
|
+
this.schemaComposer.add(graphql_scalars_1.GraphQLBigInt);
|
|
402
|
+
this.schemaComposer.add(graphql_scalars_1.GraphQLByte);
|
|
403
|
+
this.schemaComposer.add(graphql_scalars_1.GraphQLUnsignedInt);
|
|
404
|
+
this.schemaComposer.add(graphql_scalars_1.GraphQLVoid);
|
|
405
|
+
this.schemaComposer.add(graphql_scalars_1.GraphQLJSON);
|
|
406
|
+
this.schemaComposer.createScalarTC({
|
|
407
|
+
name: 'File',
|
|
408
|
+
});
|
|
409
|
+
// identical of grpc's ConnectivityState
|
|
410
|
+
this.schemaComposer.createEnumTC({
|
|
411
|
+
name: 'ConnectivityState',
|
|
412
|
+
values: {
|
|
413
|
+
IDLE: { value: 0 },
|
|
414
|
+
CONNECTING: { value: 1 },
|
|
415
|
+
READY: { value: 2 },
|
|
416
|
+
TRANSIENT_FAILURE: { value: 3 },
|
|
417
|
+
SHUTDOWN: { value: 4 },
|
|
418
|
+
},
|
|
419
|
+
});
|
|
420
|
+
this.logger.debug(`Getting channel credentials`);
|
|
421
|
+
const creds = await this.getCredentials();
|
|
422
|
+
this.logger.debug(`Getting stored root and decoded descriptor set objects`);
|
|
423
|
+
const artifacts = await this.getCachedDescriptorSets(creds);
|
|
424
|
+
for (const { name, rootJson } of artifacts) {
|
|
425
|
+
const rootLogger = this.logger.child(name);
|
|
426
|
+
rootLogger.debug(`Creating package definition from file descriptor set object`);
|
|
427
|
+
let options;
|
|
428
|
+
if (typeof this.config.source === 'object') {
|
|
429
|
+
options = this.config.source.load;
|
|
430
|
+
}
|
|
431
|
+
const packageDefinition = (0, proto_loader_1.fromJSON)(rootJson, options);
|
|
432
|
+
rootLogger.debug(`Creating service client for package definition`);
|
|
433
|
+
const grpcObject = (0, grpc_js_1.loadPackageDefinition)(packageDefinition);
|
|
434
|
+
this.logger.debug(`Building the schema structure based on the root object`);
|
|
435
|
+
this.visit({
|
|
436
|
+
nested: rootJson,
|
|
437
|
+
name: '',
|
|
438
|
+
currentPath: [],
|
|
439
|
+
rootJson,
|
|
440
|
+
creds,
|
|
441
|
+
grpcObject,
|
|
442
|
+
rootLogger,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
// graphql-compose doesn't add @defer and @stream to the schema
|
|
446
|
+
graphql_1.specifiedDirectives.forEach(directive => this.schemaComposer.addDirective(directive));
|
|
447
|
+
this.logger.debug(`Building the final GraphQL Schema`);
|
|
448
|
+
const schema = this.schemaComposer.buildSchema();
|
|
449
|
+
return {
|
|
450
|
+
schema,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
exports.default = GrpcHandler;
|
package/cjs/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const long_1 = tslib_1.__importDefault(require("long"));
|
|
5
|
+
function patchLongJs() {
|
|
6
|
+
const originalLongFromValue = long_1.default.fromValue.bind(long_1.default);
|
|
7
|
+
long_1.default.fromValue = (value) => {
|
|
8
|
+
if (typeof value === 'bigint') {
|
|
9
|
+
return long_1.default.fromValue(value.toString());
|
|
10
|
+
}
|
|
11
|
+
return originalLongFromValue(value);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
patchLongJs();
|
package/cjs/scalars.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getGraphQLScalar = exports.isScalarType = void 0;
|
|
4
|
+
const SCALARS = new Map([
|
|
5
|
+
['bool', 'Boolean'],
|
|
6
|
+
['bytes', 'Byte'],
|
|
7
|
+
['double', 'Float'],
|
|
8
|
+
['fixed32', 'Int'],
|
|
9
|
+
['fixed64', 'BigInt'],
|
|
10
|
+
['float', 'Float'],
|
|
11
|
+
['int32', 'Int'],
|
|
12
|
+
['int64', 'BigInt'],
|
|
13
|
+
['sfixed32', 'Int'],
|
|
14
|
+
['sfixed64', 'BigInt'],
|
|
15
|
+
['sint32', 'Int'],
|
|
16
|
+
['sint64', 'BigInt'],
|
|
17
|
+
['string', 'String'],
|
|
18
|
+
['uint32', 'UnsignedInt'],
|
|
19
|
+
['uint64', 'BigInt'], // A new scalar might be needed
|
|
20
|
+
]);
|
|
21
|
+
function isScalarType(type) {
|
|
22
|
+
return SCALARS.has(type);
|
|
23
|
+
}
|
|
24
|
+
exports.isScalarType = isScalarType;
|
|
25
|
+
function getGraphQLScalar(scalarType) {
|
|
26
|
+
const gqlScalar = SCALARS.get(scalarType);
|
|
27
|
+
if (!gqlScalar) {
|
|
28
|
+
throw new Error(`Could not find GraphQL Scalar for type ${scalarType}`);
|
|
29
|
+
}
|
|
30
|
+
return SCALARS.get(scalarType);
|
|
31
|
+
}
|
|
32
|
+
exports.getGraphQLScalar = getGraphQLScalar;
|
package/cjs/utils.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addMetaDataToCall = exports.addIncludePathResolver = exports.getTypeName = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const lodash_get_1 = tslib_1.__importDefault(require("lodash.get"));
|
|
6
|
+
const cross_helpers_1 = require("@graphql-mesh/cross-helpers");
|
|
7
|
+
const string_interpolation_1 = require("@graphql-mesh/string-interpolation");
|
|
8
|
+
const utils_1 = require("@graphql-mesh/utils");
|
|
9
|
+
const grpc_js_1 = require("@grpc/grpc-js");
|
|
10
|
+
const scalars_js_1 = require("./scalars.js");
|
|
11
|
+
function getTypeName(schemaComposer, pathWithName, isInput) {
|
|
12
|
+
if (pathWithName === null || pathWithName === void 0 ? void 0 : pathWithName.length) {
|
|
13
|
+
const baseTypeName = pathWithName.filter(Boolean).join('_');
|
|
14
|
+
if ((0, scalars_js_1.isScalarType)(baseTypeName)) {
|
|
15
|
+
return (0, scalars_js_1.getGraphQLScalar)(baseTypeName);
|
|
16
|
+
}
|
|
17
|
+
if (schemaComposer.isEnumType(baseTypeName)) {
|
|
18
|
+
return baseTypeName;
|
|
19
|
+
}
|
|
20
|
+
return isInput ? baseTypeName + '_Input' : baseTypeName;
|
|
21
|
+
}
|
|
22
|
+
return 'Void';
|
|
23
|
+
}
|
|
24
|
+
exports.getTypeName = getTypeName;
|
|
25
|
+
function addIncludePathResolver(root, includePaths) {
|
|
26
|
+
const originalResolvePath = root.resolvePath;
|
|
27
|
+
root.resolvePath = (origin, target) => {
|
|
28
|
+
if (cross_helpers_1.path.isAbsolute(target)) {
|
|
29
|
+
return target;
|
|
30
|
+
}
|
|
31
|
+
for (const directory of includePaths) {
|
|
32
|
+
const fullPath = cross_helpers_1.path.join(directory, target);
|
|
33
|
+
if (cross_helpers_1.fs.existsSync(fullPath)) {
|
|
34
|
+
return fullPath;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const path = originalResolvePath(origin, target);
|
|
38
|
+
if (path === null) {
|
|
39
|
+
console.warn(`${target} not found in any of the include paths ${includePaths}`);
|
|
40
|
+
}
|
|
41
|
+
return path;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
exports.addIncludePathResolver = addIncludePathResolver;
|
|
45
|
+
function isBlob(input) {
|
|
46
|
+
return input != null && input.stream instanceof Function;
|
|
47
|
+
}
|
|
48
|
+
function addMetaDataToCall(callFn, input, resolverData, metaData, isResponseStream = false) {
|
|
49
|
+
const callFnArguments = [];
|
|
50
|
+
if (!isBlob(input)) {
|
|
51
|
+
callFnArguments.push(input);
|
|
52
|
+
}
|
|
53
|
+
if (metaData) {
|
|
54
|
+
const meta = new grpc_js_1.Metadata();
|
|
55
|
+
for (const [key, value] of Object.entries(metaData)) {
|
|
56
|
+
let metaValue = value;
|
|
57
|
+
if (Array.isArray(value)) {
|
|
58
|
+
// Extract data from context
|
|
59
|
+
metaValue = (0, lodash_get_1.default)(resolverData.context, value);
|
|
60
|
+
}
|
|
61
|
+
// Ensure that the metadata is compatible with what node-grpc expects
|
|
62
|
+
if (typeof metaValue !== 'string' && !(metaValue instanceof Buffer)) {
|
|
63
|
+
metaValue = JSON.stringify(metaValue);
|
|
64
|
+
}
|
|
65
|
+
if (typeof metaValue === 'string') {
|
|
66
|
+
metaValue = string_interpolation_1.stringInterpolator.parse(metaValue, resolverData);
|
|
67
|
+
}
|
|
68
|
+
meta.add(key, metaValue);
|
|
69
|
+
}
|
|
70
|
+
callFnArguments.push(meta);
|
|
71
|
+
}
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
const call = callFn(...callFnArguments, (error, response) => {
|
|
74
|
+
if (error) {
|
|
75
|
+
reject(error);
|
|
76
|
+
}
|
|
77
|
+
resolve(response);
|
|
78
|
+
});
|
|
79
|
+
if (isResponseStream) {
|
|
80
|
+
let isCancelled = false;
|
|
81
|
+
const responseStreamWithCancel = (0, utils_1.withCancel)(call, () => {
|
|
82
|
+
var _a;
|
|
83
|
+
if (!isCancelled) {
|
|
84
|
+
(_a = call.call) === null || _a === void 0 ? void 0 : _a.cancelWithStatus(0, 'Cancelled by GraphQL Mesh');
|
|
85
|
+
isCancelled = true;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
resolve(responseStreamWithCancel);
|
|
89
|
+
if (isBlob(input)) {
|
|
90
|
+
const blobStream = input.stream();
|
|
91
|
+
blobStream.pipe(call);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
exports.addMetaDataToCall = addMetaDataToCall;
|