@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.
- package/index.js +71 -28
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
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
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
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
|
-
|
|
994
|
-
|
|
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.
|
|
3
|
+
"version": "2.6.2-beta.10",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@steedos/auth": "2.6.
|
|
8
|
-
"@steedos/router": "2.6.
|
|
9
|
-
"@steedos/service-object-graphql": "2.6.
|
|
10
|
-
"@steedos/service-ui": "2.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": "
|
|
25
|
+
"gitHead": "afbd1c34d1516e44494b5d5a192bbce80e48af93",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/graphql-iso-date": "^3.4.0",
|
|
28
|
+
"@types/react-dev-utils": "^9.0.11"
|
|
29
|
+
}
|
|
25
30
|
}
|