@ocap/gql 1.6.3 → 1.6.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/lib/index.js +113 -66
- package/lib/ws.js +31 -0
- package/package.json +12 -6
package/lib/index.js
CHANGED
|
@@ -1,74 +1,94 @@
|
|
|
1
|
+
const get = require('lodash/get');
|
|
2
|
+
const { createServer } = require('http');
|
|
1
3
|
const { graphqlHTTP } = require('express-graphql');
|
|
2
4
|
const { buildSchema } = require('graphql');
|
|
3
5
|
const schemaSource = require('@ocap/schema');
|
|
4
6
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
code: 'OK',
|
|
20
|
-
page: result ? result.paging || {} : null,
|
|
21
|
-
...resultsMap,
|
|
22
|
-
};
|
|
23
|
-
} catch (err) {
|
|
24
|
-
console.error('GraphQL API Error', err);
|
|
25
|
-
const tmpKeys = Array.isArray(keys) ? keys : [keys];
|
|
26
|
-
const tmpKeysMap = tmpKeys.reduce((acc, k) => {
|
|
27
|
-
acc[k] = null;
|
|
28
|
-
return acc;
|
|
29
|
-
}, {});
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
code: err.code,
|
|
33
|
-
message: err.message,
|
|
34
|
-
...tmpKeysMap,
|
|
35
|
-
};
|
|
7
|
+
// const debug = require('debug')(require('../package.json').name);
|
|
8
|
+
const createWebSocketServer = require('./ws');
|
|
9
|
+
|
|
10
|
+
const wrapResolver = async (name, keys, callback) => {
|
|
11
|
+
const result = await callback();
|
|
12
|
+
|
|
13
|
+
const resultsMap = {};
|
|
14
|
+
if (Array.isArray(keys)) {
|
|
15
|
+
keys.forEach((key) => {
|
|
16
|
+
resultsMap[key] = result[key];
|
|
17
|
+
});
|
|
18
|
+
} else {
|
|
19
|
+
resultsMap[keys] = result;
|
|
36
20
|
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
code: 'OK',
|
|
24
|
+
page: result ? result.paging || {} : null,
|
|
25
|
+
...resultsMap,
|
|
26
|
+
};
|
|
37
27
|
};
|
|
38
28
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
29
|
+
// eslint-disable-next-line no-unused-vars
|
|
30
|
+
const formatContext = (ctx = {}) => {
|
|
31
|
+
const featureSwitch = {};
|
|
32
|
+
return { featureSwitch };
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const resolvers = [
|
|
36
|
+
{ fn: 'sendTx', dataKey: 'hash' },
|
|
37
|
+
|
|
38
|
+
{ fn: 'subscribe', dataKey: 'value' },
|
|
39
|
+
{ fn: 'unsubscribe', dataKey: 'result' },
|
|
40
|
+
|
|
41
|
+
{ fn: 'getAccountState', dataKey: 'state' },
|
|
42
|
+
{ fn: 'getAssetState', dataKey: 'state' },
|
|
43
|
+
{ fn: 'getFactoryState', dataKey: 'state' },
|
|
44
|
+
{ fn: 'getDelegateState', dataKey: 'state' },
|
|
45
|
+
{ fn: 'getTokenState', dataKey: 'state' },
|
|
46
|
+
{ fn: 'getForgeState', dataKey: 'state' },
|
|
47
|
+
{ fn: 'getStakeState', dataKey: 'state' },
|
|
48
|
+
{ fn: 'getEvidenceState', dataKey: 'state' },
|
|
49
|
+
{ fn: 'getRollupState', dataKey: 'state' },
|
|
50
|
+
{ fn: 'getRollupBlock', dataKey: 'block' },
|
|
51
|
+
|
|
52
|
+
{ fn: 'getAccountTokens', dataKey: 'tokens' },
|
|
53
|
+
{ fn: 'getBlock', dataKey: 'block' },
|
|
54
|
+
{ fn: 'getBlocks', dataKey: 'blocks' },
|
|
55
|
+
{ fn: 'getChainInfo', dataKey: 'info' },
|
|
56
|
+
{ fn: 'getConfig', dataKey: 'config' },
|
|
57
|
+
{ fn: 'getForgeStats', dataKey: 'forgeStats' },
|
|
58
|
+
{ fn: 'getNetInfo', dataKey: 'netInfo' },
|
|
59
|
+
{ fn: 'getNodeInfo', dataKey: 'info' },
|
|
60
|
+
{ fn: 'getTx', dataKey: 'info' },
|
|
61
|
+
{ fn: 'getUnconfirmedTxs', dataKey: 'unconfirmedTxs' },
|
|
62
|
+
{ fn: 'getValidatorsInfo', dataKey: 'validatorsInfo' },
|
|
63
|
+
|
|
64
|
+
{ fn: 'listTransactions', dataKey: ['transactions'] },
|
|
65
|
+
{ fn: 'listAssets', dataKey: ['assets', 'account'] },
|
|
66
|
+
{ fn: 'listAssetTransactions', dataKey: ['transactions'] },
|
|
67
|
+
{ fn: 'listFactories', dataKey: ['factories'] },
|
|
68
|
+
{ fn: 'listTokens', dataKey: ['tokens'] },
|
|
69
|
+
{ fn: 'listTopAccounts', dataKey: ['accounts'] },
|
|
70
|
+
{ fn: 'listBlocks', dataKey: ['blocks'] },
|
|
71
|
+
{ fn: 'listStakes', dataKey: ['stakes'] },
|
|
72
|
+
{ fn: 'listRollups', dataKey: ['rollups'] },
|
|
73
|
+
{ fn: 'listRollupBlocks', dataKey: ['blocks'] },
|
|
74
|
+
{ fn: 'listRollupValidators', dataKey: ['validators'] },
|
|
75
|
+
|
|
76
|
+
{ fn: 'search', dataKey: ['results'] },
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const createResolvers = (resolver) =>
|
|
80
|
+
resolvers.reduce((acc, { fn, dataKey }) => {
|
|
81
|
+
acc[fn] = (args, ctx) => wrapResolver(fn, dataKey, () => resolver[fn](args, formatContext(ctx)));
|
|
82
|
+
return acc;
|
|
83
|
+
}, {});
|
|
84
|
+
|
|
85
|
+
const defaultErrorHandler = (err) => {
|
|
86
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
87
|
+
console.error('GraphQLError', err.originalError || err);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const createHttpHandler = ({ resolver, onError = defaultErrorHandler, graphiql = true }) =>
|
|
72
92
|
graphqlHTTP({
|
|
73
93
|
schema: buildSchema(schemaSource),
|
|
74
94
|
rootValue: createResolvers(resolver),
|
|
@@ -76,7 +96,34 @@ module.exports = (resolver, graphiql = true) =>
|
|
|
76
96
|
// NOTE: following is required because of following gql query validation issue
|
|
77
97
|
// https://stackoverflow.com/questions/56695262/graphql-error-fieldsconflict-fields-have-different-list-shapes
|
|
78
98
|
customValidateFn: () => true,
|
|
99
|
+
|
|
100
|
+
// format custom error code
|
|
101
|
+
customFormatErrorFn: (err) => {
|
|
102
|
+
onError(err);
|
|
103
|
+
|
|
104
|
+
const isProd = process.env.NODE_ENV === 'production';
|
|
105
|
+
return {
|
|
106
|
+
code: get(err, 'originalError.code', 'INTERNAL'),
|
|
107
|
+
message: err.message,
|
|
108
|
+
locations: err.locations || [],
|
|
109
|
+
stack: isProd ? [] : get(err, 'originalError.stack', '').split('\n'),
|
|
110
|
+
path: err.path,
|
|
111
|
+
};
|
|
112
|
+
},
|
|
79
113
|
});
|
|
80
114
|
|
|
81
|
-
|
|
82
|
-
|
|
115
|
+
const createSocketHandler = ({ app, indexdb }) => {
|
|
116
|
+
const httpServer = createServer(app);
|
|
117
|
+
const wsServer = createWebSocketServer({ indexdb });
|
|
118
|
+
wsServer.attach(httpServer);
|
|
119
|
+
|
|
120
|
+
return httpServer;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
module.exports = {
|
|
124
|
+
createHttpHandler,
|
|
125
|
+
createSocketHandler,
|
|
126
|
+
wrapResolver,
|
|
127
|
+
createResolvers,
|
|
128
|
+
formatContext,
|
|
129
|
+
};
|
package/lib/ws.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const { WsServer } = require('@arcblock/ws');
|
|
2
|
+
|
|
3
|
+
module.exports = function createWebsocketServer({ indexdb }) {
|
|
4
|
+
const wsServer = new WsServer({});
|
|
5
|
+
|
|
6
|
+
const mutableTables = ['account', 'asset', 'delegation', 'rollup', 'stake'];
|
|
7
|
+
const appendOnlyTables = ['tx', 'token', 'rollupBlock', 'factory'];
|
|
8
|
+
const map = { insert: 'create', update: 'update' };
|
|
9
|
+
|
|
10
|
+
// For entities that support updating
|
|
11
|
+
mutableTables.forEach((table) => {
|
|
12
|
+
['insert', 'update'].forEach((action) => {
|
|
13
|
+
indexdb[table].on(action, (data) => wsServer.broadcast([table, map[action]].join('.'), data));
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// For entities that are immutable after creation
|
|
18
|
+
appendOnlyTables.forEach((table) => {
|
|
19
|
+
['insert'].forEach((action) => {
|
|
20
|
+
indexdb[table].on(action, (data) => wsServer.broadcast([table, map[action]].join('.'), data));
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// For tx sub topic
|
|
25
|
+
indexdb.tx.on('insert', (tx) => {
|
|
26
|
+
const typeUrl = tx.tx.itxJson.type_url.split(':').pop();
|
|
27
|
+
wsServer.broadcast(`tx.${typeUrl}`, tx);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return wsServer;
|
|
31
|
+
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.6.
|
|
6
|
+
"version": "1.6.10",
|
|
7
7
|
"description": "Resolver middleware for ocap adapters",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -12,20 +12,26 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"lint": "eslint tests lib",
|
|
14
14
|
"lint:fix": "eslint --fix tests lib",
|
|
15
|
-
"test": "
|
|
15
|
+
"test": "jest --forceExit --detectOpenHandles",
|
|
16
16
|
"coverage": "npm run test -- --coverage"
|
|
17
17
|
},
|
|
18
18
|
"keywords": [],
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
|
+
"contributors": [
|
|
21
|
+
"wangshijun <shijun@arcblock.io> (https://github.com/wangshijun)"
|
|
22
|
+
],
|
|
20
23
|
"license": "MIT",
|
|
21
24
|
"dependencies": {
|
|
22
|
-
"@
|
|
25
|
+
"@arcblock/ws": "1.6.10",
|
|
26
|
+
"@ocap/schema": "1.6.10",
|
|
27
|
+
"debug": "^4.3.3",
|
|
23
28
|
"express-graphql": "^0.12.0",
|
|
24
|
-
"graphql": "14.6.0"
|
|
29
|
+
"graphql": "14.6.0",
|
|
30
|
+
"lodash": "^4.17.21"
|
|
25
31
|
},
|
|
26
32
|
"devDependencies": {
|
|
27
33
|
"express": "^4.17.1",
|
|
28
|
-
"jest": "^
|
|
34
|
+
"jest": "^27.3.1"
|
|
29
35
|
},
|
|
30
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "ab272e8db3a15c6571cc7fae7cc3d3e0fdd4bdb1"
|
|
31
37
|
}
|