@restorecommerce/facade 0.1.33 → 0.1.38

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 CHANGED
@@ -3,6 +3,52 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.1.38](https://github.com/restorecommerce/libs/compare/@restorecommerce/facade@0.1.37...@restorecommerce/facade@0.1.38) (2021-12-20)
7
+
8
+ **Note:** Version bump only for package @restorecommerce/facade
9
+
10
+
11
+
12
+
13
+
14
+ ## [0.1.37](https://github.com/restorecommerce/libs/compare/@restorecommerce/facade@0.1.36...@restorecommerce/facade@0.1.37) (2021-12-09)
15
+
16
+ **Note:** Version bump only for package @restorecommerce/facade
17
+
18
+
19
+
20
+
21
+
22
+ ## [0.1.36](https://github.com/restorecommerce/libs/compare/@restorecommerce/facade@0.1.35...@restorecommerce/facade@0.1.36) (2021-12-09)
23
+
24
+ **Note:** Version bump only for package @restorecommerce/facade
25
+
26
+
27
+
28
+
29
+
30
+ ## [0.1.35](https://github.com/restorecommerce/libs/compare/@restorecommerce/facade@0.1.34...@restorecommerce/facade@0.1.35) (2021-12-09)
31
+
32
+
33
+ ### Bug Fixes
34
+
35
+ * **facade:** updated generated schema for facade module due to changes in proto files. ([c57d5fa](https://github.com/restorecommerce/libs/commit/c57d5faaea1dbd287727f7c7678e6cfe34dba92d))
36
+
37
+
38
+
39
+
40
+
41
+ ## [0.1.34](https://github.com/restorecommerce/libs/compare/@restorecommerce/facade@0.1.33...@restorecommerce/facade@0.1.34) (2021-12-06)
42
+
43
+
44
+ ### Bug Fixes
45
+
46
+ * **facade:** Added streaming response handling for mutations and queries. ([199db2d](https://github.com/restorecommerce/libs/commit/199db2d51f5a1d08ec2af09579df9c742ae0bbb1))
47
+
48
+
49
+
50
+
51
+
6
52
  ## [0.1.33](https://github.com/restorecommerce/libs/compare/@restorecommerce/facade@0.1.32...@restorecommerce/facade@0.1.33) (2021-11-08)
7
53
 
8
54
  **Note:** Version bump only for package @restorecommerce/facade
@@ -2,6 +2,7 @@ import { GraphQLInputField, GraphQLResolveInfo, GraphQLSchema } from "graphql";
2
2
  import { GraphQLEnumType, GraphQLFieldConfig, GraphQLFieldConfigMap, GraphQLInputObjectType, GraphQLInputType, Thunk } from "graphql/type/definition";
3
3
  import { ServiceConfig, SubService, SubSpaceServiceConfig } from "./types";
4
4
  import { MethodDescriptorProto, ServiceDescriptorProto } from "ts-proto-descriptors/google/protobuf/descriptor";
5
+ import { GrpcClientConfig } from "@restorecommerce/grpc-client";
5
6
  export declare const getGQLSchema: <TSource, TContext>(method: MethodDescriptorProto) => GraphQLFieldConfig<TSource, TContext, {
6
7
  [argName: string]: any;
7
8
  }>;
@@ -13,7 +14,7 @@ declare type ServiceClient<Context extends Pick<Context, Key>, Key extends keyof
13
14
  client: T;
14
15
  };
15
16
  };
16
- export declare const getGQLResolverFunctions: <T extends Record<string, any>, CTX extends ServiceClient<CTX, keyof CTX, T>, SRV = any, R = ResolverFn<any, any, ServiceClient<CTX, keyof CTX, T>, any>, B extends keyof T = any, NS extends keyof CTX = any>(service: ServiceDescriptorProto, key: NS, serviceKey: B) => { [key in keyof SRV]: R; };
17
+ export declare const getGQLResolverFunctions: <T extends Record<string, any>, CTX extends ServiceClient<CTX, keyof CTX, T>, SRV = any, R = ResolverFn<any, any, ServiceClient<CTX, keyof CTX, T>, any>, B extends keyof T = any, NS extends keyof CTX = any>(service: ServiceDescriptorProto, key: NS, serviceKey: B, grpcClientConfig: GrpcClientConfig) => { [key in keyof SRV]: R; };
17
18
  export declare const registerResolverFunction: <T extends Record<string, any>, CTX extends ServiceClient<CTX, keyof CTX, T>>(namespace: string, name: string, func: ResolverFn<any, any, ServiceClient<CTX, keyof CTX, T>, any>, mutation?: boolean, subspace?: string | undefined) => void;
18
19
  export declare const generateResolver: (...namespaces: string[]) => any;
19
20
  export declare const registerResolverSchema: (namespace: string, name: string, schema: Thunk<GraphQLFieldConfig<any, any>>, mutation?: boolean, subspace?: string | undefined) => void;
@@ -6,6 +6,8 @@ const definition_1 = require("graphql/type/definition");
6
6
  const types_1 = require("./types");
7
7
  const registry_1 = require("./registry");
8
8
  const utils_1 = require("./utils");
9
+ const stream = require("stream");
10
+ const _ = require("lodash");
9
11
  const typeCache = new Map();
10
12
  const Mutate = ['Create', 'Update', 'Upsert'];
11
13
  const getGQLSchema = (method) => {
@@ -93,7 +95,7 @@ const recursiveUploadToBuffer = async (data, model) => {
93
95
  return data;
94
96
  };
95
97
  exports.recursiveUploadToBuffer = recursiveUploadToBuffer;
96
- const getGQLResolverFunctions = (service, key, serviceKey) => {
98
+ const getGQLResolverFunctions = (service, key, serviceKey, grpcClientConfig) => {
97
99
  if (!service.method) {
98
100
  return {};
99
101
  }
@@ -117,6 +119,7 @@ const getGQLResolverFunctions = (service, key, serviceKey) => {
117
119
  }
118
120
  }
119
121
  obj[method.name] = async (args, context) => {
122
+ var _a;
120
123
  const client = context[key].client;
121
124
  const service = client[serviceKey];
122
125
  try {
@@ -133,11 +136,57 @@ const getGQLResolverFunctions = (service, key, serviceKey) => {
133
136
  req.subject.token = authToken.split(' ')[1];
134
137
  }
135
138
  }
136
- // TODO Handle client-stream methods
137
139
  const result = await service[method.name](req);
140
+ const bufferFields = utils_1.getKeys((_a = grpcClientConfig) === null || _a === void 0 ? void 0 : _a.bufferFields);
141
+ if (result instanceof stream.Readable) {
142
+ let operationStatus = { code: 0, message: '' };
143
+ let aggregatedResponse = await new Promise((resolve, reject) => {
144
+ let response = {};
145
+ result.on('data', (chunk) => {
146
+ const chunkObj = _.cloneDeep(chunk);
147
+ if (!response) {
148
+ response = chunk;
149
+ }
150
+ else {
151
+ Object.assign(response, chunk);
152
+ }
153
+ const existingBufferFields = _.intersection(Object.keys(chunk), bufferFields);
154
+ for (let bufferField of existingBufferFields) {
155
+ if (chunkObj[bufferField] && chunkObj[bufferField].value) {
156
+ if (response[bufferField] && response[bufferField].value && !_.isArray(response[bufferField].value)) {
157
+ response[bufferField].value = [];
158
+ }
159
+ let data = JSON.parse(chunkObj[bufferField].value.toString());
160
+ if (_.isArray(data)) {
161
+ for (let dataObj of data) {
162
+ response[bufferField].value.push(dataObj);
163
+ }
164
+ }
165
+ else {
166
+ response[bufferField].value.push(data);
167
+ }
168
+ }
169
+ }
170
+ });
171
+ result.on('error', (err) => {
172
+ console.error(err);
173
+ operationStatus.code = err.code ? err.code : 500;
174
+ operationStatus.message = err.message;
175
+ });
176
+ result.on('end', () => {
177
+ if (_.isEmpty(operationStatus.message)) {
178
+ operationStatus.code = 200;
179
+ operationStatus.message = 'success';
180
+ }
181
+ resolve(response);
182
+ });
183
+ });
184
+ return { details: aggregatedResponse, operationStatus };
185
+ }
186
+ let items = utils_1.decodeBufferFields(result.items, bufferFields);
138
187
  return {
139
188
  details: {
140
- items: result.items,
189
+ items: items,
141
190
  operationStatus: result.operationStatus // overall status
142
191
  },
143
192
  };
@@ -210,10 +259,79 @@ const MutateResolver = async (req, ctx, schema) => {
210
259
  if (authToken && authToken.startsWith('Bearer ')) {
211
260
  subject.token = authToken.split(' ')[1];
212
261
  }
262
+ // TODO identify google.protobufAny from config
263
+ for (let item of input.items) {
264
+ let keys = Object.keys(item);
265
+ for (let key of keys) {
266
+ if (item[key] && item[key].value) {
267
+ item[key] = { typeUrl: '', value: Buffer.from(JSON.stringify(item.data.value)) };
268
+ }
269
+ }
270
+ }
213
271
  const result = await service[method]({
214
272
  items: input === null || input === void 0 ? void 0 : input.items,
215
273
  subject
216
274
  });
275
+ // TODO read from grpcClientConfig
276
+ // const bufferFields = getKeys((grpcClientConfig as any)?.bufferFields);
277
+ const bufferFields = [];
278
+ if (result instanceof stream.Readable) {
279
+ let operationStatus = { code: 0, message: '' };
280
+ let aggregatedResponse = await new Promise((resolve, reject) => {
281
+ let response = {};
282
+ result.on('data', (chunk) => {
283
+ const chunkObj = _.cloneDeep(chunk);
284
+ if (!response) {
285
+ response = chunk;
286
+ }
287
+ else {
288
+ Object.assign(response, chunk);
289
+ }
290
+ const existingBufferFields = _.intersection(Object.keys(chunk), bufferFields);
291
+ for (let bufferField of existingBufferFields) {
292
+ if (chunkObj[bufferField] && chunkObj[bufferField].value) {
293
+ if (response[bufferField] && response[bufferField].value && !_.isArray(response[bufferField].value)) {
294
+ response[bufferField].value = [];
295
+ }
296
+ let data = JSON.parse(chunkObj[bufferField].value.toString());
297
+ if (_.isArray(data)) {
298
+ for (let dataObj of data) {
299
+ response[bufferField].value.push(dataObj);
300
+ }
301
+ }
302
+ else {
303
+ response[bufferField].value.push(data);
304
+ }
305
+ }
306
+ }
307
+ });
308
+ result.on('error', (err) => {
309
+ console.error(err);
310
+ operationStatus.code = err.code ? err.code : 500;
311
+ operationStatus.message = err.message;
312
+ });
313
+ result.on('end', () => {
314
+ if (_.isEmpty(operationStatus.message)) {
315
+ operationStatus.code = 200;
316
+ operationStatus.message = 'success';
317
+ }
318
+ resolve(response);
319
+ });
320
+ });
321
+ return { details: { items: aggregatedResponse, operationStatus } };
322
+ }
323
+ // TODO identify google.protobufAny from config
324
+ // let items = decodeBufferFields(result.items, bufferFields);
325
+ for (let item of result.items) {
326
+ if (item && item.payload) {
327
+ const keys = Object.keys(item.payload);
328
+ for (let bufferField of keys) {
329
+ if (item.payload[bufferField] && item.payload[bufferField].value) {
330
+ item.payload[bufferField].value = JSON.parse(item.payload[bufferField].value.toString());
331
+ }
332
+ }
333
+ }
334
+ }
217
335
  return {
218
336
  details: {
219
337
  items: result.items,
@@ -470,7 +588,7 @@ const getAndGenerateSchema = (service, namespace, prefix, cfg, queryList) => {
470
588
  exports.getAndGenerateSchema = getAndGenerateSchema;
471
589
  const getAndGenerateResolvers = (service, namespace, cfg, queryList, subspace = undefined, serviceKey = undefined) => {
472
590
  const { mutations, queries } = exports.getWhitelistBlacklistConfig(service, queryList, cfg);
473
- const func = exports.getGQLResolverFunctions(service, namespace, serviceKey || subspace || namespace);
591
+ const func = exports.getGQLResolverFunctions(service, namespace, serviceKey || subspace || namespace, cfg.client);
474
592
  Object.keys(func).forEach(k => {
475
593
  exports.registerResolverFunction(namespace, k, func[k], !queries.has(k) && mutations.has(k), subspace);
476
594
  });
@@ -497,7 +615,7 @@ exports.generateSubServiceSchemas = generateSubServiceSchemas;
497
615
  const generateSubServiceResolvers = (subServices, config, namespace) => {
498
616
  subServices.forEach((sub) => {
499
617
  const { mutations, queries } = exports.getWhitelistBlacklistConfig(sub.service, sub.queries, config);
500
- const func = exports.getGQLResolverFunctions(sub.service, namespace, sub.name || namespace);
618
+ const func = exports.getGQLResolverFunctions(sub.service, namespace, sub.name || namespace, config.client);
501
619
  Object.keys(func).forEach(k => {
502
620
  exports.registerResolverFunction(config.root ? sub.name : namespace, k, func[k], !queries.has(k) && mutations.has(k), config.root ? undefined : sub.name);
503
621
  });
@@ -1,2 +1,4 @@
1
1
  export declare const capitalizeProtoName: (name: string) => string;
2
2
  export declare const convertyCamelToSnakeCase: (entity: string) => string;
3
+ export declare const getKeys: (obj: any) => string[];
4
+ export declare const decodeBufferFields: (items: any, bufferFields: string[]) => any;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertyCamelToSnakeCase = exports.capitalizeProtoName = void 0;
3
+ exports.decodeBufferFields = exports.getKeys = exports.convertyCamelToSnakeCase = exports.capitalizeProtoName = void 0;
4
+ const _ = require("lodash");
4
5
  const capitalizeProtoName = (name) => {
5
6
  return name.replace(/(?:\.|^|_)(\w)/g, v => v.toUpperCase()).replace(/[._]/g, '');
6
7
  };
@@ -10,3 +11,40 @@ const convertyCamelToSnakeCase = (entity) => {
10
11
  return entity.replace(/(?:^|\.?)([A-Z])/g, (x, y) => { return '_' + y.toLowerCase(); }).replace(/^_/, '');
11
12
  };
12
13
  exports.convertyCamelToSnakeCase = convertyCamelToSnakeCase;
14
+ const getKeys = (obj) => {
15
+ let set = new Set();
16
+ if (obj) {
17
+ const keys = Object.keys(obj);
18
+ for (let key of keys) {
19
+ if (typeof obj[key] === 'string') {
20
+ set.add(obj[key]);
21
+ }
22
+ else if (Array.isArray(obj[key])) {
23
+ for (let value of obj[key]) {
24
+ set.add(value);
25
+ }
26
+ }
27
+ }
28
+ }
29
+ return Array.from(set);
30
+ };
31
+ exports.getKeys = getKeys;
32
+ const decodeBufferFields = (items, bufferFields) => {
33
+ if (bufferFields && bufferFields.length > 0 && items && items.length > 0) {
34
+ for (let item of items) {
35
+ if (item && item.payload) {
36
+ const existingBufferFields = _.intersection(Object.keys(item.payload), bufferFields);
37
+ for (let bufferField of existingBufferFields) {
38
+ if (item.payload[bufferField] && item.payload[bufferField].value) {
39
+ item.payload[bufferField].value = JSON.parse(item.payload[bufferField].value.toString());
40
+ }
41
+ }
42
+ }
43
+ }
44
+ return items;
45
+ }
46
+ else {
47
+ return items;
48
+ }
49
+ };
50
+ exports.decodeBufferFields = decodeBufferFields;
package/dist/index.js CHANGED
@@ -188,7 +188,6 @@ class RestoreCommerceFacade {
188
188
  }
189
189
  exports.RestoreCommerceFacade = RestoreCommerceFacade;
190
190
  function createFacade(config) {
191
- var _a;
192
191
  const koa = new koa_1.default();
193
192
  if (config.env) {
194
193
  koa.env = config.env;
@@ -196,7 +195,15 @@ function createFacade(config) {
196
195
  if (config.keys) {
197
196
  koa.keys = config.keys;
198
197
  }
199
- const logger = (_a = config.logger) !== null && _a !== void 0 ? _a : logger_1.createLogger(config.logger);
198
+ let loggerCfg;
199
+ if (config.logger) {
200
+ loggerCfg = config.logger;
201
+ loggerCfg.esTransformer = (msg) => {
202
+ msg.fields = JSON.stringify(msg.fields);
203
+ return msg;
204
+ };
205
+ }
206
+ const logger = loggerCfg !== null && loggerCfg !== void 0 ? loggerCfg : logger_1.createLogger(loggerCfg);
200
207
  koa.context.logger = logger;
201
208
  return new RestoreCommerceFacade({
202
209
  koa,
@@ -10,8 +10,15 @@ const debug = debug_1.default('@restorecommerce/koa-req-res-logger');
10
10
  @returns {Middleware}
11
11
  */
12
12
  const reqResLogger = (opts) => {
13
- var _a;
14
- const logger = (_a = opts.logger) !== null && _a !== void 0 ? _a : logger_1.createLogger();
13
+ let loggerCfg;
14
+ if (opts.logger) {
15
+ loggerCfg = opts.logger;
16
+ loggerCfg.esTransformer = (msg) => {
17
+ msg.fields = JSON.stringify(msg.fields);
18
+ return msg;
19
+ };
20
+ }
21
+ const logger = loggerCfg !== null && loggerCfg !== void 0 ? loggerCfg : logger_1.createLogger(loggerCfg);
15
22
  const fn = async (ctx, next) => {
16
23
  const request = ctx.request;
17
24
  debug('yield middleware: %s', exports.reqResLogger.name);