1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | var _exportNames = {
|
7 | decorators: true,
|
8 | Resolvers: true
|
9 | };
|
10 | Object.defineProperty(exports, "Resolvers", {
|
11 | enumerable: true,
|
12 | get: function () {
|
13 | return _Resolvers.default;
|
14 | }
|
15 | });
|
16 | exports.decorators = exports.default = void 0;
|
17 |
|
18 | var _easevalidation = require("easevalidation");
|
19 |
|
20 | var _graphql = require("graphql");
|
21 |
|
22 | var _glob = _interopRequireDefault(require("glob"));
|
23 |
|
24 | var _path = _interopRequireDefault(require("path"));
|
25 |
|
26 | var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
27 |
|
28 | var _get = _interopRequireDefault(require("lodash/get"));
|
29 |
|
30 | var _set = _interopRequireDefault(require("lodash/set"));
|
31 |
|
32 | var _has = _interopRequireDefault(require("lodash/has"));
|
33 |
|
34 | var _pick = _interopRequireDefault(require("lodash/pick"));
|
35 |
|
36 | var _isPlainObject = _interopRequireDefault(require("lodash/isPlainObject"));
|
37 |
|
38 | var _invariant = _interopRequireDefault(require("invariant"));
|
39 |
|
40 | var _identity = _interopRequireDefault(require("lodash/identity"));
|
41 |
|
42 | var _oors = require("oors");
|
43 |
|
44 | var _graphqlSubscriptions = require("graphql-subscriptions");
|
45 |
|
46 | var _merge = _interopRequireDefault(require("lodash/merge"));
|
47 |
|
48 | var _graphqlTools = require("graphql-tools");
|
49 |
|
50 | var _middleware = require("graphql-voyager/middleware");
|
51 |
|
52 | var _graphqlImport = require("graphql-import");
|
53 |
|
54 | var _graphqlBinding = require("graphql-binding");
|
55 |
|
56 | var _graphqlConstraintDirective = _interopRequireDefault(require("graphql-constraint-directive"));
|
57 |
|
58 | var _graphqlDepthLimit = _interopRequireDefault(require("graphql-depth-limit"));
|
59 |
|
60 | var _validators = require("oors-express/build/validators");
|
61 |
|
62 | var _resolvers = _interopRequireDefault(require("./graphql/resolvers"));
|
63 |
|
64 | var _modulesResolvers = _interopRequireDefault(require("./graphql/modulesResolvers"));
|
65 |
|
66 | var _LoadersMap = _interopRequireDefault(require("./libs/LoadersMap"));
|
67 |
|
68 | var decorators = _interopRequireWildcard(require("./decorators"));
|
69 |
|
70 | exports.decorators = decorators;
|
71 | Object.keys(decorators).forEach(function (key) {
|
72 | if (key === "default" || key === "__esModule") return;
|
73 | if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
74 | Object.defineProperty(exports, key, {
|
75 | enumerable: true,
|
76 | get: function () {
|
77 | return decorators[key];
|
78 | }
|
79 | });
|
80 | });
|
81 |
|
82 | var _Server = _interopRequireDefault(require("./libs/Server"));
|
83 |
|
84 | var _Resolvers = _interopRequireDefault(require("./libs/Resolvers"));
|
85 |
|
86 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
|
87 |
|
88 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
89 |
|
90 | function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
91 |
|
92 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
93 |
|
94 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
95 |
|
96 | const asyncGlob = (...args) => new Promise((resolve, reject) => {
|
97 | (0, _glob.default)(...args, (err, files) => {
|
98 | if (err) {
|
99 | reject(err);
|
100 | } else {
|
101 | resolve(files);
|
102 | }
|
103 | });
|
104 | });
|
105 |
|
106 | class Gql extends _oors.Module {
|
107 | constructor(..._args) {
|
108 | super(..._args);
|
109 | this.name = 'oors.graphql';
|
110 | this.hooks = {
|
111 | 'oors.cache.load': ({
|
112 | createPolicy
|
113 | }) => {
|
114 | createPolicy('graphqlResolvers');
|
115 | }
|
116 | };
|
117 |
|
118 | this.teardown = () => this.server.stop();
|
119 |
|
120 | this.extendContext = extender => {
|
121 | (0, _invariant.default)(typeof extender === 'function' || (0, _isPlainObject.default)(extender), `Invalid context extender! Needs to be either a function or a an object that will get
|
122 | assigned to the context.`);
|
123 | this.contextExtenders.push(extender);
|
124 | return this.contextExtenders;
|
125 | };
|
126 |
|
127 | this.bindSchema = (schema, options = {}) => new _graphqlBinding.Binding(_objectSpread({
|
128 | schema
|
129 | }, options));
|
130 |
|
131 | this.addTypeDefs = typeDefs => {
|
132 | this.typeDefs.push(typeDefs);
|
133 | };
|
134 |
|
135 | this.addDirectives = directives => {
|
136 | Object.assign(this.directives, directives);
|
137 | };
|
138 |
|
139 | this.addResolvers = resolvers => {
|
140 | if (this.schema) {
|
141 | (0, _graphqlTools.addResolveFunctionsToSchema)({
|
142 | schema: this.schema,
|
143 | resolvers
|
144 | });
|
145 | } else {
|
146 | (0, _merge.default)(this.resolvers, resolvers);
|
147 | }
|
148 | };
|
149 |
|
150 | this.addResolverMiddleware = (matcher, middleware) => {
|
151 | this.resolverMiddlewares.push({
|
152 | matcher: typeof matcher === 'string' ? new RegExp(`^${matcher}$`) : matcher,
|
153 | middleware
|
154 | });
|
155 | return this;
|
156 | };
|
157 |
|
158 | this.addLoader = (...args) => {
|
159 | this.loaders.add(...args);
|
160 | };
|
161 |
|
162 | this.addLoaders = (...args) => {
|
163 | this.loaders.multiAdd(...args);
|
164 | };
|
165 |
|
166 | this.addTypeDefsByPath = async filePath => {
|
167 | this.addTypeDefs((await _fsExtra.default.readFile(filePath, 'utf8')));
|
168 | };
|
169 |
|
170 | this.importSchema = schemaPath => {
|
171 | this.addTypeDefs((0, _graphqlImport.importSchema)(schemaPath));
|
172 | };
|
173 |
|
174 | this.loadFromDir = async dirPath => Promise.all([this.loadTypeDefsFromDir(dirPath), this.loadResolversFromDir(dirPath), this.loadDirectivesFromDir(dirPath)]);
|
175 |
|
176 | this.loadTypeDefsFromDir = async dirPath => {
|
177 | try {
|
178 |
|
179 | const typeDefsDirPath = _path.default.join(dirPath, 'typeDefs');
|
180 |
|
181 | const stats = await _fsExtra.default.stat(typeDefsDirPath);
|
182 |
|
183 | if (stats.isDirectory()) {
|
184 | const files = await asyncGlob(_path.default.resolve(typeDefsDirPath, '**/*.graphql'));
|
185 | await Promise.all(files.map(file => this.addTypeDefsByPath(file)));
|
186 | }
|
187 | } catch (_unused) {
|
188 |
|
189 | try {
|
190 | await this.addTypeDefsByPath(_path.default.join(dirPath, 'typeDefs.graphql'));
|
191 | } catch (_unused2) {}
|
192 | }
|
193 | };
|
194 |
|
195 | this.loadResolversFromDir = async dirPath => {
|
196 | try {
|
197 | const resolvers = require(`${dirPath}/resolvers`);
|
198 |
|
199 | if (resolvers.default) {
|
200 | Object.assign(resolvers, resolvers.default);
|
201 | delete resolvers.default;
|
202 | }
|
203 |
|
204 | this.addResolvers(resolvers);
|
205 | } catch (err) {
|
206 | const resolversPath = await asyncGlob(_path.default.resolve(`${dirPath}/resolvers`, '**/*.js'));
|
207 | const resolvers = resolversPath.reduce((acc, resolverPath) => {
|
208 | const resolverName = _path.default.relative(`${dirPath}/resolvers`, resolverPath).slice(0, -3).split(_path.default.sep).join('.');
|
209 |
|
210 | (0, _set.default)(acc, resolverName, require(resolverPath).default);
|
211 | return acc;
|
212 | }, {});
|
213 | this.addResolvers(resolvers);
|
214 | }
|
215 | };
|
216 |
|
217 | this.loadDirectivesFromDir = async dirPath => {
|
218 | try {
|
219 | const directives = require(`${dirPath}/directives`);
|
220 |
|
221 | if (directives.default) {
|
222 | Object.assign(directives, directives.default);
|
223 | delete directives.default;
|
224 | }
|
225 |
|
226 | this.addDirectives(directives);
|
227 | } catch (err) {}
|
228 | };
|
229 |
|
230 | this.collectFromModule = async module => {
|
231 | if (!module.getConfig('oors.graphql.autoload', true)) {
|
232 | return;
|
233 | }
|
234 |
|
235 | if ((0, _has.default)(module, 'graphql')) {
|
236 | this.addTypeDefs((0, _get.default)(module, 'graphql.typeDefs', ''));
|
237 | this.addResolvers((0, _get.default)(module, 'graphql.resolvers', {}));
|
238 |
|
239 | if ((0, _has.default)(module, 'graphql.typeDefsPath')) {
|
240 | await this.addTypeDefsByPath((0, _get.default)(module, 'graphql.typeDefsPath'));
|
241 | }
|
242 | } else {
|
243 | await this.loadFromDir(_path.default.resolve(_path.default.dirname(module.filePath), 'graphql'));
|
244 | }
|
245 | };
|
246 |
|
247 | this.buildSchema = async () => {
|
248 | const schema = (0, _graphqlTools.makeExecutableSchema)(this.getConfig('configureSchema', _identity.default)({
|
249 | typeDefs: this.typeDefs,
|
250 | resolvers: this.applyResolversMiddlewares(this.resolvers),
|
251 | logger: {
|
252 | log: err => {
|
253 | this.emit('error', err);
|
254 | }
|
255 | },
|
256 | allowUndefinedInResolve: false,
|
257 | inheritResolversFromInterfaces: true,
|
258 | schemaDirectives: this.directives
|
259 | }));
|
260 | const schemas = (await this.runHook('getSchema', () => {}, {
|
261 | schema,
|
262 | mergeSchemas: _graphqlTools.mergeSchemas,
|
263 | makeExecutableSchema: _graphqlTools.makeExecutableSchema,
|
264 | makeRemoteExecutableSchema: _graphqlTools.makeRemoteExecutableSchema
|
265 | })).filter(s => s);
|
266 | return schemas.length ? (0, _graphqlTools.mergeSchemas)({
|
267 | schemas: [schema, ...schemas]
|
268 | }) : schema;
|
269 | };
|
270 |
|
271 | this.buildServer = (options = {}) => {
|
272 | const config = _objectSpread({
|
273 | context: this.buildContext,
|
274 | formatError: this.format('error'),
|
275 | formatParams: this.format('params'),
|
276 | formatResponse: this.format('response'),
|
277 | schema: this.schema,
|
278 | debug: true,
|
279 | tracing: true,
|
280 | cacheControl: true,
|
281 | subscriptions: true,
|
282 | introspection: true,
|
283 | mocks: false,
|
284 | persistedQueries: true,
|
285 | validationRules: [(0, _graphqlDepthLimit.default)(this.getConfig('depthLimit.limit'), this.getConfig('depthLimit.options'), this.getConfig('depthLimit.callback'))],
|
286 | costAnalysisConfig: this.getConfig('costAnalysis')
|
287 | }, this.getConfig('serverOptions'), {}, options);
|
288 |
|
289 | const server = new _Server.default(config);
|
290 |
|
291 | if (config.subscriptions) {
|
292 | server.installSubscriptionHandlers(this.deps['oors.express'].server);
|
293 | }
|
294 |
|
295 | return server;
|
296 | };
|
297 |
|
298 | this.buildContext = ({
|
299 | req,
|
300 | connection
|
301 | } = {}) => {
|
302 | const context = _objectSpread({}, this.gqlContext, {
|
303 | loaders: this.loaders.build(),
|
304 | req,
|
305 | connection
|
306 | }, req ? {
|
307 | user: req.user
|
308 | } : {}, {}, connection ? connection.context || {} : {});
|
309 |
|
310 | this.contextExtenders.forEach(extender => extender(context));
|
311 |
|
312 | context.execute = (source, options = {}) => this.execute(source, _objectSpread({}, options, {
|
313 | context: () => _objectSpread({}, context, {}, options.context || {})
|
314 | }));
|
315 |
|
316 | return context;
|
317 | };
|
318 |
|
319 | this.execute = (source, options = {}) => {
|
320 | const {
|
321 | root,
|
322 | context,
|
323 | variables,
|
324 | operation
|
325 | } = _objectSpread({
|
326 | root: undefined,
|
327 | variables: {},
|
328 | operation: undefined
|
329 | }, options, {
|
330 | context: typeof options.context === 'function' ? options.context(this.buildContext) : _objectSpread({}, this.buildContext(), {}, options.context || {})
|
331 | });
|
332 |
|
333 | return (0, _graphql.graphql)(this.schema, source, root, context, variables, operation);
|
334 | };
|
335 |
|
336 | this.format = type => {
|
337 | (0, _invariant.default)(Array.isArray(this.formatters[type]), `Unknown formatter type - ${type}!`);
|
338 | return arg => this.formatters[type].reduce((acc, formatter) => formatter(acc), arg);
|
339 | };
|
340 | }
|
341 |
|
342 | initialize() {
|
343 | this.typeDefs = [];
|
344 | this.directives = {
|
345 | constraint: _graphqlConstraintDirective.default
|
346 | };
|
347 | this.resolvers = _resolvers.default;
|
348 | this.resolverMiddlewares = [];
|
349 | this.pubsub = this.getConfig('pubsub', new _graphqlSubscriptions.PubSub());
|
350 | this.gqlContext = {
|
351 | pubsub: this.pubsub,
|
352 | modules: this.manager
|
353 | };
|
354 | this.loaders = new _LoadersMap.default();
|
355 | this.contextExtenders = [];
|
356 | this.formatters = {
|
357 | params: [],
|
358 | error: [],
|
359 | response: []
|
360 | };
|
361 | }
|
362 |
|
363 | async setup() {
|
364 | await this.loadDependencies(['oors.express']);
|
365 | await this.runHook('load', this.collectFromModule, (0, _pick.default)(this, ['pubsub', 'addTypeDefs', 'addDirectives', 'addTypeDefsByPath', 'addResolvers', 'addResolverMiddleware', 'addLoader', 'loadFromDir']));
|
366 | Object.assign(this.gqlContext, {
|
367 | app: this.deps['oors.express'].app
|
368 | });
|
369 |
|
370 | if (this.getConfig('exposeModules')) {
|
371 | this.addResolvers(_modulesResolvers.default);
|
372 | await this.addTypeDefsByPath(_path.default.resolve(__dirname, './graphql/modulesTypeDefs.graphql'));
|
373 | }
|
374 |
|
375 | await this.runHook('buildContext', () => {}, {
|
376 | context: this.gqlContext
|
377 | });
|
378 | this.schema = await this.buildSchema();
|
379 | this.server = this.buildServer();
|
380 | this.applyMiddlewares(this.server);
|
381 | const binding = this.bindSchema(this.schema);
|
382 | this.exportProperties(['extendContext', 'schema', 'server', 'loaders', 'addResolverMiddleware', 'addLoader', 'addLoaders', 'addResolvers', 'importSchema', 'bindSchema', 'binding', 'setupListen', 'pubsub', 'formatters', 'buildContext', 'execute']);
|
383 | this.export({
|
384 | context: this.gqlContext,
|
385 | addSchemaResolvers: rootResolveFunction => (0, _graphqlTools.addSchemaLevelResolveFunction)(this.schema, rootResolveFunction),
|
386 | addDirectivesResolvers: directivesResolvers => (0, _graphqlTools.attachDirectiveResolvers)(this.schema, directivesResolvers)
|
387 | });
|
388 | this.on('after:setup', () => {
|
389 | Object.assign(this.gqlContext, {
|
390 | binding
|
391 | });
|
392 | });
|
393 | }
|
394 |
|
395 | applyResolversMiddlewares(resolvers) {
|
396 | if (!this.resolverMiddlewares.length) {
|
397 | return resolvers;
|
398 | }
|
399 |
|
400 | return Object.keys(resolvers).reduce((resolversAcc, type) => _objectSpread({}, resolversAcc, {
|
401 | [type]: Object.keys(resolvers[type]).reduce((typeAcc, field) => {
|
402 | let resolver = resolvers[type][field];
|
403 | const branch = `${type}.${field}`;
|
404 | const middlewares = this.resolverMiddlewares.filter(({
|
405 | matcher
|
406 | }) => matcher.test(branch));
|
407 |
|
408 | if (middlewares.length) {
|
409 | resolver = [...middlewares].reverse().reduce((acc, {
|
410 | middleware
|
411 | }) => (...args) => middleware(...args, acc), resolver);
|
412 | }
|
413 |
|
414 | return _objectSpread({}, typeAcc, {
|
415 | [field]: resolver
|
416 | });
|
417 | }, {})
|
418 | }), {});
|
419 | }
|
420 |
|
421 | applyMiddlewares(server) {
|
422 | this.deps['oors.express'].middlewares.insertBefore(this.getConfig('middlewarePivot'), this.getApolloServerMiddlewares(server), this.getVoyagerMiddleware());
|
423 | }
|
424 |
|
425 |
|
426 | getApolloServerMiddlewares(server) {
|
427 | return {
|
428 | id: 'apolloServer',
|
429 | apply: ({
|
430 | app
|
431 | }) => {
|
432 | server.applyMiddleware({
|
433 | app,
|
434 | cors: false,
|
435 | bodyParserConfig: false,
|
436 | onHealthCheck: req => this.asyncEmit('healthCheck', req)
|
437 | });
|
438 | }
|
439 | };
|
440 | }
|
441 |
|
442 | getVoyagerMiddleware() {
|
443 | return {
|
444 | id: 'voyager',
|
445 | path: '/voyager',
|
446 | factory: ({
|
447 | endpointURL
|
448 | }) => (0, _middleware.express)({
|
449 | endpointUrl: endpointURL
|
450 | }),
|
451 | params: this.getConfig('voyager.params'),
|
452 | enabled: this.getConfig('voyager.enabled')
|
453 | };
|
454 | }
|
455 |
|
456 | }
|
457 |
|
458 | exports.default = Gql;
|
459 | Gql.validateConfig = (0, _easevalidation.validate)(_easevalidation.validators.isSchema({
|
460 | voyager: [_easevalidation.validators.isDefault({}), _easevalidation.validators.isSchema({
|
461 | enabled: [_easevalidation.validators.isDefault(true), _easevalidation.validators.isBoolean()],
|
462 | params: [_easevalidation.validators.isDefault({}), _easevalidation.validators.isSchema({
|
463 | endpointURL: [_easevalidation.validators.isDefault('/graphql'), _easevalidation.validators.isString()]
|
464 | })]
|
465 | })],
|
466 | middlewarePivot: [_easevalidation.validators.isDefault('isMethod'), (0, _validators.isMiddlewarePivot)()],
|
467 | configureSchema: _easevalidation.validators.isAny(_easevalidation.validators.isFunction(), _easevalidation.validators.isUndefined()),
|
468 | exposeModules: [_easevalidation.validators.isDefault(true), _easevalidation.validators.isBoolean()],
|
469 | serverOptions: [_easevalidation.validators.isDefault({}), _easevalidation.validators.isObject()],
|
470 | pubsub: _easevalidation.validators.isAny(_easevalidation.validators.isObject(), _easevalidation.validators.isUndefined()),
|
471 | depthLimit: [_easevalidation.validators.isDefault({}), _easevalidation.validators.isSchema({
|
472 | limit: [_easevalidation.validators.isDefault(10), _easevalidation.validators.isInteger()],
|
473 | options: _easevalidation.validators.isAny(_easevalidation.validators.isSchema({
|
474 | ignore: [_easevalidation.validators.isDefault([]), _easevalidation.validators.isArray()]
|
475 | }), _easevalidation.validators.isUndefined()),
|
476 | callback: _easevalidation.validators.isAny(_easevalidation.validators.isFunction(), _easevalidation.validators.isUndefined())
|
477 | })],
|
478 | costAnalysis: [_easevalidation.validators.isDefault({}), _easevalidation.validators.isSchema({
|
479 | maximumCost: [_easevalidation.validators.isDefault(1000), _easevalidation.validators.isInteger(), _easevalidation.validators.isPositive()]
|
480 | })]
|
481 | })); |
\ | No newline at end of file |