@steedos/service-api 2.6.1-beta.6 → 2.6.2-beta.10

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.
Files changed (2) hide show
  1. package/index.js +71 -28
  2. package/package.json +11 -6
package/index.js CHANGED
@@ -13,11 +13,12 @@ const {
13
13
  const SteedosRouter = require('@steedos/router');
14
14
  const _ = require('lodash');
15
15
  const ServiceObjectGraphql = require('@steedos/service-object-graphql')
16
- const open = require('open');
17
16
  const DataLoader = require("dataloader");
18
17
  const { LRUMap } = require('lru_map');
19
18
  const validator = require('validator');
20
19
  const enablePlayground = validator.toBoolean(process.env.STEEDOS_GRAPHQL_ENABLE_CONSOLE || 'true', true);
20
+ const openBrowser = require('react-dev-utils/openBrowser');
21
+ const requestIp = require('request-ip');
21
22
  const mixinOptions = {
22
23
 
23
24
  // Global GraphQL typeDefs
@@ -86,7 +87,7 @@ const mixinOptions = {
86
87
  introspection: enablePlayground
87
88
  }
88
89
  }
89
-
90
+ const ObjectDataLoaderMapKeys = {};
90
91
  /**
91
92
  * @typedef {import('moleculer').Context} Context Moleculer's Context
92
93
  * @typedef {import('http').IncomingMessage} IncomingRequest Incoming HTTP Request
@@ -94,13 +95,14 @@ const mixinOptions = {
94
95
  */
95
96
  module.exports = {
96
97
  name: "api",
97
- projectStarted: false,
98
98
  mixins: [ApiGateway,
99
99
  // GraphQL Apollo Server
100
100
  ApolloService(mixinOptions),
101
101
  ServiceObjectGraphql
102
102
  ],
103
103
 
104
+ projectStarted: false,
105
+
104
106
  // More info about settings: https://moleculer.services/docs/0.14/moleculer-web.html
105
107
  settings: {
106
108
  server: false,
@@ -169,10 +171,13 @@ module.exports = {
169
171
  * @param {ServerResponse} res
170
172
  * @param {Object} data
171
173
  *
174
+ *
175
+ */
172
176
  onBeforeCall(ctx, route, req, res) {
173
177
  // Set request headers to context meta
174
178
  ctx.meta.userAgent = req.headers["user-agent"];
175
- }, */
179
+ ctx.meta.clientIp = requestIp.getClientIp(req);
180
+ },
176
181
 
177
182
  /**
178
183
  * After call hook. You can modify the data.
@@ -323,9 +328,14 @@ module.exports = {
323
328
  * @param {Object.<string, any>} args - Arguments passed to GraphQL child resolver
324
329
  * @returns {string} Key to the dataloader instance
325
330
  */
326
- getObjectDataLoaderMapKey(objectName) {
331
+ getObjectDataLoaderMapKey(objectName, referenceToField = '_id', spaceId) {
327
332
  if (objectName) {
328
- return `object:${objectName}`;
333
+ const key = `${spaceId}_object:${objectName}.${referenceToField}`;
334
+ if(!ObjectDataLoaderMapKeys[objectName]){
335
+ ObjectDataLoaderMapKeys[objectName] = [] ;
336
+ }
337
+ ObjectDataLoaderMapKeys[objectName].push(key);
338
+ return key;
329
339
  }
330
340
  // 如果没有objectName,则抛出错误信息
331
341
  throw new Error("objectName is required");
@@ -335,8 +345,12 @@ module.exports = {
335
345
  async objectDataLoaderHandler(actionName, staticParams, rootParams, graphqlCtx) {
336
346
  const rootKeys = Object.keys(rootParams);
337
347
  const {root, args, context, resolveInfo} = graphqlCtx;
348
+ const userSession = context.ctx.meta.user;
349
+ const spaceId = userSession.spaceId;
338
350
  const dataLoaderMapKey = this.getObjectDataLoaderMapKey(
339
351
  staticParams.__objectName || staticParams.objectName
352
+ , staticParams.referenceToField || '_id'
353
+ , spaceId
340
354
  );
341
355
  const objectDataLoaders = this.objectDataLoaders;
342
356
  // if a dataLoader batching parameter is specified, then all root params can be data loaded;
@@ -359,7 +373,8 @@ module.exports = {
359
373
  batchedParamKey,
360
374
  staticParams,
361
375
  args,
362
- { hashCacheKey: dataLoaderUseAllRootKeys } // must hash the cache key if not loading scalar
376
+ { hashCacheKey: dataLoaderUseAllRootKeys }, // must hash the cache key if not loading scalar
377
+ spaceId
363
378
  );
364
379
  objectDataLoaders.set(dataLoaderMapKey, dataLoader);
365
380
  }
@@ -454,10 +469,13 @@ module.exports = {
454
469
  if(useObjectDataLoader){
455
470
  return await this.objectDataLoaderHandler(actionName, staticParams, rootParams, {root, args, context, resolveInfo});
456
471
  }else if (useDataLoader) {
472
+ const userSession = context.ctx.meta.user;
473
+ const spaceId = userSession.spaceId;
457
474
  const dataLoaderMapKey = this.getDataLoaderMapKey(
458
475
  actionName,
459
476
  staticParams,
460
- args
477
+ args,
478
+ spaceId
461
479
  );
462
480
  // if a dataLoader batching parameter is specified, then all root params can be data loaded;
463
481
  // otherwise use only the primary rootParam
@@ -479,7 +497,8 @@ module.exports = {
479
497
  batchedParamKey,
480
498
  staticParams,
481
499
  args,
482
- { hashCacheKey: dataLoaderUseAllRootKeys } // must hash the cache key if not loading scalar
500
+ { hashCacheKey: dataLoaderUseAllRootKeys }, // must hash the cache key if not loading scalar
501
+ spaceId
483
502
  );
484
503
  context.dataLoaders.set(dataLoaderMapKey, dataLoader);
485
504
  }
@@ -892,6 +911,25 @@ module.exports = {
892
911
  }
893
912
  },
894
913
 
914
+ /**
915
+ * Get the unique key assigned to the DataLoader map
916
+ * @param {string} actionName - Fully qualified action name to bind to dataloader
917
+ * @param {Object.<string, any>} staticParams - Static parameters to use in dataloader
918
+ * @param {Object.<string, any>} args - Arguments passed to GraphQL child resolver
919
+ * @returns {string} Key to the dataloader instance
920
+ */
921
+ getDataLoaderMapKey(actionName, staticParams, args, spaceId) {
922
+ if (Object.keys(staticParams).length > 0 || Object.keys(args).length > 0) {
923
+ // create a unique hash of the static params and the arguments to ensure a unique DataLoader instance
924
+ const actionParams = _.defaultsDeep({}, args, staticParams);
925
+ const paramsHash = hash(actionParams);
926
+ return `${spaceId}_${actionName}:${paramsHash}`;
927
+ }
928
+
929
+ // if no static params or arguments are present then the action name can serve as the key
930
+ return actionName;
931
+ },
932
+
895
933
  /**
896
934
  * Build a DataLoader instance
897
935
  *
@@ -910,11 +948,13 @@ module.exports = {
910
948
  batchedParamKey,
911
949
  staticParams,
912
950
  args,
913
- { hashCacheKey = false } = {}
951
+ { hashCacheKey = false } = {},
952
+ spaceId
914
953
  ) {
915
954
  const batchLoadFn = keys => {
916
955
  const rootParams = { [batchedParamKey]: keys };
917
- return ctx.call(actionName, _.defaultsDeep({}, args, rootParams, staticParams));
956
+ // !!! 这里的ctx是buildDataLoader时传进来的参数,在后续触发执行batchLoadFn时ctx.meta中的信息依然是旧的,故此函数体中代码不要使用ctx.meta中的信息
957
+ return ctx.call(actionName, _.defaultsDeep({}, args, rootParams, staticParams), { meta: { ...ctx.meta, spaceId } });
918
958
  };
919
959
 
920
960
  const dataLoaderOptions = this.dataLoaderOptions.get(actionName) || {};
@@ -936,19 +976,19 @@ module.exports = {
936
976
  '@objectRecordEvent.*.*': function(ctx){
937
977
  const { objectApiName, isUpdate, isDelete, id, doc } = ctx.params;
938
978
  if(objectApiName && (isUpdate || isDelete)){
939
- const key = this.getObjectDataLoaderMapKey(
940
- objectApiName
941
- );
979
+ const keys = ObjectDataLoaderMapKeys[objectApiName] || [];
942
980
  let dataLoaderKeys = [id];
943
981
  if(objectApiName === 'space_users'){
944
982
  dataLoaderKeys.push(doc.user)
945
983
  }
946
- const loader = this.objectDataLoaders.get(key);
947
- if(loader){
948
- for(const dataLoaderKey of dataLoaderKeys){
949
- loader.clear(dataLoaderKey);
984
+ _.each(keys, (key)=>{
985
+ const loader = this.objectDataLoaders.get(key);
986
+ if(loader){
987
+ for(const dataLoaderKey of dataLoaderKeys){
988
+ loader.clear(dataLoaderKey);
989
+ }
950
990
  }
951
- }
991
+ })
952
992
  }
953
993
  },
954
994
  'service-ui.started': function(){
@@ -964,12 +1004,15 @@ module.exports = {
964
1004
  console.log(`Project is running at ${process.env.ROOT_URL}`);
965
1005
  console.log('');
966
1006
  if (process.env.STEEDOS_AUTO_OPEN_BROWSER != 'false') { // 默认打开,如果不想打开,设置STEEDOS_AUTO_OPEN_BROWSER=false
967
- try {
968
- open(process.env.ROOT_URL);
969
- } catch (error) {
970
- console.error(error);
971
- console.error('auto open browser failed.');
972
- }
1007
+ setTimeout(function () {
1008
+ try {
1009
+ openBrowser(process.env.ROOT_URL);
1010
+ } catch (error) {
1011
+ console.error(error);
1012
+ console.error('auto open browser failed.');
1013
+ }
1014
+ }, 100)
1015
+
973
1016
  }
974
1017
  }
975
1018
  }
@@ -990,9 +1033,9 @@ module.exports = {
990
1033
  // });
991
1034
  // }
992
1035
 
993
- // this.broker.waitForServices('~packages-@steedos/service-ui').then(() => {
994
- // this.app.use("/", this.express());
995
- // })
1036
+ this.broker.waitForServices('~packages-@steedos/service-ui').then(() => {
1037
+ this.app.use("/", this.express());
1038
+ })
996
1039
 
997
1040
  global.SteedosApi = {
998
1041
  express: this.express
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@steedos/service-api",
3
- "version": "2.6.1-beta.6",
3
+ "version": "2.6.2-beta.10",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
7
- "@steedos/auth": "2.6.1-beta.6",
8
- "@steedos/router": "2.6.1-beta.6",
9
- "@steedos/service-object-graphql": "2.6.1-beta.6",
10
- "@steedos/service-ui": "2.6.1-beta.6",
7
+ "@steedos/auth": "2.6.2-beta.10",
8
+ "@steedos/router": "2.6.2-beta.10",
9
+ "@steedos/service-object-graphql": "2.6.2-beta.10",
10
+ "@steedos/service-ui": "2.6.2-beta.10",
11
11
  "graphql": "^15.8.0",
12
12
  "graphql-iso-date": "^3.6.1",
13
13
  "graphql-type-json": "^0.3.2",
@@ -15,11 +15,16 @@
15
15
  "moleculer": "^0.14.25",
16
16
  "moleculer-apollo-server": "^0.3.6",
17
17
  "moleculer-web": "^0.10.4",
18
+ "react-dev-utils": "12.0.1",
18
19
  "validator": "^13.6.0"
19
20
  },
20
21
  "private": false,
21
22
  "publishConfig": {
22
23
  "access": "public"
23
24
  },
24
- "gitHead": "d77961251196c5352622d977e554660796ed6208"
25
+ "gitHead": "afbd1c34d1516e44494b5d5a192bbce80e48af93",
26
+ "devDependencies": {
27
+ "@types/graphql-iso-date": "^3.4.0",
28
+ "@types/react-dev-utils": "^9.0.11"
29
+ }
25
30
  }