@blocklet/sdk 1.8.1 → 1.8.2
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/README.md +0 -14
- package/lib/index.js +0 -2
- package/lib/service/notification.js +99 -17
- package/lib/util/send-notification.js +75 -9
- package/lib/validators/index.js +2 -1
- package/lib/validators/notification.js +6 -1
- package/package.json +10 -11
- package/lib/logger.js +0 -8
package/README.md
CHANGED
|
@@ -303,20 +303,6 @@ For Blocklet to write business logs, provides a consistent write format.
|
|
|
303
303
|
|
|
304
304
|
### Usage
|
|
305
305
|
|
|
306
|
-
```javascript
|
|
307
|
-
const { logger } = require('@blocklet/sdk');
|
|
308
|
-
|
|
309
|
-
// log
|
|
310
|
-
log = logger('demo');
|
|
311
|
-
log.info('this is demo', { id: 'test-id' });
|
|
312
|
-
log.warn('this is demo', { id: 'test-id' });
|
|
313
|
-
log.error('this is demo', { id: 'test-id' });
|
|
314
|
-
log.debug('this is demo', { id: 'test-id' });
|
|
315
|
-
|
|
316
|
-
// access log
|
|
317
|
-
app.use(morgan('combined', { stream: logger.getAccessLogStream() }));
|
|
318
|
-
```
|
|
319
|
-
|
|
320
306
|
## getWallet
|
|
321
307
|
|
|
322
308
|
### Usage
|
package/lib/index.js
CHANGED
|
@@ -6,7 +6,6 @@ const Database = require('./database');
|
|
|
6
6
|
const env = require('./env');
|
|
7
7
|
const middlewares = require('./middlewares');
|
|
8
8
|
const getWallet = require('./wallet');
|
|
9
|
-
const logger = require('./logger');
|
|
10
9
|
|
|
11
10
|
module.exports = {
|
|
12
11
|
AuthService,
|
|
@@ -17,5 +16,4 @@ module.exports = {
|
|
|
17
16
|
getWallet,
|
|
18
17
|
env,
|
|
19
18
|
middlewares,
|
|
20
|
-
logger,
|
|
21
19
|
};
|
|
@@ -2,25 +2,62 @@ const Jwt = require('@arcblock/jwt');
|
|
|
2
2
|
const EventEmitter = require('events');
|
|
3
3
|
|
|
4
4
|
const { WsClient } = require('@arcblock/ws');
|
|
5
|
+
const { getAppPublicChannel } = require('@blocklet/meta/lib/channel');
|
|
5
6
|
|
|
6
7
|
const checkBlockletEnv = require('../util/check-blocklet-env');
|
|
7
|
-
const
|
|
8
|
+
const { sendToUser, sendToAppChannel } = require('../util/send-notification');
|
|
8
9
|
const { SERVICE_PREFIX } = require('../util/constants');
|
|
9
10
|
const getWallet = require('../wallet');
|
|
11
|
+
const { NOTIFICATION_TYPES } = require('../validators/notification');
|
|
10
12
|
|
|
11
|
-
const
|
|
13
|
+
const getSender = () => ({
|
|
14
|
+
appDid: process.env.BLOCKLET_APP_ID,
|
|
15
|
+
appSk: process.env.BLOCKLET_APP_SK,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @param {Notification} notification
|
|
21
|
+
* @param {{
|
|
22
|
+
* keepForOfflineUser: Boolean
|
|
23
|
+
* }} options
|
|
24
|
+
* @returns
|
|
25
|
+
*/
|
|
26
|
+
const doSendToUser = async (receiver, notification, options) => {
|
|
27
|
+
checkBlockletEnv();
|
|
28
|
+
|
|
29
|
+
return sendToUser(receiver, notification, getSender(), process.env.ABT_NODE_SERVICE_PORT, options);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* @param {Notification} notification
|
|
35
|
+
* @param {{
|
|
36
|
+
* channel: String
|
|
37
|
+
* event: String
|
|
38
|
+
* socketId: String
|
|
39
|
+
* socketDid: String
|
|
40
|
+
* }} options
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
const broadcast = async (notification, options = {}) => {
|
|
12
44
|
checkBlockletEnv();
|
|
13
45
|
|
|
14
|
-
const sender =
|
|
15
|
-
appId: process.env.BLOCKLET_APP_ID,
|
|
16
|
-
appSk: process.env.BLOCKLET_APP_SK,
|
|
17
|
-
did: process.env.BLOCKLET_DID,
|
|
18
|
-
};
|
|
46
|
+
const sender = getSender();
|
|
19
47
|
|
|
20
|
-
|
|
48
|
+
const { channel = getAppPublicChannel(sender.appDid) } = options;
|
|
49
|
+
const { event = 'message' } = options;
|
|
50
|
+
|
|
51
|
+
return sendToAppChannel(channel, event, notification, sender, process.env.ABT_NODE_SERVICE_PORT, options);
|
|
21
52
|
};
|
|
22
53
|
|
|
23
54
|
const emitter = new EventEmitter();
|
|
55
|
+
const messageEmitter = new EventEmitter();
|
|
56
|
+
|
|
57
|
+
const emitError = (error) => {
|
|
58
|
+
messageEmitter.emit('error', error);
|
|
59
|
+
emitter.emit('error', error);
|
|
60
|
+
};
|
|
24
61
|
|
|
25
62
|
let client = null;
|
|
26
63
|
|
|
@@ -41,9 +78,38 @@ const initClient = () => {
|
|
|
41
78
|
|
|
42
79
|
client.connect();
|
|
43
80
|
|
|
44
|
-
const
|
|
81
|
+
const messageChannel = client.channel(did, () => ({ token: token(), pk }));
|
|
82
|
+
const appPublicChannel = client.channel(getAppPublicChannel(did), () => ({ token: token(), pk }));
|
|
45
83
|
|
|
46
|
-
|
|
84
|
+
messageChannel
|
|
85
|
+
.join()
|
|
86
|
+
.receive('error', (err) => {
|
|
87
|
+
const msg = `join channel error: ${err.message}`;
|
|
88
|
+
console.error(msg);
|
|
89
|
+
emitError({ message: msg });
|
|
90
|
+
})
|
|
91
|
+
.receive('timeout', () => {
|
|
92
|
+
const msg = 'join channel timeout';
|
|
93
|
+
console.error(msg);
|
|
94
|
+
emitError({ message: msg });
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
messageChannel.on('message', ({ status, response } = {}) => {
|
|
98
|
+
if (status === 'ok') {
|
|
99
|
+
messageEmitter.emit(response.type, response);
|
|
100
|
+
if (response.type === NOTIFICATION_TYPES.HI) {
|
|
101
|
+
emitter.emit(response.type, response);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
emitError(response);
|
|
105
|
+
console.error({
|
|
106
|
+
status,
|
|
107
|
+
response,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
appPublicChannel
|
|
47
113
|
.join()
|
|
48
114
|
.receive('error', (err) => {
|
|
49
115
|
const msg = `join channel error: ${err.message}`;
|
|
@@ -56,9 +122,9 @@ const initClient = () => {
|
|
|
56
122
|
emitter.emit('error', { message: msg });
|
|
57
123
|
});
|
|
58
124
|
|
|
59
|
-
|
|
125
|
+
appPublicChannel.on(NOTIFICATION_TYPES.HI, ({ status, response } = {}) => {
|
|
60
126
|
if (status === 'ok') {
|
|
61
|
-
emitter.emit(
|
|
127
|
+
emitter.emit(NOTIFICATION_TYPES.HI, response);
|
|
62
128
|
} else {
|
|
63
129
|
emitter.emit('error', response);
|
|
64
130
|
console.error({
|
|
@@ -70,14 +136,30 @@ const initClient = () => {
|
|
|
70
136
|
}
|
|
71
137
|
};
|
|
72
138
|
|
|
139
|
+
const ensureClient = () => {
|
|
140
|
+
if (!client) {
|
|
141
|
+
initClient();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
73
145
|
module.exports = {
|
|
74
|
-
sendToUser,
|
|
75
|
-
|
|
76
|
-
if (!client) {
|
|
77
|
-
initClient();
|
|
78
|
-
}
|
|
146
|
+
sendToUser: doSendToUser,
|
|
147
|
+
broadcast,
|
|
79
148
|
|
|
149
|
+
// System notification
|
|
150
|
+
on: (event, cb) => {
|
|
151
|
+
ensureClient();
|
|
80
152
|
return emitter.on(event, cb);
|
|
81
153
|
},
|
|
82
154
|
off: emitter.off.bind(emitter),
|
|
155
|
+
|
|
156
|
+
// Just for DID Wallet developing
|
|
157
|
+
// Any message received from any account
|
|
158
|
+
_message: {
|
|
159
|
+
on: (event, cb) => {
|
|
160
|
+
ensureClient();
|
|
161
|
+
return messageEmitter.on(event, cb);
|
|
162
|
+
},
|
|
163
|
+
off: messageEmitter.off.bind(messageEmitter),
|
|
164
|
+
},
|
|
83
165
|
};
|
|
@@ -10,26 +10,32 @@ const { SERVICE_PREFIX } = require('./constants');
|
|
|
10
10
|
|
|
11
11
|
const VERSION = require('../../package.json').version; // version of notification sdk
|
|
12
12
|
|
|
13
|
-
const { validateNotification, validateReceiver, validateOption } = validators;
|
|
13
|
+
const { validateNotification, validateReceiver, validateOption, validateChannelEvent } = validators;
|
|
14
14
|
|
|
15
15
|
const SERVER_MODE = process.env.ABT_NODE_MODE;
|
|
16
16
|
|
|
17
|
+
const getRequestHeaders = () => ({ 'User-Agent': `BlockletSDK/${VERSION}` });
|
|
18
|
+
|
|
17
19
|
/**
|
|
18
20
|
* @param {String|Array} receiver
|
|
19
21
|
* @param {Object} notification
|
|
20
|
-
* @param {
|
|
22
|
+
* @param {{
|
|
23
|
+
* appDid: String
|
|
24
|
+
* appSk: String
|
|
25
|
+
* }} sender
|
|
21
26
|
* @param {String|Number} port port of abtnode service endpoint
|
|
22
27
|
* @param {Object} options
|
|
23
28
|
* @returns
|
|
24
29
|
*/
|
|
25
|
-
|
|
30
|
+
const sendToUser = async (
|
|
26
31
|
receiver,
|
|
27
32
|
notification,
|
|
28
|
-
{
|
|
33
|
+
{ appDid, appSk } = {},
|
|
29
34
|
port = process.env.ABT_NODE_SERVICE_PORT,
|
|
30
35
|
options = {}
|
|
31
36
|
) => {
|
|
32
37
|
await validateReceiver(receiver);
|
|
38
|
+
|
|
33
39
|
const opt = pick(options, ['keepForOfflineUser']);
|
|
34
40
|
await validateOption(opt);
|
|
35
41
|
|
|
@@ -37,27 +43,87 @@ module.exports = async (
|
|
|
37
43
|
await validateNotification(notification);
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
const token = JWT.sign(appId, appSk);
|
|
41
|
-
|
|
42
46
|
try {
|
|
43
47
|
const { data: res } = await axios.post(
|
|
44
|
-
`http://127.0.0.1:${port}${SERVICE_PREFIX}/api/
|
|
48
|
+
`http://127.0.0.1:${port}${SERVICE_PREFIX}/api/send-to-user`,
|
|
45
49
|
{
|
|
46
50
|
apiVersion: VERSION,
|
|
47
51
|
data: {
|
|
48
|
-
sender: {
|
|
52
|
+
sender: { appDid, token: JWT.sign(appDid, appSk) },
|
|
49
53
|
receiver,
|
|
50
54
|
notification,
|
|
51
55
|
options: opt,
|
|
52
56
|
},
|
|
53
57
|
},
|
|
54
58
|
{
|
|
55
|
-
|
|
59
|
+
timeout: 60 * 1000,
|
|
60
|
+
headers: getRequestHeaders(),
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return res;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(error);
|
|
67
|
+
throw new Error(error.response ? error.response.statusText : error.message);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const sendToAppChannel = async (
|
|
72
|
+
channel,
|
|
73
|
+
event,
|
|
74
|
+
notification,
|
|
75
|
+
{ appDid, appSk } = {},
|
|
76
|
+
port = process.env.ABT_NODE_SERVICE_PORT,
|
|
77
|
+
options = {}
|
|
78
|
+
) => {
|
|
79
|
+
if (!channel) {
|
|
80
|
+
throw new Error('channel is required');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!event) {
|
|
84
|
+
throw new Error('event is required');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
await validateChannelEvent(event);
|
|
88
|
+
|
|
89
|
+
const opt = pick(options, ['socketId', 'userDid']);
|
|
90
|
+
|
|
91
|
+
if (opt.userDid) {
|
|
92
|
+
opt.socketDid = opt.userDid;
|
|
93
|
+
delete opt.userDid;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (SERVER_MODE !== NODE_MODES.DEBUG) {
|
|
97
|
+
await validateNotification(notification);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const { data: res } = await axios.post(
|
|
102
|
+
`http://127.0.0.1:${port}${SERVICE_PREFIX}/api/send-to-app-channel`,
|
|
103
|
+
{
|
|
104
|
+
apiVersion: VERSION,
|
|
105
|
+
data: {
|
|
106
|
+
sender: { appDid, token: JWT.sign(appDid, appSk) },
|
|
107
|
+
channel,
|
|
108
|
+
event,
|
|
109
|
+
notification,
|
|
110
|
+
options: opt,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
timeout: 60 * 1000,
|
|
115
|
+
headers: getRequestHeaders(),
|
|
56
116
|
}
|
|
57
117
|
);
|
|
58
118
|
|
|
59
119
|
return res;
|
|
60
120
|
} catch (error) {
|
|
121
|
+
console.error(error);
|
|
61
122
|
throw new Error(error.response ? error.response.statusText : error.message);
|
|
62
123
|
}
|
|
63
124
|
};
|
|
125
|
+
|
|
126
|
+
module.exports = {
|
|
127
|
+
sendToUser,
|
|
128
|
+
sendToAppChannel,
|
|
129
|
+
};
|
package/lib/validators/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
const { validateNotification, validateReceiver, validateOption } = require('./notification');
|
|
1
|
+
const { validateNotification, validateReceiver, validateOption, validateChannelEvent } = require('./notification');
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
validateNotification,
|
|
5
5
|
validateReceiver,
|
|
6
6
|
validateOption,
|
|
7
|
+
validateChannelEvent,
|
|
7
8
|
};
|
|
@@ -89,12 +89,15 @@ const inputReceiverSchema = Joi.alternatives().try(Joi.array().items(receiverSch
|
|
|
89
89
|
|
|
90
90
|
const optionSchema = Joi.object({
|
|
91
91
|
keepForOfflineUser: Joi.boolean(),
|
|
92
|
-
});
|
|
92
|
+
}).unknown();
|
|
93
|
+
|
|
94
|
+
const channelEventSchema = Joi.string().required();
|
|
93
95
|
|
|
94
96
|
module.exports = {
|
|
95
97
|
validateReceiver: inputReceiverSchema.validateAsync.bind(inputReceiverSchema),
|
|
96
98
|
validateNotification: inputNotificationSchema.validateAsync.bind(inputNotificationSchema),
|
|
97
99
|
validateMessage: messageSchema.validateAsync.bind(messageSchema),
|
|
100
|
+
validateChannelEvent: channelEventSchema.validateAsync.bind(channelEventSchema),
|
|
98
101
|
validateOption: optionSchema.validateAsync.bind(optionSchema),
|
|
99
102
|
tokenSchema,
|
|
100
103
|
actionSchema,
|
|
@@ -104,4 +107,6 @@ module.exports = {
|
|
|
104
107
|
notificationSchema,
|
|
105
108
|
messageSchema,
|
|
106
109
|
optionSchema,
|
|
110
|
+
channelEventSchema,
|
|
111
|
+
NOTIFICATION_TYPES: TYPES,
|
|
107
112
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.8.
|
|
6
|
+
"version": "1.8.2",
|
|
7
7
|
"description": "graphql client to read/write data on abt node",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,16 +19,15 @@
|
|
|
19
19
|
"author": "linchen1987 <linchen.1987@foxmail.com> (http://github.com/linchen1987)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/client": "1.8.
|
|
23
|
-
"@abtnode/constant": "1.8.
|
|
24
|
-
"@
|
|
25
|
-
"@arcblock/
|
|
26
|
-
"@arcblock/
|
|
27
|
-
"@
|
|
28
|
-
"@blocklet/meta": "1.8.1",
|
|
22
|
+
"@abtnode/client": "1.8.2",
|
|
23
|
+
"@abtnode/constant": "1.8.2",
|
|
24
|
+
"@arcblock/did-auth": "1.17.2",
|
|
25
|
+
"@arcblock/jwt": "1.17.2",
|
|
26
|
+
"@arcblock/ws": "1.17.2",
|
|
27
|
+
"@blocklet/meta": "1.8.2",
|
|
29
28
|
"@nedb/core": "^1.3.1",
|
|
30
|
-
"@ocap/mcrypto": "1.17.
|
|
31
|
-
"@ocap/wallet": "1.17.
|
|
29
|
+
"@ocap/mcrypto": "1.17.2",
|
|
30
|
+
"@ocap/wallet": "1.17.2",
|
|
32
31
|
"axios": "^0.27.2",
|
|
33
32
|
"fs-extra": "^10.0.1",
|
|
34
33
|
"joi": "^17.6.0",
|
|
@@ -40,5 +39,5 @@
|
|
|
40
39
|
"detect-port": "^1.3.0",
|
|
41
40
|
"jest": "^27.4.5"
|
|
42
41
|
},
|
|
43
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "fcbe3c97f3825c507ee16714f49bbf8f58c5b59f"
|
|
44
43
|
}
|
package/lib/logger.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
const logger = require('@abtnode/logger');
|
|
2
|
-
|
|
3
|
-
if (!process.env.BLOCKLET_LOG_DIR) {
|
|
4
|
-
throw new Error('valid BLOCKLET_LOG_DIR env is required by logger');
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
module.exports = (label) => logger(label, { logDir: process.env.BLOCKLET_LOG_DIR, filename: 'info' });
|
|
8
|
-
module.exports.getAccessLogStream = () => logger.getAccessLogStream(process.env.BLOCKLET_LOG_DIR);
|